From 540789f846ecd1126041ab775c9901c778d08c82 Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Sun, 28 Feb 2021 22:14:31 +0100 Subject: [PATCH] Added Quake engine code from UQE project that will be gradually stripped down and used as the basis for a Unity plugin --- engine/GNU.TXT | 87 + engine/README.TXT | 60 + engine/code/3dfx.txt | 69 + engine/code/WinQuake.sln | 22 + engine/code/WinQuake.vcxproj | 305 + engine/code/anorm_dots.h | 37 + engine/code/anorms.h | 181 + engine/code/bspfile.h | 324 + engine/code/cd_win.c | 595 ++ engine/code/cdaudio.h | 33 + engine/code/cl_demo.c | 595 ++ engine/code/cl_input.c | 469 + engine/code/cl_main.c | 800 ++ engine/code/cl_parse.c | 1026 +++ engine/code/cl_tent.c | 394 + engine/code/client.h | 408 + engine/code/cmd.c | 753 ++ engine/code/cmd.h | 121 + engine/code/common.c | 2226 +++++ engine/code/common.h | 198 + engine/code/conproc.c | 365 + engine/code/conproc.h | 37 + engine/code/console.c | 671 ++ engine/code/console.h | 46 + engine/code/crc.c | 81 + engine/code/crc.h | 24 + engine/code/cvar.c | 289 + engine/code/cvar.h | 99 + engine/code/draw.h | 55 + engine/code/gl_draw.c | 2466 ++++++ engine/code/gl_fullbright.c | 88 + engine/code/gl_fullbright.h | 27 + engine/code/gl_mesh.c | 362 + engine/code/gl_model.c | 2261 +++++ engine/code/gl_model.h | 454 + engine/code/gl_refrag.c | 234 + engine/code/gl_rlight.c | 579 ++ engine/code/gl_rmain.c | 1683 ++++ engine/code/gl_rmisc.c | 543 ++ engine/code/gl_rsurf.c | 2230 +++++ engine/code/gl_screen.c | 1172 +++ engine/code/gl_test.c | 182 + engine/code/gl_vidnt.c | 2260 +++++ engine/code/gl_warp.c | 1182 +++ engine/code/gl_warp_sin.h | 51 + engine/code/glext.h | 12050 ++++++++++++++++++++++++++ engine/code/glqnotes.txt | 171 + engine/code/glquake.h | 358 + engine/code/host.c | 1040 +++ engine/code/host_cmd.c | 1935 +++++ engine/code/in_win.c | 1293 +++ engine/code/input.h | 34 + engine/code/keys.c | 763 ++ engine/code/keys.h | 136 + engine/code/mathlib.c | 587 ++ engine/code/mathlib.h | 107 + engine/code/menu.c | 3364 +++++++ engine/code/menu.h | 38 + engine/code/modelgen.h | 134 + engine/code/net.h | 337 + engine/code/net_dgrm.c | 1390 +++ engine/code/net_dgrm.h | 34 + engine/code/net_loop.c | 245 + engine/code/net_loop.h | 33 + engine/code/net_main.c | 1012 +++ engine/code/net_vcr.c | 167 + engine/code/net_vcr.h | 37 + engine/code/net_win.c | 120 + engine/code/net_wins.c | 580 ++ engine/code/net_wins.h | 39 + engine/code/net_wipx.c | 440 + engine/code/net_wipx.h | 39 + engine/code/pr_cmds.c | 1940 +++++ engine/code/pr_comp.h | 180 + engine/code/pr_edict.c | 1112 +++ engine/code/pr_exec.c | 673 ++ engine/code/progdefs.h | 24 + engine/code/progdefs.q1 | 143 + engine/code/progdefs.q2 | 158 + engine/code/progs.h | 134 + engine/code/protocol.h | 173 + engine/code/quake.bmp | Bin 0 -> 286808 bytes engine/code/quake.ico | Bin 0 -> 56715 bytes engine/code/quakedef.h | 359 + engine/code/r_part.c | 819 ++ engine/code/render.h | 162 + engine/code/resource.h | 19 + engine/code/sbar.c | 1391 +++ engine/code/sbar.h | 41 + engine/code/screen.h | 55 + engine/code/server.h | 262 + engine/code/snd_dma.c | 1027 +++ engine/code/snd_fmod.c | 1129 +++ engine/code/snd_fmod.h | 45 + engine/code/snd_mem.c | 341 + engine/code/snd_mix.c | 398 + engine/code/snd_win.c | 737 ++ engine/code/sound.h | 177 + engine/code/spritegn.h | 110 + engine/code/sv_main.c | 1227 +++ engine/code/sv_move.c | 427 + engine/code/sv_phys.c | 2035 +++++ engine/code/sv_user.c | 635 ++ engine/code/sys.h | 89 + engine/code/sys_win.c | 1007 +++ engine/code/unzip.c | 4321 +++++++++ engine/code/unzip.h | 336 + engine/code/vid.h | 85 + engine/code/vid_gamma.c | 308 + engine/code/vid_gamma.h | 28 + engine/code/view.c | 1210 +++ engine/code/view.h | 42 + engine/code/wad.c | 158 + engine/code/wad.h | 75 + engine/code/wglext.h | 840 ++ engine/code/winquake.h | 183 + engine/code/winquake.rc | 108 + engine/code/world.c | 1023 +++ engine/code/world.h | 78 + engine/code/wqreadme.txt | 1119 +++ engine/code/zone.c | 935 ++ engine/code/zone.h | 131 + engine/docs/COMEXP.TXT | 487 ++ engine/docs/HELP.TXT | 119 + engine/docs/LICINFO.TXT | 97 + engine/docs/MANUAL.TXT | 1030 +++ engine/docs/ORDER.TXT | 103 + engine/docs/README.TXT | 456 + engine/docs/RLICNSE.TXT | 204 + engine/docs/SLICNSE.TXT | 175 + engine/docs/TECHINFO.TXT | 1901 ++++ engine/docs/UQE Quake.pdf | Bin 0 -> 503181 bytes engine/fmod-4/inc/fmod.h | 2473 ++++++ engine/fmod-4/inc/fmod.hpp | 609 ++ engine/fmod-4/inc/fmod_codec.h | 159 + engine/fmod-4/inc/fmod_dsp.h | 746 ++ engine/fmod-4/inc/fmod_errors.h | 123 + engine/fmod-4/inc/fmod_memoryinfo.h | 201 + engine/fmod-4/inc/fmod_output.h | 93 + engine/jpeg-6/README | 385 + engine/jpeg-6/jcapimin.c | 228 + engine/jpeg-6/jcapistd.c | 161 + engine/jpeg-6/jccoefct.c | 448 + engine/jpeg-6/jccolor.c | 459 + engine/jpeg-6/jcdctmgr.c | 391 + engine/jpeg-6/jchuff.c | 846 ++ engine/jpeg-6/jchuff.h | 34 + engine/jpeg-6/jcinit.c | 72 + engine/jpeg-6/jcmainct.c | 296 + engine/jpeg-6/jcmarker.c | 639 ++ engine/jpeg-6/jcmaster.c | 578 ++ engine/jpeg-6/jcomapi.c | 94 + engine/jpeg-6/jconfig.h | 41 + engine/jpeg-6/jcparam.c | 575 ++ engine/jpeg-6/jcphuff.c | 829 ++ engine/jpeg-6/jcprepct.c | 371 + engine/jpeg-6/jcsample.c | 519 ++ engine/jpeg-6/jctrans.c | 371 + engine/jpeg-6/jdapimin.c | 398 + engine/jpeg-6/jdapistd.c | 275 + engine/jpeg-6/jdatadst.c | 151 + engine/jpeg-6/jdatasrc.c | 204 + engine/jpeg-6/jdcoefct.c | 725 ++ engine/jpeg-6/jdcolor.c | 367 + engine/jpeg-6/jdct.h | 176 + engine/jpeg-6/jddctmgr.c | 270 + engine/jpeg-6/jdhuff.c | 574 ++ engine/jpeg-6/jdhuff.h | 202 + engine/jpeg-6/jdinput.c | 381 + engine/jpeg-6/jdmainct.c | 520 ++ engine/jpeg-6/jdmarker.c | 1052 +++ engine/jpeg-6/jdmaster.c | 557 ++ engine/jpeg-6/jdmerge.c | 400 + engine/jpeg-6/jdphuff.c | 642 ++ engine/jpeg-6/jdpostct.c | 290 + engine/jpeg-6/jdsample.c | 478 + engine/jpeg-6/jdtrans.c | 122 + engine/jpeg-6/jerror.c | 232 + engine/jpeg-6/jerror.h | 273 + engine/jpeg-6/jfdctflt.c | 168 + engine/jpeg-6/jfdctfst.c | 224 + engine/jpeg-6/jfdctint.c | 283 + engine/jpeg-6/jidctflt.c | 241 + engine/jpeg-6/jidctfst.c | 367 + engine/jpeg-6/jidctint.c | 388 + engine/jpeg-6/jidctred.c | 397 + engine/jpeg-6/jinclude.h | 116 + engine/jpeg-6/jload.c | 145 + engine/jpeg-6/jmemansi.c | 167 + engine/jpeg-6/jmemdos.c | 634 ++ engine/jpeg-6/jmemmgr.c | 1115 +++ engine/jpeg-6/jmemname.c | 271 + engine/jpeg-6/jmemnobs.c | 106 + engine/jpeg-6/jmemsys.h | 182 + engine/jpeg-6/jmorecfg.h | 348 + engine/jpeg-6/jpegint.h | 388 + engine/jpeg-6/jpeglib.h | 1051 +++ engine/jpeg-6/jpegtran.c | 370 + engine/jpeg-6/jquant1.c | 856 ++ engine/jpeg-6/jquant2.c | 1310 +++ engine/jpeg-6/jutils.c | 175 + engine/jpeg-6/jversion.h | 14 + 202 files changed, 114554 insertions(+) create mode 100644 engine/GNU.TXT create mode 100644 engine/README.TXT create mode 100644 engine/code/3dfx.txt create mode 100644 engine/code/WinQuake.sln create mode 100644 engine/code/WinQuake.vcxproj create mode 100644 engine/code/anorm_dots.h create mode 100644 engine/code/anorms.h create mode 100644 engine/code/bspfile.h create mode 100644 engine/code/cd_win.c create mode 100644 engine/code/cdaudio.h create mode 100644 engine/code/cl_demo.c create mode 100644 engine/code/cl_input.c create mode 100644 engine/code/cl_main.c create mode 100644 engine/code/cl_parse.c create mode 100644 engine/code/cl_tent.c create mode 100644 engine/code/client.h create mode 100644 engine/code/cmd.c create mode 100644 engine/code/cmd.h create mode 100644 engine/code/common.c create mode 100644 engine/code/common.h create mode 100644 engine/code/conproc.c create mode 100644 engine/code/conproc.h create mode 100644 engine/code/console.c create mode 100644 engine/code/console.h create mode 100644 engine/code/crc.c create mode 100644 engine/code/crc.h create mode 100644 engine/code/cvar.c create mode 100644 engine/code/cvar.h create mode 100644 engine/code/draw.h create mode 100644 engine/code/gl_draw.c create mode 100644 engine/code/gl_fullbright.c create mode 100644 engine/code/gl_fullbright.h create mode 100644 engine/code/gl_mesh.c create mode 100644 engine/code/gl_model.c create mode 100644 engine/code/gl_model.h create mode 100644 engine/code/gl_refrag.c create mode 100644 engine/code/gl_rlight.c create mode 100644 engine/code/gl_rmain.c create mode 100644 engine/code/gl_rmisc.c create mode 100644 engine/code/gl_rsurf.c create mode 100644 engine/code/gl_screen.c create mode 100644 engine/code/gl_test.c create mode 100644 engine/code/gl_vidnt.c create mode 100644 engine/code/gl_warp.c create mode 100644 engine/code/gl_warp_sin.h create mode 100644 engine/code/glext.h create mode 100644 engine/code/glqnotes.txt create mode 100644 engine/code/glquake.h create mode 100644 engine/code/host.c create mode 100644 engine/code/host_cmd.c create mode 100644 engine/code/in_win.c create mode 100644 engine/code/input.h create mode 100644 engine/code/keys.c create mode 100644 engine/code/keys.h create mode 100644 engine/code/mathlib.c create mode 100644 engine/code/mathlib.h create mode 100644 engine/code/menu.c create mode 100644 engine/code/menu.h create mode 100644 engine/code/modelgen.h create mode 100644 engine/code/net.h create mode 100644 engine/code/net_dgrm.c create mode 100644 engine/code/net_dgrm.h create mode 100644 engine/code/net_loop.c create mode 100644 engine/code/net_loop.h create mode 100644 engine/code/net_main.c create mode 100644 engine/code/net_vcr.c create mode 100644 engine/code/net_vcr.h create mode 100644 engine/code/net_win.c create mode 100644 engine/code/net_wins.c create mode 100644 engine/code/net_wins.h create mode 100644 engine/code/net_wipx.c create mode 100644 engine/code/net_wipx.h create mode 100644 engine/code/pr_cmds.c create mode 100644 engine/code/pr_comp.h create mode 100644 engine/code/pr_edict.c create mode 100644 engine/code/pr_exec.c create mode 100644 engine/code/progdefs.h create mode 100644 engine/code/progdefs.q1 create mode 100644 engine/code/progdefs.q2 create mode 100644 engine/code/progs.h create mode 100644 engine/code/protocol.h create mode 100644 engine/code/quake.bmp create mode 100644 engine/code/quake.ico create mode 100644 engine/code/quakedef.h create mode 100644 engine/code/r_part.c create mode 100644 engine/code/render.h create mode 100644 engine/code/resource.h create mode 100644 engine/code/sbar.c create mode 100644 engine/code/sbar.h create mode 100644 engine/code/screen.h create mode 100644 engine/code/server.h create mode 100644 engine/code/snd_dma.c create mode 100644 engine/code/snd_fmod.c create mode 100644 engine/code/snd_fmod.h create mode 100644 engine/code/snd_mem.c create mode 100644 engine/code/snd_mix.c create mode 100644 engine/code/snd_win.c create mode 100644 engine/code/sound.h create mode 100644 engine/code/spritegn.h create mode 100644 engine/code/sv_main.c create mode 100644 engine/code/sv_move.c create mode 100644 engine/code/sv_phys.c create mode 100644 engine/code/sv_user.c create mode 100644 engine/code/sys.h create mode 100644 engine/code/sys_win.c create mode 100644 engine/code/unzip.c create mode 100644 engine/code/unzip.h create mode 100644 engine/code/vid.h create mode 100644 engine/code/vid_gamma.c create mode 100644 engine/code/vid_gamma.h create mode 100644 engine/code/view.c create mode 100644 engine/code/view.h create mode 100644 engine/code/wad.c create mode 100644 engine/code/wad.h create mode 100644 engine/code/wglext.h create mode 100644 engine/code/winquake.h create mode 100644 engine/code/winquake.rc create mode 100644 engine/code/world.c create mode 100644 engine/code/world.h create mode 100644 engine/code/wqreadme.txt create mode 100644 engine/code/zone.c create mode 100644 engine/code/zone.h create mode 100644 engine/docs/COMEXP.TXT create mode 100644 engine/docs/HELP.TXT create mode 100644 engine/docs/LICINFO.TXT create mode 100644 engine/docs/MANUAL.TXT create mode 100644 engine/docs/ORDER.TXT create mode 100644 engine/docs/README.TXT create mode 100644 engine/docs/RLICNSE.TXT create mode 100644 engine/docs/SLICNSE.TXT create mode 100644 engine/docs/TECHINFO.TXT create mode 100644 engine/docs/UQE Quake.pdf create mode 100644 engine/fmod-4/inc/fmod.h create mode 100644 engine/fmod-4/inc/fmod.hpp create mode 100644 engine/fmod-4/inc/fmod_codec.h create mode 100644 engine/fmod-4/inc/fmod_dsp.h create mode 100644 engine/fmod-4/inc/fmod_errors.h create mode 100644 engine/fmod-4/inc/fmod_memoryinfo.h create mode 100644 engine/fmod-4/inc/fmod_output.h create mode 100644 engine/jpeg-6/README create mode 100644 engine/jpeg-6/jcapimin.c create mode 100644 engine/jpeg-6/jcapistd.c create mode 100644 engine/jpeg-6/jccoefct.c create mode 100644 engine/jpeg-6/jccolor.c create mode 100644 engine/jpeg-6/jcdctmgr.c create mode 100644 engine/jpeg-6/jchuff.c create mode 100644 engine/jpeg-6/jchuff.h create mode 100644 engine/jpeg-6/jcinit.c create mode 100644 engine/jpeg-6/jcmainct.c create mode 100644 engine/jpeg-6/jcmarker.c create mode 100644 engine/jpeg-6/jcmaster.c create mode 100644 engine/jpeg-6/jcomapi.c create mode 100644 engine/jpeg-6/jconfig.h create mode 100644 engine/jpeg-6/jcparam.c create mode 100644 engine/jpeg-6/jcphuff.c create mode 100644 engine/jpeg-6/jcprepct.c create mode 100644 engine/jpeg-6/jcsample.c create mode 100644 engine/jpeg-6/jctrans.c create mode 100644 engine/jpeg-6/jdapimin.c create mode 100644 engine/jpeg-6/jdapistd.c create mode 100644 engine/jpeg-6/jdatadst.c create mode 100644 engine/jpeg-6/jdatasrc.c create mode 100644 engine/jpeg-6/jdcoefct.c create mode 100644 engine/jpeg-6/jdcolor.c create mode 100644 engine/jpeg-6/jdct.h create mode 100644 engine/jpeg-6/jddctmgr.c create mode 100644 engine/jpeg-6/jdhuff.c create mode 100644 engine/jpeg-6/jdhuff.h create mode 100644 engine/jpeg-6/jdinput.c create mode 100644 engine/jpeg-6/jdmainct.c create mode 100644 engine/jpeg-6/jdmarker.c create mode 100644 engine/jpeg-6/jdmaster.c create mode 100644 engine/jpeg-6/jdmerge.c create mode 100644 engine/jpeg-6/jdphuff.c create mode 100644 engine/jpeg-6/jdpostct.c create mode 100644 engine/jpeg-6/jdsample.c create mode 100644 engine/jpeg-6/jdtrans.c create mode 100644 engine/jpeg-6/jerror.c create mode 100644 engine/jpeg-6/jerror.h create mode 100644 engine/jpeg-6/jfdctflt.c create mode 100644 engine/jpeg-6/jfdctfst.c create mode 100644 engine/jpeg-6/jfdctint.c create mode 100644 engine/jpeg-6/jidctflt.c create mode 100644 engine/jpeg-6/jidctfst.c create mode 100644 engine/jpeg-6/jidctint.c create mode 100644 engine/jpeg-6/jidctred.c create mode 100644 engine/jpeg-6/jinclude.h create mode 100644 engine/jpeg-6/jload.c create mode 100644 engine/jpeg-6/jmemansi.c create mode 100644 engine/jpeg-6/jmemdos.c create mode 100644 engine/jpeg-6/jmemmgr.c create mode 100644 engine/jpeg-6/jmemname.c create mode 100644 engine/jpeg-6/jmemnobs.c create mode 100644 engine/jpeg-6/jmemsys.h create mode 100644 engine/jpeg-6/jmorecfg.h create mode 100644 engine/jpeg-6/jpegint.h create mode 100644 engine/jpeg-6/jpeglib.h create mode 100644 engine/jpeg-6/jpegtran.c create mode 100644 engine/jpeg-6/jquant1.c create mode 100644 engine/jpeg-6/jquant2.c create mode 100644 engine/jpeg-6/jutils.c create mode 100644 engine/jpeg-6/jversion.h diff --git a/engine/GNU.TXT b/engine/GNU.TXT new file mode 100644 index 0000000..2f3289a --- /dev/null +++ b/engine/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 diff --git a/engine/README.TXT b/engine/README.TXT new file mode 100644 index 0000000..132bc4d --- /dev/null +++ b/engine/README.TXT @@ -0,0 +1,60 @@ + +This is the complete source code for winquake, glquake, quakeworld, and +glquakeworld. + +The projects have been tested with visual C++ 6.0, but masm is also required +to build the assembly language files. It is possible to change a #define and +build with only C code, but the software rendering versions lose almost half +its speed. The OpenGL versions will not be effected very much. The +gas2masm tool was created to allow us to use the same source for the dos, +linux, and windows versions, but I don't really recommend anyone mess +with the asm code. + +The original dos version of Quake should also be buildable from these +sources, but we didn't bother trying. + +The code is all licensed under the terms of the GPL (gnu public license). +You should read the entire license, but the gist of it is that you can do +anything you want with the code, including sell your new version. The catch +is that if you distribute new binary versions, you are required to make the +entire source code available for free to everyone. + +Our previous code releases have been under licenses that preclude +commercial exploitation, but have no clause forcing sharing of source code. +There have been some unfortunate losses to the community as a result of +mod teams keeping their sources closed (and sometimes losing them). If +you are going to publicly release modified versions of this code, you must +also make source code available. I would encourage teams to even go a step +farther and investigate using public CVS servers for development where +possible. + +The primary intent of this release is for entertainment and educational +purposes, but the GPL does allow commercial exploitation if you obey the +full license. If you want to do something commercial and you just can't bear +to have your source changes released, we could still negotiate a separate +license agreement (for $$$), but I would encourage you to just live with the +GPL. + +All of the Quake data files remain copyrighted and licensed under the +original terms, so you cannot redistribute data from the original game, but if +you do a true total conversion, you can create a standalone game based on +this code. + +I will see about having the license changed on the shareware episode of +quake to allow it to be duplicated more freely (for linux distributions, for +example), but I can't give a timeframe for it. You can still download one of +the original quake demos and use that data with the code, but there are +restrictions on the redistribution of the demo data. + +If you never actually bought a complete version of Quake, you might want +to rummage around in a local software bargain bin for one of the originals, +or perhaps find a copy of the "Quake: the offering" boxed set with both +mission packs. + +Thanks to Dave "Zoid" Kirsh and Robert Duffy for doing the grunt work of +building this release. + +John Carmack +Id Software + + diff --git a/engine/code/3dfx.txt b/engine/code/3dfx.txt new file mode 100644 index 0000000..404aa9a --- /dev/null +++ b/engine/code/3dfx.txt @@ -0,0 +1,69 @@ +GLQuake Drivers + +Graphics Subsystem: Voodoo Graphics or Voodoo Rush + +Copyright ( 1997 3Dfx Interactive, Inc. ) +All Rights Reserved + +3Dfx Interactive, Inc. +www: www.3dfx.com +news: news.3dfx.com + +----------------------------------------------------------------------- +NOTE: GLQuake requires DirectX support DirectSound. DirectX can be +installed from the media provided with your Voodoo Based 3D Accelerator. + +Glide 2.31 or HIGHER runtime drivers *MUST* be installed to use this +GLQuake driver. Please download these drivers from your board +manufacturer OR unsupported drivers from http://www.3dfx.com +----------------------------------------------------------------------- + +Release Notes for GLQuake's mini-GL driver + +What's in the distribution? +--------------------------- + +This distribution contains GLQuake Drivers for Voodoo Based 3D +Accelerators. These drivers were tested on the following boards: + +Voodoo Graphics: +- Quantum 3D Obsidian +- Diamond Monster 3D +- Orchid Righteous 3D +- Deltron Realvision Flash 3D +- Guillemot MaxiGamer +- Skywell Magic 3D + +Voodoo Rush: +- Hercules Stringray 128-3D +- Intergraph Intense 3D Voodoo +- Jazz Multimedia Adrenaline Rush + +NOTE: The enclosed drivers are not meant to replace any Direct3D or +Glide drivers provided by your Voodoo Graphics card manufacturer. +Please obtain supported drivers from your board manufacturer. + +OEMSR2 and NT users: Do NOT replace OPENGL32.DLL located in your +Windows\SYSTEM directory. + +Requirements +------------ + +- Voodoo Graphics or Voodoo Rush Based 3D Accelerator +- Windows 95 (Windows NT is supported for Voodoo Rush) +- A PC with a Pentium 90 or higher CPU +- 16MB of RAM +- 2D Video card set at 16 bit color + +Support and Frequently Asked Questions +-------------------------------------- + +GLQuake is currently unsupported. You may however find answers to +questions on various Quake dedicated websites. 3Dfx provides a GLQuake +newsgroup on news.3dfx.com (Newsgroup name is 3dfx.games.glquake ) to +discuss GLQuake with other users. 3Dfx also provides a regularly +updated GLQuake FAQ at: http://www.3dfx.com/game_dev/quake_faq.html + + +Voodoo Graphics and Voodoo Rush are trademarks of 3Dfx Interactive, Inc. +All other trademarks are the property of their respective owners. \ No newline at end of file diff --git a/engine/code/WinQuake.sln b/engine/code/WinQuake.sln new file mode 100644 index 0000000..49a6129 --- /dev/null +++ b/engine/code/WinQuake.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinQuake", "WinQuake.vcxproj", "{6BF8FC22-9003-40F6-BF03-68A262C348BA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6BF8FC22-9003-40F6-BF03-68A262C348BA}.Debug|Win32.ActiveCfg = Debug|Win32 + {6BF8FC22-9003-40F6-BF03-68A262C348BA}.Debug|Win32.Build.0 = Debug|Win32 + {6BF8FC22-9003-40F6-BF03-68A262C348BA}.Release|Win32.ActiveCfg = Release|Win32 + {6BF8FC22-9003-40F6-BF03-68A262C348BA}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/engine/code/WinQuake.vcxproj b/engine/code/WinQuake.vcxproj new file mode 100644 index 0000000..2df9c61 --- /dev/null +++ b/engine/code/WinQuake.vcxproj @@ -0,0 +1,305 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {6BF8FC22-9003-40F6-BF03-68A262C348BA} + 10.0.14393.0 + + + + Application + false + v140 + + + Application + false + v140 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + .\Release\ + .\Release\ + .\Debug\ + .\Debug\ + AllRules.ruleset + + + AllRules.ruleset + + + UQE-Quake + UQE-Quake + + + false + + + false + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(TargetDir)/$(ProjectName).tlb + + + + + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;GLQUAKE + .\Release\WinQuake.pch + .\Release\ + .\Release\ + .\Release\ + MultiThreaded + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + .\Release\UQE-Quake.exe + false + Windows + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;winmm.lib;wsock32.lib;glu32.lib + + + true + $(TargetDir)/$(ProjectName).bsc + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(TargetDir)/$(ProjectName).tlb + + + + + .\Debug\WinQuake.pch + .\Debug\ + .\Debug\ + .\Debug\ + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;GLQUAKE + Disabled + MultiThreadedDebug + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + .\Debug\UQE-Quake.exe + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;winmm.lib;wsock32.lib;glu32.lib + Windows + + + true + $(TargetDir)/$(ProjectName).bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/engine/code/anorm_dots.h b/engine/code/anorm_dots.h new file mode 100644 index 0000000..2845fa2 --- /dev/null +++ b/engine/code/anorm_dots.h @@ -0,0 +1,37 @@ +/* +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. + +*/ +{ +{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/engine/code/anorms.h b/engine/code/anorms.h new file mode 100644 index 0000000..11a9007 --- /dev/null +++ b/engine/code/anorms.h @@ -0,0 +1,181 @@ +/* +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. + +*/ +{-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/engine/code/bspfile.h b/engine/code/bspfile.h new file mode 100644 index 0000000..2265079 --- /dev/null +++ b/engine/code/bspfile.h @@ -0,0 +1,324 @@ +/* +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. + +*/ + + +// upper design bounds + +#define MAX_MAP_HULLS 4 + +#define MAX_MAP_MODELS 1024 // jkrige - design bounds : 256 +#define MAX_MAP_BRUSHES 8192 // jkrige - design bounds : 4096 +#define MAX_MAP_ENTITIES 2048 // jkrige - design bounds : 1024 +#define MAX_MAP_ENTSTRING 0x40000 // jkrige - design bounds : 65536 + +#define MAX_MAP_PLANES 65536 // jkrige - design bounds : 32767 +#define MAX_MAP_NODES 65536 // jkrige - design bounds : 32767 // because negative shorts are contents +#define MAX_MAP_CLIPNODES 65536 // jkrige - design bounds : 32767 // +#define MAX_MAP_LEAFS 16384 // jkrige - design bounds : 8192 +#define MAX_MAP_VERTS 65535 +#define MAX_MAP_FACES 65535 +#define MAX_MAP_MARKSURFACES 65535 +#define MAX_MAP_TEXINFO 8192 // jkrige - design bounds : 4096 +#define MAX_MAP_EDGES 256000 +#define MAX_MAP_SURFEDGES 512000 +#define MAX_MAP_TEXTURES 1024 // jkrige - design bounds : 512 +#define MAX_MAP_MIPTEX 0x400000 // jkrige - design bounds : 0x200000 +#define MAX_MAP_LIGHTING 0x200000 // jkrige - design bounds : 0x100000 +#define MAX_MAP_VISIBILITY 0x200000 // jkrige - design bounds : 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 + +// 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/engine/code/cd_win.c b/engine/code/cd_win.c new file mode 100644 index 0000000..42a0703 --- /dev/null +++ b/engine/code/cd_win.c @@ -0,0 +1,595 @@ +/* +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. + +*/ +// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All +// rights reserved. + + +#include "quakedef.h" + +#ifndef UQE_FMOD_CDAUDIO +#include + +extern HWND mainwindow; +extern cvar_t bgmvolume; + +static qboolean cdValid = false; +static qboolean playing = false; +static qboolean wasPlaying = false; +static qboolean initialized = false; +static qboolean enabled = false; +static qboolean playLooping = false; +static float cdvolume; +static byte remap[100]; +static byte cdrom; +static byte playTrack; +static byte maxTrack; + +// jkrige - cd audio volume fix +static UINT CD_ID; +static unsigned long CD_OrigVolume; +// jkrige - cd audio volume fix + +UINT wDeviceID; + +// jkrige - CD Resume +static DWORD end_pos; +// jkrige - CD Resume + + +static void CDAudio_Eject(void) +{ + DWORD dwReturn; + + if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, (DWORD)NULL)) + Con_DPrintf("MCI_SET_DOOR_OPEN failed (%i)\n", dwReturn); +} + + +static void CDAudio_CloseDoor(void) +{ + DWORD dwReturn; + + if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, (DWORD)NULL)) + Con_DPrintf("MCI_SET_DOOR_CLOSED failed (%i)\n", dwReturn); +} + + +static int CDAudio_GetAudioDiskInfo(void) +{ + DWORD dwReturn; + MCI_STATUS_PARMS mciStatusParms; + + + cdValid = false; + + mciStatusParms.dwItem = MCI_STATUS_READY; + dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms); + if (dwReturn) + { + Con_DPrintf("CDAudio: drive ready test - get status failed\n"); + return -1; + } + if (!mciStatusParms.dwReturn) + { + Con_DPrintf("CDAudio: drive not ready\n"); + return -1; + } + + mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; + dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms); + if (dwReturn) + { + Con_DPrintf("CDAudio: get tracks - status failed\n"); + return -1; + } + if (mciStatusParms.dwReturn < 1) + { + Con_DPrintf("CDAudio: no music tracks\n"); + return -1; + } + + cdValid = true; + maxTrack = mciStatusParms.dwReturn; + + return 0; +} + + +void CDAudio_Play(byte track, qboolean looping) +{ + DWORD dwReturn; + MCI_PLAY_PARMS mciPlayParms; + MCI_STATUS_PARMS mciStatusParms; + + if (!enabled) + return; + + if (!cdValid) + { + CDAudio_GetAudioDiskInfo(); + if (!cdValid) + return; + } + + track = remap[track]; + + if (track < 1 || track > maxTrack) + { + Con_DPrintf("CDAudio: Bad track number %u.\n", track); + return; + } + + // don't try to play a non-audio track + mciStatusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK; + mciStatusParms.dwTrack = track; + dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms); + if (dwReturn) + { + Con_DPrintf("MCI_STATUS failed (%i)\n", dwReturn); + return; + } + if (mciStatusParms.dwReturn != MCI_CDA_TRACK_AUDIO) + { + Con_Printf("CDAudio: track %i is not audio\n", track); + return; + } + + // get the length of the track to be played + mciStatusParms.dwItem = MCI_STATUS_LENGTH; + mciStatusParms.dwTrack = track; + dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms); + if (dwReturn) + { + Con_DPrintf("MCI_STATUS failed (%i)\n", dwReturn); + return; + } + + if (playing) + { + if (playTrack == track) + return; + CDAudio_Stop(); + } + + mciPlayParms.dwFrom = MCI_MAKE_TMSF(track, 0, 0, 0); + mciPlayParms.dwTo = (mciStatusParms.dwReturn << 8) | track; + + // jkrige - CD Resume + end_pos = mciPlayParms.dwTo; + // jkrige - CD Resume + + mciPlayParms.dwCallback = (DWORD)mainwindow; + dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD)(LPVOID) &mciPlayParms); + if (dwReturn) + { + Con_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn); + return; + } + + playLooping = looping; + playTrack = track; + playing = true; + + if (cdvolume == 0.0) + CDAudio_Pause (); +} + + +void CDAudio_Stop(void) +{ + DWORD dwReturn; + + if (!enabled) + return; + + if (!playing) + return; + + if (dwReturn = mciSendCommand(wDeviceID, MCI_STOP, 0, (DWORD)NULL)) + Con_DPrintf("MCI_STOP failed (%i)", dwReturn); + + wasPlaying = false; + playing = false; +} + + +void CDAudio_Pause(void) +{ + DWORD dwReturn; + MCI_GENERIC_PARMS mciGenericParms; + + if (!enabled) + return; + + if (!playing) + return; + + mciGenericParms.dwCallback = (DWORD)mainwindow; + if (dwReturn = mciSendCommand(wDeviceID, MCI_PAUSE, 0, (DWORD)(LPVOID) &mciGenericParms)) + Con_DPrintf("MCI_PAUSE failed (%i)", dwReturn); + + wasPlaying = playing; + playing = false; +} + + +void CDAudio_Resume(void) +{ + DWORD dwReturn; + + // jkrige - CD Resume + MCI_STATUS_PARMS mciStatusParms; + // jkrige - CD Resume + + MCI_PLAY_PARMS mciPlayParms; + + if (!enabled) + return; + + if (!cdValid) + return; + + if (!wasPlaying) + return; + + // jkrige - CD Resume + //mciPlayParms.dwFrom = MCI_MAKE_TMSF(playTrack, 0, 0, 0); + //mciPlayParms.dwTo = MCI_MAKE_TMSF(playTrack + 1, 0, 0, 0); + //mciPlayParms.dwCallback = (DWORD)mainwindow; + //dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_TO | MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms); + + mciStatusParms.dwItem = MCI_STATUS_POSITION; + dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR) (LPVOID) &mciStatusParms); + if (dwReturn) + { + Con_DPrintf("MCI_STATUS failed (%i)\n", dwReturn); + return; + } + mciPlayParms.dwFrom = mciStatusParms.dwReturn; + mciPlayParms.dwTo = end_pos; // set in CDAudio_Play() + mciPlayParms.dwCallback = (DWORD_PTR)mainwindow; + dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_FROM | MCI_TO | MCI_NOTIFY, (DWORD_PTR)(LPVOID) &mciPlayParms); + // jkrige - CD Resume + + + if (dwReturn) + { + Con_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn); + return; + } + playing = true; +} + + +static void CD_f (void) +{ + char *command; + int ret; + int n; + int startAddress; + + if (Cmd_Argc() < 2) + return; + + command = Cmd_Argv (1); + + if (Q_strcasecmp(command, "on") == 0) + { + enabled = true; + return; + } + + if (Q_strcasecmp(command, "off") == 0) + { + if (playing) + CDAudio_Stop(); + enabled = false; + return; + } + + if (Q_strcasecmp(command, "reset") == 0) + { + enabled = true; + if (playing) + CDAudio_Stop(); + for (n = 0; n < 100; n++) + remap[n] = n; + CDAudio_GetAudioDiskInfo(); + return; + } + + if (Q_strcasecmp(command, "remap") == 0) + { + ret = Cmd_Argc() - 2; + if (ret <= 0) + { + for (n = 1; n < 100; n++) + if (remap[n] != n) + Con_Printf(" %u -> %u\n", n, remap[n]); + return; + } + for (n = 1; n <= ret; n++) + remap[n] = Q_atoi(Cmd_Argv (n+1)); + return; + } + + if (Q_strcasecmp(command, "close") == 0) + { + CDAudio_CloseDoor(); + return; + } + + if (!cdValid) + { + CDAudio_GetAudioDiskInfo(); + if (!cdValid) + { + Con_Printf("No CD in player.\n"); + return; + } + } + + if (Q_strcasecmp(command, "play") == 0) + { + CDAudio_Play((byte)Q_atoi(Cmd_Argv (2)), false); + return; + } + + if (Q_strcasecmp(command, "loop") == 0) + { + CDAudio_Play((byte)Q_atoi(Cmd_Argv (2)), true); + return; + } + + if (Q_strcasecmp(command, "stop") == 0) + { + CDAudio_Stop(); + return; + } + + if (Q_strcasecmp(command, "pause") == 0) + { + CDAudio_Pause(); + return; + } + + if (Q_strcasecmp(command, "resume") == 0) + { + CDAudio_Resume(); + return; + } + + if (Q_strcasecmp(command, "eject") == 0) + { + if (playing) + CDAudio_Stop(); + CDAudio_Eject(); + cdValid = false; + return; + } + + if (Q_strcasecmp(command, "info") == 0) + { + Con_Printf("%u tracks\n", maxTrack); + if (playing) + Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack); + else if (wasPlaying) + Con_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack); + Con_Printf("Volume is %f\n", cdvolume); + return; + } +} + + +LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (lParam != wDeviceID) + return 1; + + switch (wParam) + { + case MCI_NOTIFY_SUCCESSFUL: + if (playing) + { + playing = false; + if (playLooping) + CDAudio_Play(playTrack, true); + } + break; + + case MCI_NOTIFY_ABORTED: + case MCI_NOTIFY_SUPERSEDED: + break; + + case MCI_NOTIFY_FAILURE: + Con_DPrintf("MCI_NOTIFY_FAILURE\n"); + CDAudio_Stop (); + cdValid = false; + break; + + default: + Con_DPrintf("Unexpected MM_MCINOTIFY type (%i)\n", wParam); + return 1; + } + + return 0; +} + +// jkrige - cd audio volume fix +void CD_SetVolume(unsigned long Volume) +{ + if (CD_ID != -1) + auxSetVolume(CD_ID,(Volume<<16)+Volume); +} + +void CD_FindCDAux(void) +{ + UINT NumDevs,counter; + MMRESULT Result; + AUXCAPS Caps; + + CD_ID = -1; + if (!COM_CheckParm("-usecdvolume")) + return; + NumDevs = auxGetNumDevs(); + for(counter=0;counter 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; +}*/ + +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) // always grab until fully connected + { + // jkrige - fix demo playback across maps + // Pa3PyX: always wait for full frame update on stuff + // messages. If the server stuffs a reconnect, + // we must wait for the client to re-initialize + // before accepting further messages. Otherwise + // demo playback may freeze. + if (stufftext_frame == host_framecount) { + return 0; + } + // jkrige - fix demo playback across maps + + 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); + net_message.cursize = ( (cls.demobuffer[cls.demobufferposition + 3] << 24) + (cls.demobuffer[cls.demobufferposition + 2] << 16) + (cls.demobuffer[cls.demobufferposition + 1] << 8) + (cls.demobuffer[cls.demobufferposition + 0]) ); + cls.demobufferposition += 4; + net_message.cursize = LittleLong (net_message.cursize); + + VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); + for (i=0 ; i<3 ; i++) + { + //r = fread (&f, 4, 1, cls.demofile); + memcpy(&f, &cls.demobuffer[cls.demobufferposition], 4); + cls.demobufferposition += 4; + cl.mviewangles[0][i] = LittleFloat (f); + } + + 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; + //} + + if(net_message.cursize == 0 || net_message.cursize > (cls.demobufferlength - cls.demobufferposition)) + { + CL_StopPlayback (); + return 0; + } + + for(i = 0; i < net_message.cursize; i++) + { + net_message.data[i] = cls.demobuffer[cls.demobufferposition++]; + } + + 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; +} +// jkrige - pk3 file support + + +/* +==================== +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] +==================== +*/ + +// jkrige - get rid of the menu and/or console +#define m_none 0 // enumerated menu state from menu.c +extern int m_state; +// jkrige - get rid of the menu and/or console + +// jkrige - pk3 file support +/*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); + + // jkrige - moved to CL_PlayDemo_f + // Get a new message on playback start. + cls.td_lastframe = -1; + // jkrige - moved to CL_PlayDemo_f +}*/ +void CL_PlayDemo_f (void) +{ + char name[256]; + int c; + //int fi; + qboolean neg = false; + + if (cmd_source != src_command) + return; + + if (Cmd_Argc() != 2) + { + Con_Printf ("playdemo : 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); + cls.demobufferlength = COM_FOpenFile (name, &cls.demofile); + cls.demobufferposition = 0; + + if (/*!cls.demofile |*/ cls.demobufferlength < 1) + { + Con_Printf ("ERROR: couldn't open.\n"); + cls.demonum = -1; // stop demo loop + return; + } + + cls.demobuffer = COM_FReadFile(cls.demofile, cls.demobufferlength); + if (!cls.demobuffer) + return; + + cls.demoplayback = true; + cls.state = ca_connected; + cls.forcetrack = 0; + + while ((c = cls.demobuffer[cls.demobufferposition++]) != '\n') + { + if (c == '-') + neg = true; + else + cls.forcetrack = cls.forcetrack * 10 + (c - '0'); + } + + if (neg) + cls.forcetrack = -cls.forcetrack; + + // jkrige - get rid of the menu and/or console + if (key_dest == key_console || key_dest == key_menu) + { + key_dest = key_game; + m_state = m_none; + } + // jkrige - get rid of the menu and/or console + + +// ZOID, fscanf is evil +// fscanf (cls.demofile, "%i\n", &cls.forcetrack); + + // jkrige - moved to CL_PlayDemo_f + // Get a new message on playback start. + cls.td_lastframe = -1; + // jkrige - moved to CL_PlayDemo_f +} +// jkrige - pk3 file support + + +/* +==================== +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; + + // jkrige - moved to CL_PlayDemo_f() + //cls.td_lastframe = -1; // get a new message this frame + // jkrige - moved to CL_PlayDemo_f() +} + diff --git a/engine/code/cl_input.c b/engine/code/cl_input.c new file mode 100644 index 0000000..aff2946 --- /dev/null +++ b/engine/code/cl_input.c @@ -0,0 +1,469 @@ +/* +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. + +*/ +// 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" + +/* +=============================================================================== + +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; // jkrige - mlook cvar, removed klook command +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 +} + +// jkrige - removed klook command +//void IN_KLookDown (void) {KeyDown(&in_klook);} +//void IN_KLookUp (void) {KeyUp(&in_klook);} +// jkrige - removed klook command + +// jkrige - mlook cvar +/*void IN_MLookDown (void) {KeyDown(&in_mlook);} +void IN_MLookUp (void) { +KeyUp(&in_mlook); +if ( !(in_mlook.state&1) && lookspring.value) + V_StartPitchDrift(); +}*/ +// jkrige - mlook cvar + +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}; + +// jkrige - reduced strafe speed +//cvar_t cl_sidespeed = {"cl_sidespeed","350"}; +cvar_t cl_sidespeed = {"cl_sidespeed","225"}; +// jkrige - reduced strafe speed + + +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"}; + +cvar_t cl_mlook = {"cl_mlook", "1", true}; // jkrige - mlook cvar +cvar_t cl_slook = {"cl_slook", "0", true}; // jkrige - slook cvar + +/* +================ +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]); + } + + // jkrige - removed klook command + /*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); + }*/ + // jkrige - removed klook command + + 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 (); + + if (cl.viewangles[PITCH] > 80) + cl.viewangles[PITCH] = 80; + if (cl.viewangles[PITCH] < -70) + cl.viewangles[PITCH] = -70; + + 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); + + // jkrige - removed klook command + //if (! (in_klook.state & 1) ) + //{ + cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward); + cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back); + //} + // jkrige - removed klook command + +// +// adjust for speed key +// + // jkrige - speed key now acts as slow key when always run is chosen + //if (in_speed.state & 1) + if ( ( (cl_forwardspeed.value <= 200 && in_speed.state & 1) || (cl_forwardspeed.value > 200 && !(in_speed.state & 1)) ) ) + { + cmd->forwardmove *= cl_movespeedkey.value; + cmd->sidemove *= cl_movespeedkey.value; + cmd->upmove *= cl_movespeedkey.value; + } + // jkrige - speed key now acts as slow key when always run is chosen + +#ifdef QUAKE2 + cmd->lightlevel = cl.light_level; +#endif +} + + + +/* +============== +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++) + MSG_WriteAngle (&buf, cl.viewangles[i]); + + 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; + +#ifdef QUAKE2 +// +// light level +// + MSG_WriteByte (&buf, cmd->lightlevel); +#endif + +// +// 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); // jkrige - removed klook command + //Cmd_AddCommand ("-klook", IN_KLookUp); // jkrige - removed klook command + //Cmd_AddCommand ("+mlook", IN_MLookDown); // jkrige - removed mlook command + //Cmd_AddCommand ("-mlook", IN_MLookUp); // jkrige - removed mlook command + +} + diff --git a/engine/code/cl_main.c b/engine/code/cl_main.c new file mode 100644 index 0000000..092868c --- /dev/null +++ b/engine/code/cl_main.c @@ -0,0 +1,800 @@ +/* +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. + +*/ +// 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"}; + +// jkrige - configurable fps caps +cvar_t cl_maxfps = {"cl_maxfps", "110", true}; +// jkrige - configurable fps caps + +cvar_t lookspring = {"lookspring","0", true}; +cvar_t lookstrafe = {"lookstrafe","0", true}; + +// jkrige - mouse sensitivity +//cvar_t sensitivity = {"sensitivity","5", true}; +cvar_t sensitivity = {"sensitivity","5.5", true}; +// jkrige - mouse sensitivity + +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}; + + +client_static_t cls; +client_state_t cl; +// FIXME: put these on hunk? +efrag_t cl_efrags[MAX_EFRAGS]; +entity_t cl_entities[MAX_EDICTS]; +entity_t cl_static_entities[MAX_STATIC_ENTITIES]; +lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; +dlight_t cl_dlights[MAX_DLIGHTS]; + +int cl_numvisedicts; +entity_t *cl_visedicts[MAX_VISEDICTS]; + +/* +===================== +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_entities, 0, sizeof(cl_entities)); + 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)); + +// +// 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]); + } +} + + +/* +=============== +SetPal + +Debugging tool, just flashes the screen +=============== +*/ +void SetPal (int i) +{ +#if 0 + static int old; + byte pal[768]; + int c; + + if (i == old) + return; + old = i; + + if (i==0) + VID_SetPalette (host_basepal); + else if (i==1) + { + for (c=0 ; c<768 ; c+=3) + { + pal[c] = 0; + pal[c+1] = 255; + pal[c+2] = 0; + } + VID_SetPalette (pal); + } + else + { + for (c=0 ; c<768 ; c+=3) + { + pal[c] = 0; + pal[c+1] = 0; + pal[c+2] = 255; + } + VID_SetPalette (pal); + } +#endif +} + +/* +=============== +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; + + // jkrige - .lit colored lights + dl->color [0] = dl->color[1] = dl->color[2] = 1; + // jkrige - .lit colored lights + + return dl; + } + } + } + +// then look for anything else + dl = cl_dlights; + for (i=0 ; idie < cl.time) + { + memset (dl, 0, sizeof(*dl)); + dl->key = key; + + // jkrige - .lit colored lights + dl->color [0] = dl->color[1] = dl->color[2] = 1; + // jkrige - .lit colored lights + + return dl; + } + } + + dl = &cl_dlights[0]; + memset (dl, 0, sizeof(*dl)); + dl->key = key; + + // jkrige - .lit colored lights + dl->color [0] = dl->color[1] = dl->color[2] = 1; + // jkrige - .lit colored lights + + 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 || cl_nolerp.value || 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; +//Con_Printf ("frac: %f\n",frac); + if (frac < 0) + { + if (frac < -0.01) + { +SetPal(1); + cl.time = cl.mtime[1]; +// Con_Printf ("low frac\n"); + } + frac = 0; + } + else if (frac > 1) + { + if (frac > 1.01) + { +SetPal(2); + cl.time = cl.mtime[0]; +// Con_Printf ("high frac\n"); + } + frac = 1; + } + else + SetPal(0); + + 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; + 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 + } + + // 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); +#ifdef QUAKE2 + if (ent->effects & EF_DARKFIELD) + R_DarkFieldParticles (ent); +#endif + 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; + } + 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; + } +#ifdef QUAKE2 + if (ent->effects & EF_DARKLIGHT) + { + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = 200.0 + (rand()&31); + dl->die = cl.time + 0.001; + dl->dark = true; + } + if (ent->effects & EF_LIGHT) + { + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = 200; + dl->die = cl.time + 0.001; + } +#endif + + 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; + + // jkrige - removed chase + if (i == cl.viewentity) // && !chase_active.value + continue; + // jkrige - removed chase + +#ifdef QUAKE2 + if ( ent->effects & EF_NODRAW ) + continue; +#endif + 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; + + 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 (); + +// +// 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_Init +================= +*/ +void CL_Init (void) +{ + SZ_Alloc (&cls.message, 1024); + + CL_InitInput (); + CL_InitTEnts (); + +// +// register our commands +// + Cvar_RegisterVariable (&cl_name); + Cvar_RegisterVariable (&cl_color); + Cvar_RegisterVariable (&cl_upspeed); + Cvar_RegisterVariable (&cl_forwardspeed); + Cvar_RegisterVariable (&cl_backspeed); + Cvar_RegisterVariable (&cl_sidespeed); + Cvar_RegisterVariable (&cl_movespeedkey); + Cvar_RegisterVariable (&cl_yawspeed); + Cvar_RegisterVariable (&cl_pitchspeed); + Cvar_RegisterVariable (&cl_anglespeedkey); + Cvar_RegisterVariable (&cl_shownet); + Cvar_RegisterVariable (&cl_nolerp); + + // jkrige - configurable fps caps + Cvar_RegisterVariable (&cl_maxfps); + // jkrige - configurable fps caps + + Cvar_RegisterVariable (&lookspring); + Cvar_RegisterVariable (&lookstrafe); + Cvar_RegisterVariable (&sensitivity); + + Cvar_RegisterVariable (&cl_mlook); // jkrige - mlook cvar + Cvar_RegisterVariable (&cl_slook); // jkrige - slook cvar + + Cvar_RegisterVariable (&m_pitch); + Cvar_RegisterVariable (&m_yaw); + Cvar_RegisterVariable (&m_forward); + Cvar_RegisterVariable (&m_side); + +// Cvar_RegisterVariable (&cl_autofire); + + 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); +} + diff --git a/engine/code/cl_parse.c b/engine/code/cl_parse.c new file mode 100644 index 0000000..8e5399b --- /dev/null +++ b/engine/code/cl_parse.c @@ -0,0 +1,1026 @@ +/* +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. + +*/ +// cl_parse.c -- parse a message received from the server + +#include "quakedef.h" + +// jkrige - fix demo playback across maps (music) +// Pa3PyX: new var +extern int stufftext_frame; +// jkrige - fix demo playback across maps + +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", + "svc_skybox" // jkrige - skybox +}; + +//============================================================================= + +/* +=============== +CL_EntityNum + +This error checks and tracks the total number of entities +=============== +*/ +entity_t *CL_EntityNum (int num) +{ + if (num >= cl.num_entities) + { + if (num >= 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.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; + + channel = MSG_ReadShort (); + sound_num = MSG_ReadByte (); + + ent = channel >> 3; + channel &= 7; + + if (ent > 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 (); + if (i != PROTOCOL_VERSION) + { + Con_Printf ("Server returned version %i, not %i", i, PROTOCOL_VERSION); + return; + } + +// 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\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); + Con_Printf ("%c%s\n", 2, str); + +// +// 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); + } + +// 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); + } + +// +// 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; + + 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; + + 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 +#ifdef GLQUAKE + if (num > 0 && num <= cl.maxclients) + R_TranslatePlayerSkin (num - 1); +#endif + } + + 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; + } + +#ifdef GLQUAKE + 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_TranslatePlayerSkin (num - 1); + } + +#else + + if (bits & U_SKIN) + ent->skinnum = MSG_ReadByte(); + else + ent->skinnum = ent->baseline.skin; +#endif + + 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]; + + if ( bits & U_NOLERP ) + ent->forcelink = true; + + 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 i; + + ent->baseline.modelindex = MSG_ReadByte (); + ent->baseline.frame = MSG_ReadByte (); + 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 (); + } +} + + +/* +================== +CL_ParseClientdata + +Server information pertaining to this client only +================== +*/ +void CL_ParseClientdata (int bits) +{ + int i, j; + + 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; +#ifdef GLQUAKE + R_TranslatePlayerSkin (slot); +#endif + + for (i=0 ; i= MAX_STATIC_ENTITIES) + Host_Error ("Too many static entities"); + ent = &cl_static_entities[i]; + cl.num_statics++; + CL_ParseBaseline (ent); + +// copy it to the current state + ent->model = cl.model_precache[ent->baseline.modelindex]; + ent->frame = ent->baseline.frame; + ent->colormap = vid.colormap; + ent->skinnum = ent->baseline.skin; + ent->effects = ent->baseline.effects; + + VectorCopy (ent->baseline.origin, ent->origin); + VectorCopy (ent->baseline.angles, ent->angles); + R_AddEfrags (ent); +} + +/* +=================== +CL_ParseStaticSound +=================== +*/ +void CL_ParseStaticSound (void) +{ + vec3_t org; + int sound_num, vol, atten; + int i; + + for (i=0 ; i<3 ; i++) + org[i] = MSG_ReadCoord (); + sound_num = MSG_ReadByte (); + 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; + +// +// 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 & 128) + { + SHOWNET("fast update"); + CL_ParseUpdate (cmd&127); + continue; + } + + SHOWNET(svc_strings[cmd]); + + // other commands + switch (cmd) + { + default: + Host_Error ("CL_ParseServerMessage: Illegible server message\n"); + 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: + i = MSG_ReadShort (); + CL_ParseClientdata (i); + break; + + case svc_version: + i = MSG_ReadLong (); + if (i != PROTOCOL_VERSION) + Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, PROTOCOL_VERSION); + break; + + case svc_disconnect: + Host_EndGame ("Server disconnected\n"); + + case svc_print: + Con_Printf ("%s", MSG_ReadString ()); + break; + + case svc_centerprint: + SCR_CenterPrint (MSG_ReadString ()); + break; + + case svc_stufftext: + // jkrige - fix demo playback across maps + // Pa3PyX: allow full frame update on stuff messages + stufftext_frame = host_framecount; + // jkrige - fix demo playback across maps + + 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); + break; + + case svc_sound: + CL_ParseStartSoundPacket(); + break; + + case svc_stopsound: + i = MSG_ReadShort(); + S_StopSound(i>>3, i&7); + break; + + case svc_updatename: + //Sbar_Changed (); // jkrige - always draw sbar + 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 (); // jkrige - always draw sbar + 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 (); // jkrige - always draw sbar + 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)); + break; + case svc_spawnstatic: + CL_ParseStatic (); + break; + case svc_temp_entity: + CL_ParseTEnt (); + break; + + case svc_setpause: + { + cl.paused = MSG_ReadByte (); + + if (cl.paused) + { + // jkrige - fmod sound system - begin +#ifdef UQE_FMOD + FMOD_MusicPause(); +#else + CDAudio_Pause(); +#endif + // jkrige - fmod sound system - end +#ifdef _WIN32 + VID_HandlePause (true); +#endif + } + else + { + // jkrige - fmod sound system - begin +#ifdef UQE_FMOD + FMOD_MusicResume(); +#else + CDAudio_Resume(); +#endif + // jkrige - fmod sound system - end +#ifdef _WIN32 + VID_HandlePause (false); +#endif + } + } + 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; + 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 (); + break; + + case svc_cdtrack: + cl.cdtrack = MSG_ReadByte (); + cl.looptrack = MSG_ReadByte (); + byte cdtrack; + + // jkrige - invalid track number (hipnotic demo) + // if the demo playback returns with an invalid track number, set forcetrack to -1 + if (cls.demoplayback && cls.forcetrack < -1) + cls.forcetrack = -1; + // jkrige - invalid track number (hipnotic demo) + + if ((cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1)) + { + if (cls.forcetrack == 1) + cls.forcetrack++; + + cdtrack = (byte)cls.forcetrack; + } + else + { + cdtrack = (byte)cl.cdtrack; + } + + // jkrige - fmod sound system - begin +#ifdef UQE_FMOD + FMOD_MusicStart(va("%i", (int)cdtrack), true, false); +#else + CDAudio_Play(cdtrack, true); +#endif + // jkrige - fmod sound system - end + break; + + // jkrige - skybox + case svc_skybox: + strcpy(cl.skybox, MSG_ReadString()); +#ifdef GLQUAKE + Cvar_Set("gl_skytype", "0"); + if (strcmpi(cl.skybox, "") != 0) + R_LoadSkys (); +#endif + + break; + // jkrige - skybox + + 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 + SCR_CenterPrint (MSG_ReadString ()); + break; + + case svc_cutscene: + cl.intermission = 3; + cl.completed_time = cl.time; + vid.recalc_refdef = true; // go to full screen + SCR_CenterPrint (MSG_ReadString ()); + break; + + case svc_sellscreen: + Cmd_ExecuteString ("help", src_command); + break; + } + } +} + diff --git a/engine/code/cl_tent.c b/engine/code/cl_tent.c new file mode 100644 index 0000000..546e832 --- /dev/null +++ b/engine/code/cl_tent.c @@ -0,0 +1,394 @@ +/* +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. + +*/ +// 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; +#ifdef QUAKE2 +sfx_t *cl_sfx_imp; +sfx_t *cl_sfx_rail; +#endif + +/* +================= +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"); +#ifdef QUAKE2 + cl_sfx_imp = S_PrecacheSound ("shambler/sattck1.wav"); + cl_sfx_rail = S_PrecacheSound ("weapons/lstart.wav"); +#endif +} + +/* +================= +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; + } + } + Con_Printf ("beam list overflow!\n"); +} + +/* +================= +CL_ParseTEnt +================= +*/ +void CL_ParseTEnt (void) +{ + int type; + vec3_t pos; +#ifdef QUAKE2 + vec3_t endpos; +#endif + 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; + +#ifdef QUAKE2 + case TE_IMPLOSION: + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + S_StartSound (-1, 0, cl_sfx_imp, pos, 1, 1); + break; + + case TE_RAILTRAIL: + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + endpos[0] = MSG_ReadCoord (); + endpos[1] = MSG_ReadCoord (); + endpos[2] = MSG_ReadCoord (); + S_StartSound (-1, 0, cl_sfx_rail, pos, 1, 1); + S_StartSound (-1, 1, cl_sfx_r_exp3, endpos, 1, 1); + R_RocketTrail (pos, endpos, 0+128); + R_ParticleExplosion (endpos); + dl = CL_AllocDlight (-1); + VectorCopy (endpos, dl->origin); + dl->radius = 350; + dl->die = cl.time + 0.5; + dl->decay = 300; + break; +#endif + + 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; + beam_t *b; + vec3_t dist, org; + float d; + entity_t *ent; + float yaw, pitch; + float forward; + + num_temp_entities = 0; + +// 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; + + for (i=0 ; i<3 ; i++) + org[i] += dist[i]*30; + d -= 30; + } + } + +} + + diff --git a/engine/code/client.h b/engine/code/client.h new file mode 100644 index 0000000..cb83143 --- /dev/null +++ b/engine/code/client.h @@ -0,0 +1,408 @@ +/* +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. + +*/ +// client.h + +typedef struct +{ + vec3_t viewangles; + +// intended velocities + float forwardmove; + float sidemove; + float upmove; + +#ifdef QUAKE2 + byte lightlevel; +#endif + +} usercmd_t; + +typedef struct +{ + int length; + char map[MAX_STYLESTRING]; +} 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 + +// jkrige - increase dlights +//#define MAX_DLIGHTS 32 +#define MAX_DLIGHTS 64 +// jkrige - increase dlights + + +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; +#ifdef QUAKE2 + qboolean dark; // subtracts light instead of adding +#endif + + // jkrige - .lit colored lights + vec3_t color; + // jkrige - .lit colored lights + +} dlight_t; + + +#define MAX_BEAMS 24 +typedef struct +{ + int entity; + struct model_s *model; + float endtime; + vec3_t start, end; +} beam_t; + +#define MAX_EFRAGS 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; + + // jkrige - pk3 file support + byte *demobuffer; + int demobufferlength; + int demobufferposition; + // jkrige - pk3 file support + + 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[40]; // for display on solo scoreboard + 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 + + // jkrige - skybox + char skybox[128]; + // jkrige - skybox + +// frag scoreboard + scoreboard_t *scores; // [cl.maxclients] + +#ifdef QUAKE2 +// light level at player's position including dlights +// this is sent back to the server each frame +// architectually ugly but it works + int light_level; +#endif +} 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; + +// jkrige - configurable fps caps +extern cvar_t cl_maxfps; +// jkrige - configurable fps caps + +extern cvar_t cl_pitchdriftspeed; +extern cvar_t lookspring; +extern cvar_t lookstrafe; +extern cvar_t sensitivity; + +extern cvar_t crosshair; // jkrige - crosshair + +extern cvar_t cl_mlook; // jkrige - mlook cvar +extern cvar_t cl_slook; // jkrige - slook cvar + +extern cvar_t m_pitch; +extern cvar_t m_yaw; +extern cvar_t m_forward; +extern cvar_t m_side; + + +#define MAX_TEMP_ENTITIES 64 // lightning bolts, etc +#define MAX_STATIC_ENTITIES 128 // torches, etc + +extern client_state_t cl; + +// FIXME, allocate dynamically +extern efrag_t cl_efrags[MAX_EFRAGS]; +extern entity_t cl_entities[MAX_EDICTS]; +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]; + +//============================================================================= + +// +// 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); + +#define MAX_VISEDICTS 256 +extern int cl_numvisedicts; +extern entity_t *cl_visedicts[MAX_VISEDICTS]; + +// +// 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; // jkrige - mlook cvar, removed klook command +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); +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/engine/code/cmd.c b/engine/code/cmd.c new file mode 100644 index 0000000..7ca11ec --- /dev/null +++ b/engine/code/cmd.c @@ -0,0 +1,753 @@ +/* +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. + +*/ +// cmd.c -- Quake script command processing module + +#include "quakedef.h" + +void Cmd_ForwardToServer (void); + +#define MAX_ALIAS_NAME 32 + +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 + +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) +{ + int i, j; + int s; + char *text, *build, c; + + if (Cmd_Argc () != 1) + { + Con_Printf ("stuffcmds : execute command line parameters\n"); + return; + } + +// build the combined string to parse from + s = 0; + for (i=1 ; i : 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) + Con_Printf ("%s : %s\n", a->name, a->value); + return; + } + + 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); +} + +/* +============================================================================= + + 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; + + +static cmd_function_t *cmd_functions; // possible commands to execute + +// jkrige - cmdlist +/* +======== +Cmd_List +======== +*/ +void Cmd_List_f (void) +{ + cmd_function_t *cmd; + char *partial; + int len; + int count; + + if (Cmd_Argc() > 1) + { + partial = Cmd_Argv (1); + len = strlen(partial); + } + else + { + partial = NULL; + len = 0; + } + + count=0; + + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (partial && strncmp (partial,cmd->name, len)) + { + continue; + } + Con_Printf ("\"%s\"\n", cmd->name); + count++; + } + + Con_Printf ("%i command(s)", count); + + if (partial) + { + Con_Printf (" beginning with \"%s\"", partial); + } + Con_Printf ("\n"); +} +// jkrige - cmdlist + +/* +============ +Cmd_Init +============ +*/ +void Cmd_Init (void) +{ +// +// register our commands +// + 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_AddCommand ("cmdlist", Cmd_List_f); // jkrige - cmdlist + Cmd_AddCommand ("cvarlist", Cvar_List_f); // jkrige - cvarlist +} + +/* +============ +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; + cmd->next = cmd_functions; + cmd_functions = cmd; +} + +/* +============ +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/engine/code/cmd.h b/engine/code/cmd.h new file mode 100644 index 0000000..f9eab24 --- /dev/null +++ b/engine/code/cmd.h @@ -0,0 +1,121 @@ +/* +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. + +*/ + +// 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/engine/code/common.c b/engine/code/common.c new file mode 100644 index 0000000..9a097a8 --- /dev/null +++ b/engine/code/common.c @@ -0,0 +1,2226 @@ +/* +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. + +*/ +// common.c -- misc functions used in client and server + +#include "quakedef.h" + +// jkrige - scale2d +#ifdef _WIN32 +#include "winquake.h" +#endif +// jkrige - scale2d + + +#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","0", false, true}; + +qboolean com_modified; // set true if using non-id files + +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 +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; +} + + +// jkrige - scale2d +int Scale2DWidth; +int Scale2DHeight; +float Scale2DFactor; + +void COM_SetScale2D() +{ + float AspectRatio; + + AspectRatio = (float)modelist[(int)vid_mode.value].width / (float)modelist[(int)vid_mode.value].height; + Scale2DFactor = ceil((float)modelist[(int)vid_mode.value].height / (float)BASEHEIGHT); + + if (Scale2DFactor < 2.0f) + Scale2DFactor = 2.0f; + + Scale2DHeight = (float)modelist[(int)vid_mode.value].height / Scale2DFactor; + Scale2DWidth = (float)Scale2DHeight * AspectRatio; +} +// jkrige - scale2d + + +/* +============================================================================ + + 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); +} + +void MSG_WriteCoord (sizebuf_t *sb, float f) +{ + // jkrige - round to nearest value, rather than rounding toward zero + if (f >= 0) + MSG_WriteShort (sb, (int)(f * 8.0 + 0.5)); + else + MSG_WriteShort (sb, (int)(f * 8.0 - 0.5)); + + + //MSG_WriteShort (sb, (int)(f*8)); +} + +void MSG_WriteAngle (sizebuf_t *sb, float f) +{ + // jkrige - round to nearest value, rather than rounding toward zero + if (f >= 0) + MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255); + else + MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255); + + + //MSG_WriteByte (sb, ((int)f*256/360) & 255); +} + +// +// 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; +} + +float MSG_ReadCoord (void) +{ + return MSG_ReadShort() * (1.0/8); +} + +float MSG_ReadAngle (void) +{ + return MSG_ReadChar() * (360.0/256); +} + + + +//=========================================================================== + +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--; + + /* Pa3PyX: no range checking -- used to trash the stack and crash the + game randomly upon loading progs, for instance (or in any other + instance where one would supply a filename witout a path */ +// for (s2 = s ; *s2 && *s2 != '/' ; s2--); + for (s2 = s; *s2 && *s2 != '/' && s2 >= in; 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]; + + 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 + +Only used for CopyFile +============ +*/ +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); +} + +// jkrige - pk3 file support +qboolean LoadFromPK3; +// jkrige - pk3 file support + +/* +=========== +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"); + + LoadFromPK3 = false; // jkrige - pk3 file support + +// +// 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); + com_filesize = 0; + + if (handle) + { + *handle = pak->handle; + + // jkrige - pk3 file support + //Sys_FileSeek (pak->handle, pak->files[i].filepos); + if(pak->ident == ZPAKHEADER) + { + if(unzSetCurrentFileInfoPosition (pak->uzf, pak->files[i].filepos) == UNZ_OK) + { + if(unzOpenCurrentFile (pak->uzf) == UNZ_OK) + com_filesize = pak->files[i].filelen; + } + //unzLocateFile (pak->uzf, pak->files[i].name, 0); + + LoadFromPK3 = true; + } + else + { + Sys_FileSeek (pak->handle, pak->files[i].filepos); + com_filesize = pak->files[i].filelen; + } + // jkrige - pk3 file support + } + else + { + // open a new file on the pakfile + + // jkrige - pk3 file support + // *file = fopen (pak->filename, "rb"); + //if (*file) + // fseek (*file, pak->files[i].filepos, SEEK_SET); + if(pak->ident == ZPAKHEADER) + { + *file = pak->uzf; + + if(unzSetCurrentFileInfoPosition (pak->uzf, pak->files[i].filepos) == UNZ_OK) + { + if(unzOpenCurrentFile (pak->uzf) == UNZ_OK) + com_filesize = pak->files[i].filelen; + } + //unzLocateFile (pak->uzf, pak->files[i].name, 0); + + LoadFromPK3 = true; + } + else + { + *file = fopen (pak->filename, "rb"); + if (*file) + { + fseek (*file, pak->files[i].filepos, SEEK_SET); + com_filesize = pak->files[i].filelen; + } + } + // jkrige - pk3 file support + } + + 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); +} + + +// jkrige - pk3 file support +byte *COM_ReadFile (int handle, int len) +{ + byte *buf; + + buf = NULL; // quiet compiler warning + buf = malloc (len+1); + + if (!buf) + Sys_Error ("COM_ReadFile: not enough space."); + + ((byte *)buf)[len] = 0; + + Draw_BeginDisc (); + + if(LoadFromPK3 == true) + { + if (unzReadCurrentFile(sys_zhandles[handle], buf, len) < 1) + { + free(buf); + buf = NULL; + } + + if (unzCloseCurrentFile(sys_zhandles[handle]) != UNZ_OK) + { + free(buf); + buf = NULL; + } + + LoadFromPK3 = false; + } + else + { + int result; + + result = Sys_FileRead (handle, buf, len); + Sys_FileClose (handle); + + if (result = 0) + { + free(buf); + buf = NULL; + } + } + + Draw_EndDisc (); + + return buf; +} + +byte *COM_FReadFile (FILE *file, int len) +{ + byte *buf; + + buf = NULL; // quiet compiler warning + buf = malloc (len+1); + + if (!buf) + Sys_Error ("COM_FReadFile: not enough space."); + + ((byte *)buf)[len] = 0; + + Draw_BeginDisc (); + + if(LoadFromPK3 == true) + { + if (unzReadCurrentFile(file, buf, len) < 1) + { + free(buf); + buf = NULL; + } + + if (unzCloseCurrentFile(file) != UNZ_OK) + { + free(buf); + buf = NULL; + } + + LoadFromPK3 = false; + } + else + { + int result; + + result = Sys_FFileRead (file, buf, len); + Sys_FFileClose (file); + + if (result = 0) + { + free(buf); + buf = NULL; + } + } + + Draw_EndDisc (); + + return buf; +} +// jkrige - pk3 file support + + +/* +============ +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); + + Draw_EndDisc (); + + 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 + +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)); + + // jkrige - pk3 file support + //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); + if (LittleLong(header.ident) != IDPAKHEADER) + Sys_Error ("%s is not a packfile", packfile); + // jkrige - pk3 file support + + 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 + + newfiles = Hunk_AllocName (numpackfiles * sizeof(packfile_t), "packfile"); + + 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 ; iident = IDPAKHEADER; // jkrige - pk3 file support + 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; +} + +// jkrige - pk3 file support +pack_t *COM_LoadZPackFile (char *packfile) +{ + dzpackheader_t header; + int i; + packfile_t *newfiles; + pack_t *pack; + int packhandle; + //FILE *uf; + unzFile uf; + dpackfile_t info[MAX_FILES_IN_PACK]; + + int err; + unz_global_info gi; + unz_file_info file_info; + char filename_inzip[MAX_ZPATH]; + int len; + + unsigned long filepos; + + uf = unzOpen(packfile); + if(uf == NULL) + return NULL; + + packhandle = findhandle(true); + sys_zhandles[packhandle] = uf; + + err = unzGetGlobalInfo (uf, &gi); + + if (err != UNZ_OK) + return NULL; + + len = 0; + unzGoToFirstFile(uf); + for (i = 0; i < gi.number_entry; i++) + { + err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + if (err != UNZ_OK) { + break; + } + len += strlen(filename_inzip) + 1; + unzGoToNextFile(uf); + } + + newfiles = Hunk_AllocName (gi.number_entry * sizeof(packfile_t)+ len, "packfile"); + + unzGoToFirstFile(uf); + for (i = 0; i < gi.number_entry; i++) + { + err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + if (err != UNZ_OK) + break; + + //strlwr( filename_inzip ); + strcpy( newfiles[i].name, filename_inzip ); + + unzGetCurrentFileInfoPosition(uf, &filepos); + newfiles[i].filepos = filepos; + newfiles[i].filelen = file_info.uncompressed_size; + + unzGoToNextFile(uf); + } + + pack = Hunk_Alloc (sizeof (pack_t)); + pack->ident = ZPAKHEADER; + pack->uzf = uf; + strcpy (pack->filename, packfile); + pack->handle = packhandle; + pack->numfiles = gi.number_entry; + pack->files = newfiles; + + Con_Printf ("Added packfile %s (%i files)\n", packfile, pack->numfiles); + return pack; +} +// jkrige - pk3 file support + + +/* +================ +COM_AddGameDirectory + +Sets com_gamedir, adds the directory to the head of the path, +then loads and adds pak1.pak pak2.pak ... +================ +*/ +void COM_AddGameDirectory (char *dir) +{ + // jkrige - pack naming convention + //int i; + // jkrige - pack naming convention + + searchpath_t *search; + pack_t *pak; + char pakfile[MAX_OSPATH]; + + // jkrige - pack naming convention + char dirstring[1024]; + int handle; + struct _finddata_t fileinfo; + // jkrige - pack naming convention + + + strcpy (com_gamedir, dir); + +// +// add the directory to the search path +// + search = Hunk_Alloc (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, ... +// + // jkrige - pack naming convention + /*for (i=0 ; ; i++) + { + sprintf (pakfile, "%s/pak%i.pak", dir, i); + pak = COM_LoadPackFile (pakfile); + if (!pak) + break; + search = Hunk_Alloc (sizeof(searchpath_t)); + search->pack = pak; + search->next = com_searchpaths; + com_searchpaths = search; + }*/ + + + // we are going to add pak files first so they can be overridden by pk3 files + // we want pk3 to take presidence over pak + sprintf (dirstring, "%s/*.pak", dir); + handle = _findfirst (dirstring, &fileinfo); + if (handle != -1) + { + do + { + if (fileinfo.name[0] == '.') + continue; + + sprintf(pakfile,"%s/%s", dir, fileinfo.name); + pak = COM_LoadPackFile (pakfile); + + if (!pak) + break; + + search = Hunk_Alloc (sizeof(searchpath_t)); + search->pack = pak; + search->next = com_searchpaths; + com_searchpaths = search; + } + while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); + } + + + sprintf (dirstring, "%s/*.pk3", dir); + handle = _findfirst (dirstring, &fileinfo); + if (handle != -1) + { + do + { + if (fileinfo.name[0] == '.') + continue; + + sprintf(pakfile,"%s/%s", dir, fileinfo.name); + pak = COM_LoadZPackFile (pakfile); + + if (!pak) + break; + + search = Hunk_Alloc (sizeof(searchpath_t)); + search->pack = pak; + search->next = com_searchpaths; + com_searchpaths = search; + } + while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); + } + // jkrige - pack naming convention + +// +// add the contents of the parms.txt file to the end of the command line +// + +} + +/* +================ +COM_InitFilesystem +================ +*/ +void COM_InitFilesystem (void) +{ + int i, j; + char basedir[MAX_OSPATH]; + searchpath_t *search; + +// +// -basedir +// Overrides the system supplied base directory (under GAMENAME) +// + 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; + } + +// +// -cachedir +// Overrides the system supplied cache directory (NULL or /qcache) +// -cachedir - will disable caching. +// + 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) ); + + if (COM_CheckParm ("-rogue")) + COM_AddGameDirectory (va("%s/rogue", basedir) ); + if (COM_CheckParm ("-hipnotic")) + COM_AddGameDirectory (va("%s/hipnotic", basedir) ); + + // jkrige - added Dimension of the Past - begin + if (COM_CheckParm("-dopa")) + COM_AddGameDirectory(va("%s/dopa", basedir)); + // jkrige - added Dimension of the Past - end + +// +// -game +// Adds basedir/gamedir as an override game +// + i = COM_CheckParm ("-game"); + if (i && i < com_argc-1) + { + com_modified = true; + COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1])); + } + +// +// -path [] ... +// Fully specifies the exact serach path, overriding the generated one +// + 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 if ( !strcmp(COM_FileExtension(com_argv[i]), "pk3") ) // jkrige - pk3 file support + { + search->pack = COM_LoadZPackFile (com_argv[i]); + if (!search->pack) + Sys_Error ("Couldn't load packfile: %s", com_argv[i]); + } // jkrige - pk3 file support + else + strcpy (search->filename, com_argv[i]); + search->next = com_searchpaths; + com_searchpaths = search; + } + } + + if (COM_CheckParm ("-proghack")) + proghack = true; +} + + diff --git a/engine/code/common.h b/engine/code/common.h new file mode 100644 index 0000000..8a4b3c8 --- /dev/null +++ b/engine/code/common.h @@ -0,0 +1,198 @@ +/* +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. + +*/ +// 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); + +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); + +//============================================================================ + +// jkrige - scale2d +extern int Scale2DWidth; +extern int Scale2DHeight; +extern float Scale2DFactor; +extern void COM_SetScale2D(); +// jkrige - scale2d + +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); + + +// jkrige - pk3 file support +extern qboolean LoadFromPK3; +byte *COM_ReadFile (int handle, int len); +byte *COM_FReadFile (FILE *file, int len); +// jkrige - pk3 file support + + +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/engine/code/conproc.c b/engine/code/conproc.c new file mode 100644 index 0000000..43c20ca --- /dev/null +++ b/engine/code/conproc.c @@ -0,0 +1,365 @@ +/* +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. + +*/ +// conproc.c + +#include +#include "conproc.h" +#include "quakedef.h" + +HANDLE heventDone; +HANDLE hfileBuffer; +HANDLE heventChildSend; +HANDLE heventParentSend; +HANDLE hStdout; +HANDLE hStdin; + +DWORD RequestProc (DWORD dwNichts); +LPVOID GetMappedBuffer (HANDLE hfileBuffer); +void ReleaseMappedBuffer (LPVOID pBuffer); +BOOL GetScreenBufferLines (int *piLines); +BOOL SetScreenBufferLines (int iLines); +BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine); +BOOL WriteText (LPCTSTR szText); +int CharToCode (char c); +BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy); + + +void InitConProc (HANDLE hFile, HANDLE heventParent, HANDLE heventChild) +{ + DWORD dwID; + CONSOLE_SCREEN_BUFFER_INFO info; + int wheight, wwidth; + +// ignore if we don't have all the events. + if (!hFile || !heventParent || !heventChild) + return; + + hfileBuffer = hFile; + heventParentSend = heventParent; + heventChildSend = heventChild; + +// so we'll know when to go away. + heventDone = CreateEvent (NULL, FALSE, FALSE, NULL); + + if (!heventDone) + { + Con_SafePrintf ("Couldn't create heventDone\n"); + return; + } + + if (!CreateThread (NULL, + 0, + (LPTHREAD_START_ROUTINE) RequestProc, + 0, + 0, + &dwID)) + { + CloseHandle (heventDone); + Con_SafePrintf ("Couldn't create QHOST thread\n"); + return; + } + +// save off the input/output handles. + hStdout = GetStdHandle (STD_OUTPUT_HANDLE); + hStdin = GetStdHandle (STD_INPUT_HANDLE); + +// force 80 character width, at least 25 character height + SetConsoleCXCY (hStdout, 80, 25); +} + + +void DeinitConProc (void) +{ + if (heventDone) + SetEvent (heventDone); +} + + +DWORD RequestProc (DWORD dwNichts) +{ + int *pBuffer; + DWORD dwRet; + HANDLE heventWait[2]; + int iBeginLine, iEndLine; + + heventWait[0] = heventParentSend; + heventWait[1] = heventDone; + + while (1) + { + dwRet = WaitForMultipleObjects (2, heventWait, FALSE, INFINITE); + + // heventDone fired, so we're exiting. + if (dwRet == WAIT_OBJECT_0 + 1) + break; + + pBuffer = (int *) GetMappedBuffer (hfileBuffer); + + // hfileBuffer is invalid. Just leave. + if (!pBuffer) + { + Con_SafePrintf ("Invalid hfileBuffer\n"); + break; + } + + switch (pBuffer[0]) + { + case CCOM_WRITE_TEXT: + // Param1 : Text + pBuffer[0] = WriteText ((LPCTSTR) (pBuffer + 1)); + break; + + case CCOM_GET_TEXT: + // Param1 : Begin line + // Param2 : End line + iBeginLine = pBuffer[1]; + iEndLine = pBuffer[2]; + pBuffer[0] = ReadText ((LPTSTR) (pBuffer + 1), iBeginLine, + iEndLine); + break; + + case CCOM_GET_SCR_LINES: + // No params + pBuffer[0] = GetScreenBufferLines (&pBuffer[1]); + break; + + case CCOM_SET_SCR_LINES: + // Param1 : Number of lines + pBuffer[0] = SetScreenBufferLines (pBuffer[1]); + break; + } + + ReleaseMappedBuffer (pBuffer); + SetEvent (heventChildSend); + } + + return 0; +} + + +LPVOID GetMappedBuffer (HANDLE hfileBuffer) +{ + LPVOID pBuffer; + + pBuffer = MapViewOfFile (hfileBuffer, + FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + + return pBuffer; +} + + +void ReleaseMappedBuffer (LPVOID pBuffer) +{ + UnmapViewOfFile (pBuffer); +} + + +BOOL GetScreenBufferLines (int *piLines) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + BOOL bRet; + + bRet = GetConsoleScreenBufferInfo (hStdout, &info); + + if (bRet) + *piLines = info.dwSize.Y; + + return bRet; +} + + +BOOL SetScreenBufferLines (int iLines) +{ + + return SetConsoleCXCY (hStdout, 80, iLines); +} + + +BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine) +{ + COORD coord; + DWORD dwRead; + BOOL bRet; + + coord.X = 0; + coord.Y = iBeginLine; + + bRet = ReadConsoleOutputCharacter( + hStdout, + pszText, + 80 * (iEndLine - iBeginLine + 1), + coord, + &dwRead); + + // Make sure it's null terminated. + if (bRet) + pszText[dwRead] = '\0'; + + return bRet; +} + + +BOOL WriteText (LPCTSTR szText) +{ + DWORD dwWritten; + INPUT_RECORD rec; + char upper, *sz; + + sz = (LPTSTR) szText; + + while (*sz) + { + // 13 is the code for a carriage return (\n) instead of 10. + if (*sz == 10) + *sz = 13; + + upper = toupper(*sz); + + rec.EventType = KEY_EVENT; + rec.Event.KeyEvent.bKeyDown = TRUE; + rec.Event.KeyEvent.wRepeatCount = 1; + rec.Event.KeyEvent.wVirtualKeyCode = upper; + rec.Event.KeyEvent.wVirtualScanCode = CharToCode (*sz); + rec.Event.KeyEvent.uChar.AsciiChar = *sz; + rec.Event.KeyEvent.uChar.UnicodeChar = *sz; + rec.Event.KeyEvent.dwControlKeyState = isupper(*sz) ? 0x80 : 0x0; + + WriteConsoleInput( + hStdin, + &rec, + 1, + &dwWritten); + + rec.Event.KeyEvent.bKeyDown = FALSE; + + WriteConsoleInput( + hStdin, + &rec, + 1, + &dwWritten); + + sz++; + } + + return TRUE; +} + + +int CharToCode (char c) +{ + char upper; + + upper = toupper(c); + + switch (c) + { + case 13: + return 28; + + default: + break; + } + + if (isalpha(c)) + return (30 + upper - 65); + + if (isdigit(c)) + return (1 + upper - 47); + + return c; +} + + +BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + COORD coordMax; + + coordMax = GetLargestConsoleWindowSize(hStdout); + + if (cy > coordMax.Y) + cy = coordMax.Y; + + if (cx > coordMax.X) + cx = coordMax.X; + + if (!GetConsoleScreenBufferInfo(hStdout, &info)) + return FALSE; + +// height + info.srWindow.Left = 0; + info.srWindow.Right = info.dwSize.X - 1; + info.srWindow.Top = 0; + info.srWindow.Bottom = cy - 1; + + if (cy < info.dwSize.Y) + { + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + return FALSE; + + info.dwSize.Y = cy; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return FALSE; + } + else if (cy > info.dwSize.Y) + { + info.dwSize.Y = cy; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return FALSE; + + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + return FALSE; + } + + if (!GetConsoleScreenBufferInfo(hStdout, &info)) + return FALSE; + +// width + info.srWindow.Left = 0; + info.srWindow.Right = cx - 1; + info.srWindow.Top = 0; + info.srWindow.Bottom = info.dwSize.Y - 1; + + if (cx < info.dwSize.X) + { + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + return FALSE; + + info.dwSize.X = cx; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return FALSE; + } + else if (cx > info.dwSize.X) + { + info.dwSize.X = cx; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + return FALSE; + + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + return FALSE; + } + + return TRUE; +} + diff --git a/engine/code/conproc.h b/engine/code/conproc.h new file mode 100644 index 0000000..743526f --- /dev/null +++ b/engine/code/conproc.h @@ -0,0 +1,37 @@ +/* +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. + +*/ +// conproc.h + +#define CCOM_WRITE_TEXT 0x2 +// Param1 : Text + +#define CCOM_GET_TEXT 0x3 +// Param1 : Begin line +// Param2 : End line + +#define CCOM_GET_SCR_LINES 0x4 +// No params + +#define CCOM_SET_SCR_LINES 0x5 +// Param1 : Number of lines + +void InitConProc (HANDLE hFile, HANDLE heventParent, HANDLE heventChild); +void DeinitConProc (void); + diff --git a/engine/code/console.c b/engine/code/console.c new file mode 100644 index 0000000..68df650 --- /dev/null +++ b/engine/code/console.c @@ -0,0 +1,671 @@ +/* +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. + +*/ +// console.c + +#ifdef NeXT +#include +#endif +#ifndef _MSC_VER +#include +#endif +#include +#include "quakedef.h" + +// jkrige - scale2d +#ifdef _WIN32 +#include "winquake.h" +#endif +// jkrige - scale2d + +int con_linewidth; + +float con_cursorspeed = 4; + +#define CON_TEXTSIZE 16384 + +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 + +#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; + +int con_notifylines; // scan lines to clear for notify lines + +extern void M_Menu_Main_f (void); + +/* +================ +Con_ToggleConsole_f +================ +*/ +void Con_ToggleConsole_f (void) +{ + if (key_dest == key_console) + { + if (cls.state == ca_connected) + { + key_dest = key_game; + key_lines[edit_line][1] = 0; // clear any typing + key_linepos = 1; + } + else + { + M_Menu_Main_f (); + } + } + else + 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_TEXTSIZE); +} + + +/* +================ +Con_ClearNotify +================ +*/ +void Con_ClearNotify (void) +{ + int i; + + for (i=0 ; i 1.0f) + { + vid.width = vid.conwidth = conback->width = Scale2DWidth; + vid.height = vid.conheight = conback->height = Scale2DHeight; + } + else + { + vid.width = vid.conwidth = conback->width = modelist[(int)vid_mode.value].width; + vid.height = vid.conheight = conback->height = modelist[(int)vid_mode.value].height; + } +#endif + // jkrige - scale2d + + + width = (vid.width >> 3) - 2; + + if (width == con_linewidth) + return; + + if (width < 1) // video hasn't been initialized yet + { + width = 38; + con_linewidth = width; + con_totallines = CON_TEXTSIZE / con_linewidth; + Q_memset (con_text, ' ', CON_TEXTSIZE); + } + else + { + oldwidth = con_linewidth; + con_linewidth = width; + oldtotallines = con_totallines; + con_totallines = CON_TEXTSIZE / con_linewidth; + numlines = oldtotallines; + + if (con_totallines < numlines) + numlines = con_totallines; + + numchars = oldwidth; + + if (con_linewidth < numchars) + numchars = con_linewidth; + + Q_memcpy (tbuf, con_text, CON_TEXTSIZE); + Q_memset (con_text, ' ', CON_TEXTSIZE); + + for (i=0 ; i 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); // also echo to debugging console + +// 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_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_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; +} + + +/* +============================================================================== + +DRAWING + +============================================================================== +*/ + + +/* +================ +Con_DrawInput + +The input line scrolls horizontally if typing goes beyond the right edge +================ +*/ +void Con_DrawInput (void) +{ + int y; + int i; + char *text; + + if (key_dest != key_console && !con_forcedup) + return; // don't draw anything + + text = key_lines[edit_line]; + +// add the cursor frame + text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1); + +// fill out remainder with spaces + for (i=key_linepos+1 ; i< con_linewidth ; i++) + text[i] = ' '; + +// prestep if horizontally scrolling + if (key_linepos >= con_linewidth) + text += 1 + key_linepos - con_linewidth; + +// draw it + y = con_vislines-16; + + for (i=0 ; i con_notifytime.value) + continue; + text = con_text + (i % con_totallines)*con_linewidth; + + clearnotify = 0; + scr_copytop = 1; + + for (x = 0 ; x < con_linewidth ; x++) + Draw_Character ( (x+1)<<3, v, text[x]); + + v += 8; + } + + + if (key_dest == key_message) + { + clearnotify = 0; + scr_copytop = 1; + + x = 0; + + Draw_String (8, v, "say:"); + while(chat_buffer[x]) + { + Draw_Character ( (x+5)<<3, v, chat_buffer[x]); + x++; + } + Draw_Character ( (x+5)<<3, v, 10+((int)(realtime*con_cursorspeed)&1)); + v += 8; + } + + if (v > con_notifylines) + con_notifylines = v; +} + +/* +================ +Con_DrawConsole + +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; + int rows; + char *text; + int j; + + if (lines <= 0) + return; + +// draw the background + Draw_ConsoleBackground (lines); + +// draw the text + con_vislines = lines; + + rows = (lines-16)>>3; // rows of text to draw + y = lines - 16 - (rows<<3); // may start slightly negative + + for (i= con_current - rows + 1 ; i<=con_current ; 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; +} \ No newline at end of file diff --git a/engine/code/crc.h b/engine/code/crc.h new file mode 100644 index 0000000..cad9772 --- /dev/null +++ b/engine/code/crc.h @@ -0,0 +1,24 @@ +/* +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. + +*/ +/* crc.h */ + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); diff --git a/engine/code/cvar.c b/engine/code/cvar.c new file mode 100644 index 0000000..4145b7d --- /dev/null +++ b/engine/code/cvar.c @@ -0,0 +1,289 @@ +/* +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. + +*/ +// cvar.c -- dynamic variable tracking + +#include "quakedef.h" + +cvar_t *cvar_vars; +char *cvar_null_string = ""; + +// jkrige - cvarlist +/* +========= +Cvar_List +========= +*/ + +void Cvar_List_f (void) +{ + cvar_t *cvar; + char *partial; + int len; + int count; + + if (Cmd_Argc() > 1) + { + partial = Cmd_Argv (1); + len = strlen(partial); + } + else + { + partial = NULL; + len = 0; + } + + count=0; + + for (cvar=cvar_vars ; cvar ; cvar=cvar->next) + { + if (partial && strncmp (partial,cvar->name, len)) + { + continue; + } + + Con_Printf ("\"%s\" is \"%s\"\n", cvar->name, cvar->string); + + count++; + } + + Con_Printf ("%i cvar(s)", count); + + if (partial) + { + Con_Printf (" beginning with \"%s\"", partial); + } + + Con_Printf ("\n"); +} +// jkrige - cvarlist + +/* +============ +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_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); + if (var->server && changed) + { + if (sv.active) + SV_BroadcastPrintf ("\"%s\" changed to \"%s\"\n", var->name, var->string); + } + + // jkrige - deathmatch/coop not at the same time fix + if ( (var->value != 0) && (!Q_strcmp (var->name, deathmatch.name)) ) + Cvar_Set ("coop", "0"); + + if ( (var->value != 0) && (!Q_strcmp (var->name, coop.name)) ) + Cvar_Set ("deathmatch", "0"); + // jkrige - deathmatch/coop not at the same time fix +} + +/* +============ +Cvar_SetValue +============ +*/ +void Cvar_SetValue (char *var_name, float value) +{ + char val[32]; + + // jkrige - cvar zeros fix + //sprintf (val, "%f",value); + if (value == (int)value) + sprintf (val, "%d", (int)value); + else + sprintf (val, "%f",value); + // jkrige - cvar zeros fix + + Cvar_Set (var_name, val); +} + + +/* +============ +Cvar_RegisterVariable + +Adds a freestanding variable to the variable list. +============ +*/ +void Cvar_RegisterVariable (cvar_t *variable) +{ + char *oldstr; + +// 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); + +// link the variable in + variable->next = cvar_vars; + cvar_vars = variable; +} + +/* +============ +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/engine/code/cvar.h b/engine/code/cvar.h new file mode 100644 index 0000000..5b84761 --- /dev/null +++ b/engine/code/cvar.h @@ -0,0 +1,99 @@ +/* +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. + +*/ +// 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; +} cvar_t; + +void Cvar_RegisterVariable (cvar_t *variable); +// 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); + +void Cvar_List_f (void); // jkrige - cvarlist + +extern cvar_t *cvar_vars; diff --git a/engine/code/draw.h b/engine/code/draw.h new file mode 100644 index 0000000..41454ff --- /dev/null +++ b/engine/code/draw.h @@ -0,0 +1,55 @@ +/* +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. + +*/ + +// 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 + +// jkrige - external texture loading +extern int image_width; +extern int image_height; +extern int image_bits; +extern int image_alpha; +// jkrige - external texture loading + +// jkrige - .lit colored lights +extern vec3_t lightcolor; // jkrige - used by model rendering +// jkrige - .lit colored lights + +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_TransPic (int x, int y, qpic_t *pic); +void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation); +void Draw_ConsoleBackground (int lines); +void Draw_BeginDisc (void); +void Draw_EndDisc (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); +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); + +// jkrige - external texture loading +byte* LoadImagePixels (char* filename, qboolean complain); +// jkrige - external texture loading \ No newline at end of file diff --git a/engine/code/gl_draw.c b/engine/code/gl_draw.c new file mode 100644 index 0000000..379c559 --- /dev/null +++ b/engine/code/gl_draw.c @@ -0,0 +1,2466 @@ +/* +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. + +*/ + +// draw.c -- this is the only file outside the refresh that touches the +// vid buffer + +#include "quakedef.h" + +// jkrige - scale2d +#ifdef _WIN32 +#include "winquake.h" +#endif +// jkrige - scale2d + +// jkrige - jpg +#include "../jpeg-6/jpeglib.h" +byte *jpeg_rgba; +// jkrige - jpg + +//#define GL_COLOR_INDEX8_EXT 0x80E5 + +extern unsigned char d_15to8table[65536]; + +cvar_t gl_nobind = {"gl_nobind", "0"}; +cvar_t gl_max_size = {"gl_max_size", "1024"}; +cvar_t gl_picmip = {"gl_picmip", "0"}; + +// jkrige - luma textures +cvar_t gl_lumatex_render = {"gl_lumatex_render", "1", true}; +// jkrige - luma textures + +byte *draw_chars; // 8*8 graphic characters +qpic_t *draw_disc; +qpic_t *draw_backtile; + +int translate_texture; +int char_texture; + +typedef struct +{ + int texnum; + float sl, tl, sh, th; +} glpic_t; + +byte conback_buffer[sizeof(qpic_t) + sizeof(glpic_t)]; +qpic_t *conback = (qpic_t *)&conback_buffer; + +// jkrige - .lit colored lights +//int gl_lightmap_format = 4; +// jkrige - .lit colored lights +int gl_solid_format = 3; +int gl_alpha_format = 4; + +// jkrige - change bilinear texture filtering to trilinear texture filtering +//int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; +//int gl_filter_max = GL_LINEAR; +int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; +int gl_filter_max = GL_LINEAR_MIPMAP_LINEAR; +// jkrige - change bilinear texture filtering to trilinear texture filtering + +float tex_mode = -1.0f; + +int texels; + +// jkrige - moved to glquake.h +/*typedef struct +{ + int texnum; + + qboolean tex_luma; // jkrige - luma textures + + char identifier[64]; + int width, height; + qboolean mipmap; +} gltexture_t; + +#define MAX_GLTEXTURES 1024*/ +// jkrige - moved to glquake.h + +gltexture_t gltextures[MAX_GLTEXTURES]; +int numgltextures; + + +void GL_Bind (int texnum) +{ + if (gl_nobind.value) + texnum = char_texture; + if (currenttexture == texnum) + return; + currenttexture = texnum; + +// jkrige - opengl's bind function +//#ifdef _WIN32 +// bindTexFunc (GL_TEXTURE_2D, texnum); +//#else + glBindTexture(GL_TEXTURE_2D, texnum); +//#endif +// jkrige - opengl's bind function + +} + + +/* +============================================================================= + + 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*4]; +qboolean scrap_dirty; +int scrap_texnum; + +// returns a texture number and the position inside it +int Scrap_AllocBlock (int w, int h, int *x, int *y) +{ + int i, j; + int best, best2; + int bestx; + 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]; + texnum += scrap_texnum; + gl->texnum = texnum; + gl->sl = (x+0.01)/(float)BLOCK_WIDTH; + gl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH; + gl->tl = (y+0.01)/(float)BLOCK_WIDTH; + gl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH; + + pic_count++; + pic_texels += p->width*p->height; + } + else + { + gl->texnum = GL_LoadPicTexture (p); + gl->sl = 0; + gl->sh = 1; + gl->tl = 0; + gl->th = 1; + } + + 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->texnum = GL_LoadPicTexture (dat); + gl->sl = 0; + gl->sh = 1; + gl->tl = 0; + gl->th = 1; + + return &pic->pic; +} + + +/*void Draw_CharToConback (int num, byte *dest) +{ + int row, col; + byte *source; + int drawline; + int x; + + row = num>>4; + col = num&15; + source = draw_chars + (row<<10) + (col<<3); + + drawline = 8; + + while (drawline--) + { + for (x=0 ; x<8 ; x++) + if (source[x] != 255) + dest[x] = 0x60 + source[x]; + source += 128; + dest += 320; + } + +}*/ + +typedef struct +{ + char *name; + int minimize, maximize; +} glmode_t; + +glmode_t modes[] = { + {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, + {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, + {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, + {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, + {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, + {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} +}; + +/* +=============== +Draw_TextureMode_f +=============== +*/ +/*void Draw_TextureMode_f (void) +{ + int i; + gltexture_t *glt; + + if (Cmd_Argc() == 1) + { + for (i=0 ; i< 6 ; i++) + if (gl_filter_min == modes[i].minimize) + { + Con_Printf ("%s\n", modes[i].name); + return; + } + Con_Printf ("current filter is unknown???\n"); + return; + } + + for (i=0 ; i< 6 ; i++) + { + if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) ) + break; + } + if (i == 6) + { + Con_Printf ("bad filter name\n"); + return; + } + + gl_filter_min = modes[i].minimize; + gl_filter_max = modes[i].maximize; + + // change all the existing mipmap texture objects + for (i=0, glt=gltextures ; imipmap) + { + GL_Bind (glt->texnum); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } + } +}*/ + +// jkrige - texture mode +extern int solidskytexture; +extern int alphaskytexture; + +void Draw_TextureMode_f (void) +{ + int i, j; + gltexture_t *glt; + int AnisotropyModes = 0; + + if(tex_mode < 0.0f) + tex_mode = gl_texturemode.value; + + if(tex_mode == gl_texturemode.value) + return; + + if(floor(gl_texturemode.value) < 0.0f | gl_texturemode.value != floor(gl_texturemode.value)) + { + Con_Printf ("unknown texture mode\n"); + Cvar_Set ("gl_texturemode", "2"); + + return; + } + + i = 0; + + if(gl_texturemode.value == 1.0f) + i = 3; + + if(gl_texturemode.value >= 2.0f) + i = 5; + + if(anisotropic_ext == true) + AnisotropyModes = (int)floor((log(maximumAnisotrophy)/log(2.0f)) + 0.5f); + else + AnisotropyModes = 0; + + if(anisotropic_ext == false) + { + if (gl_texturemode.value > 2.0f) + { + Con_Printf ("unknown texture mode\n"); + Cvar_Set ("gl_texturemode", "2"); + + return; + } + } + + if(anisotropic_ext == true) + { + if (gl_texturemode.value > (2.0f + (float)AnisotropyModes)) + { + Con_Printf ("unknown texture mode\n"); + Cvar_SetValue ("gl_texturemode", (2.0f + (float)AnisotropyModes)); + + return; + } + } + + gl_filter_min = modes[i].minimize; + gl_filter_max = modes[i].maximize; + + // change all the existing mipmap texture objects + for (j=0, glt=gltextures ; jmipmap) + { + GL_Bind (glt->texnum); + + if(gl_texturemode.value <= 2.0f) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + if(anisotropic_ext == true) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); + } + + // jkrige - anisotropic filtering + if(gl_texturemode.value > 2.0f && anisotropic_ext == true) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, pow(2.0f, gl_texturemode.value - 2.0f)); + // jkrige - anisotropic filtering + + + // jkrige - luma textures + if(glt->tex_luma == true) + { + GL_Bind (JK_LUMA_TEX + glt->texnum); + + if(gl_texturemode.value <= 2.0f) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + if(anisotropic_ext == true) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); + } + + // jkrige - anisotropic filtering + if(gl_texturemode.value > 2.0f && anisotropic_ext == true) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, pow(2.0f, gl_texturemode.value - 2.0f)); + // jkrige - anisotropic filtering + } + // jkrige - luma textures + } + } + + + // sky textures + if(gl_texturemode.value == 0.0f) + { + GL_Bind (solidskytexture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + GL_Bind (alphaskytexture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else + { + GL_Bind (solidskytexture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + GL_Bind (alphaskytexture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + // sky textures + + + tex_mode = gl_texturemode.value; +} +// jkrige - texture mode + +/* +=============== +Draw_Init +=============== +*/ +void Draw_Init (void) +{ + int i; + qpic_t *cb; + byte *dest, *src; + int x, y; + char ver[40]; + glpic_t *gl; + int start; + byte *ncdata; + int f, fstep; + + + Cvar_RegisterVariable (&gl_nobind); + Cvar_RegisterVariable (&gl_max_size); + Cvar_RegisterVariable (&gl_picmip); + + // jkrige - luma textures + Cvar_RegisterVariable (&gl_lumatex_render); + // jkrige - luma textures + + + // 3dfx can only handle 256 wide textures + if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) || strstr((char *)gl_renderer, "Glide")) + Cvar_Set ("gl_max_size", "256"); + + //Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f); // jkrige - texture mode + + // load the console background and the charset + // by hand, because we need to write the version + // string into the background before turning + // it into a texture + draw_chars = W_GetLumpName ("conchars"); + for (i=0 ; i<256*64 ; i++) + if (draw_chars[i] == 0) + draw_chars[i] = 255; // proper transparent color + + // now turn them into textures + + + // jkrige - external texture loading + //char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true); + char_texture = GL_LoadTexture ("charset", "lump", 128, 128, draw_chars, false, true, 1); + // jkrige - external texture loading + + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + start = Hunk_LowMark(); + + cb = (qpic_t *)COM_LoadTempFile ("gfx/conback.lmp"); + if (!cb) + Sys_Error ("Couldn't load gfx/conback.lmp"); + SwapPic (cb); + + // jkrige - print version info to the console + // hack the version number directly into the pic +/*#if defined(__linux__) + sprintf (ver, "(Linux %2.2f, gl %4.2f) %4.2f", (float)LINUX_VERSION, (float)GLQUAKE_VERSION, (float)VERSION); +#else + sprintf (ver, "(gl %4.2f) %4.2f", (float)GLQUAKE_VERSION, (float)VERSION); +#endif + dest = cb->data + 320*186 + 320 - 11 - 8*strlen(ver); + y = strlen(ver); + for (x=0 ; xwidth = vid.conwidth; + conback->height = vid.conheight; + + // scale console to vid size + dest = ncdata = Hunk_AllocName(vid.conwidth * vid.conheight, "conback"); + + for (y=0 ; ydata + cb->width * (y*cb->height/vid.conheight); + if (vid.conwidth == cb->width) + memcpy (dest, src, vid.conwidth); + else + { + f = 0; + fstep = cb->width*0x10000/vid.conwidth; + for (x=0 ; x>16]; + f += fstep; + dest[x+1] = src[f>>16]; + f += fstep; + dest[x+2] = src[f>>16]; + f += fstep; + dest[x+3] = src[f>>16]; + f += fstep; + } + } + } +#else + conback->width = cb->width; + conback->height = cb->height; + ncdata = cb->data; +#endif + + gl = (glpic_t *)conback->data; + + // jkrige - external texture loading + //gl->texnum = GL_LoadTexture ("conback", conback->width, conback->height, ncdata, false, false); + gl->texnum = GL_LoadTexture ("conback", "lump", conback->width, conback->height, ncdata, false, false, 1); + // jkrige - external texture loading + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl->sl = 0; + gl->sh = 1; + gl->tl = 0; + gl->th = 1; + conback->width = vid.width; + conback->height = vid.height; + + // free loaded console + Hunk_FreeToLowMark(start); + + // save a texture slot for translated picture + translate_texture = texture_extension_number++; + + // save slots for scraps + scrap_texnum = texture_extension_number; + texture_extension_number += MAX_SCRAPS; + + // + // get the other pics we need + // + draw_disc = Draw_PicFromWad ("disc"); + draw_backtile = Draw_PicFromWad ("backtile"); +} + + + +/* +================ +Draw_Character + +Draws one 8*8 graphics character with 0 being transparent. +It can be clipped to the top of the screen to allow the console to be +smoothly scrolled off. +================ +*/ +void Draw_Character (int x, int y, int num) +{ + byte *dest; + byte *source; + unsigned short *pusdest; + int drawline; + int row, col; + float frow, fcol, size; + + if (num == 32) + return; // space + + num &= 255; + + if (y <= -8) + return; // totally off screen + + row = num>>4; + col = num&15; + + frow = row*0.0625; + fcol = col*0.0625; + size = 0.0625; + + GL_Bind (char_texture); + + glBegin (GL_QUADS); + 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); + glEnd (); +} + +/* +================ +Draw_String +================ +*/ +void Draw_String (int x, int y, char *str) +{ + while (*str) + { + Draw_Character (x, y, *str); + str++; + x += 8; + } +} + +/* +================ +Draw_DebugChar + +Draws a single character directly to the upper right corner of the screen. +This is for debugging lockups by drawing different chars in different parts +of the code. +================ +*/ +void Draw_DebugChar (char num) +{ +} + +/* +============= +Draw_AlphaPic +============= +*/ +void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha) +{ + byte *dest, *source; + unsigned short *pusdest; + int v, u; + glpic_t *gl; + + if (scrap_dirty) + Scrap_Upload (); + gl = (glpic_t *)pic->data; + glDisable(GL_ALPHA_TEST); + glEnable (GL_BLEND); +// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +// glCullFace(GL_FRONT); + glColor4f (1,1,1,alpha); + GL_Bind (gl->texnum); + 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 (); + glColor4f (1,1,1,1); + glEnable(GL_ALPHA_TEST); + glDisable (GL_BLEND); +} + + +/* +============= +Draw_Pic +============= +*/ +void Draw_Pic (int x, int y, qpic_t *pic) +{ + byte *dest, *source; + unsigned short *pusdest; + int v, u; + glpic_t *gl; + + if (scrap_dirty) + Scrap_Upload (); + gl = (glpic_t *)pic->data; + glColor4f (1,1,1,1); + GL_Bind (gl->texnum); + 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_TransPic +============= +*/ +void Draw_TransPic (int x, int y, qpic_t *pic) +{ + byte *dest, *source, tbyte; + unsigned short *pusdest; + int v, u; + + if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 || (unsigned)(y + pic->height) > vid.height) + { + Sys_Error ("Draw_TransPic: bad coordinates"); + } + + Draw_Pic (x, y, pic); +} + + +/* +============= +Draw_TransPicTranslate + +Only used for the player color selection menu +============= +*/ +void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation) +{ + int v, u, c; + unsigned trans[64*64], *dest; + byte *src; + int p; + + GL_Bind (translate_texture); + + c = pic->width * pic->height; + + dest = trans; + for (v=0 ; v<64 ; v++, dest += 64) + { + src = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width]; + for (u=0 ; u<64 ; u++) + { + p = src[(u*pic->width)>>6]; + if (p == 255) + dest[u] = p; + else + dest[u] = d_8to24table[translation[p]]; + } + } + + glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans); + + // jkrige - use "point sampled" texture mode + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // jkrige - use "point sampled" texture mode + + glColor3f (1,1,1); + glBegin (GL_QUADS); + glTexCoord2f (0, 0); + glVertex2f (x, y); + glTexCoord2f (1, 0); + glVertex2f (x+pic->width, y); + glTexCoord2f (1, 1); + glVertex2f (x+pic->width, y+pic->height); + glTexCoord2f (0, 1); + glVertex2f (x, y+pic->height); + glEnd (); +} + +// jkrige - print version info to the console +void Console_Print (int cx, int cy, char *str) +{ + while (*str) + { + Draw_Character (cx, cy, ((unsigned char)(*str))+256); + str++; + cx += 8; + } +} +// jkrige - print version info to the console + +/* +================ +Draw_ConsoleBackground + +================ +*/ +void Draw_ConsoleBackground (int lines) +{ + // jkrige - removed alpha console background + //int y = (vid.height * 3) >> 2; + // jkrige - removed alpha console background + + + // jkrige - print version info to the console + int ver_x, ver_y; + char engineversion[32]; + sprintf(engineversion, "UQE Quake %.2f", QUAKE_VERSION); + ver_x = (int)vid.width - (strlen(engineversion)*8) /*- 8*/; + ver_y = (int)vid.height - 8; //- 16; + // jkrige - print version info to the console + + + // jkrige - removed alpha console background + //if (lines > y) + // Draw_Pic(0, lines - vid.height, conback); + //else + // Draw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y); + Draw_Pic(0, lines - vid.height, conback); + // jkrige - removed alpha console background + + + // jkrige - print version info to the console + Console_Print(ver_x, lines - (int)vid.height + ver_y, engineversion); + // jkrige - print version info to the console +} + + +/* +============= +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) +{ + glColor3f (1,1,1); + GL_Bind (*(int *)draw_backtile->data); + 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) +{ + glDisable (GL_TEXTURE_2D); + glColor3f (host_basepal[c*3]/255.0, + host_basepal[c*3+1]/255.0, + host_basepal[c*3+2]/255.0); + + glBegin (GL_QUADS); + + glVertex2f (x,y); + glVertex2f (x+w, y); + glVertex2f (x+w, y+h); + glVertex2f (x, y+h); + + glEnd (); + glColor3f (1,1,1); + glEnable (GL_TEXTURE_2D); +} +//============================================================================= + +/* +================ +Draw_FadeScreen + +================ +*/ +void Draw_FadeScreen (void) +{ + glEnable (GL_BLEND); + glDisable (GL_TEXTURE_2D); + glColor4f (0, 0, 0, 0.8); + glBegin (GL_QUADS); + + glVertex2f (0,0); + glVertex2f (vid.width, 0); + glVertex2f (vid.width, vid.height); + glVertex2f (0, vid.height); + + glEnd (); + glColor4f (1,1,1,1); + glEnable (GL_TEXTURE_2D); + glDisable (GL_BLEND); + + //Sbar_Changed(); // jkrige - always draw sbar +} + +//============================================================================= + +/* +================ +Draw_BeginDisc + +Draws the little blue disc in the corner of the screen. +Call before beginning any disc IO. +================ +*/ +void Draw_BeginDisc (void) +{ + if (!draw_disc) + return; + glDrawBuffer (GL_FRONT); + Draw_Pic (vid.width - 24, 0, draw_disc); + glDrawBuffer (GL_BACK); +} + + +/* +================ +Draw_EndDisc + +Erases the disc icon. +Call after completing any disc IO +================ +*/ +void Draw_EndDisc (void) +{ +} + +/* +================ +GL_Set2D + +Setup as if the screen was 320*200 +================ +*/ +void GL_Set2D (void) +{ + glViewport (glx, gly, glwidth, glheight); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity (); + glOrtho (0, vid.width, vid.height, 0, -99999, 99999); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity (); + + glDisable (GL_DEPTH_TEST); + glDisable (GL_CULL_FACE); + glDisable (GL_BLEND); + glEnable (GL_ALPHA_TEST); +// glDisable (GL_ALPHA_TEST); + + glColor4f (1,1,1,1); +} + +//==================================================================== + +/* +================ +GL_FindTexture +================ +*/ +int GL_FindTexture (char *identifier) +{ + int i; + gltexture_t *glt; + + for (i=0, glt=gltextures ; iidentifier)) + return gltextures[i].texnum; + } + + return -1; +} + +/* +================ +GL_ResampleTexture +================ +*/ +void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight) +{ + int i, j; + unsigned *inrow; + unsigned frac, fracstep; + + fracstep = inwidth*0x10000/outwidth; + for (i=0 ; i> 1; + for (j=0 ; j>16]; + frac += fracstep; + out[j+1] = inrow[frac>>16]; + frac += fracstep; + out[j+2] = inrow[frac>>16]; + frac += fracstep; + out[j+3] = inrow[frac>>16]; + frac += fracstep; + } + } +} + +/* +================ +GL_Resample8BitTexture -- JACK +================ +*/ +void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out, int outwidth, int outheight) +{ + int i, j; + unsigned char *inrow; + unsigned frac, fracstep; + + fracstep = inwidth*0x10000/outwidth; + for (i=0 ; i> 1; + for (j=0 ; j>16]; + frac += fracstep; + out[j+1] = inrow[frac>>16]; + frac += fracstep; + out[j+2] = inrow[frac>>16]; + frac += fracstep; + out[j+3] = inrow[frac>>16]; + frac += fracstep; + } + } +} + + +/* +================ +GL_MipMap + +Operates in place, quartering the size of the texture +================ +*/ +void GL_MipMap (byte *in, int width, int height) +{ + int i, j; + byte *out; + + width <<=2; + height >>= 1; + out = in; + for (i=0 ; i>2; + out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2; + out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2; + out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2; + } + } +} + +/* +================ +GL_MipMap8Bit + +Mipping for 8 bit textures +================ +*/ +void GL_MipMap8Bit (byte *in, int width, int height) +{ + int i, j; + unsigned short r,g,b; + byte *out, *at1, *at2, *at3, *at4; + +// width <<=2; + height >>= 1; + out = in; + for (i=0 ; i>=5; + g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5; + b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5; + + out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)]; + } + } +} + +/* +=============== +GL_Upload32 +=============== +*/ +void GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap, qboolean alpha) +{ + int samples; + + // jkrige - doubled textures + //static unsigned scaled[1024 * 512]; // [512*256]; + static unsigned scaled[2048 * 2048]; + // jkrige - doubled textures + + int scaled_width, scaled_height; + + // jkrige - anisotropic filtering + int i = 3; + int AnisotropyModes = 0; + // jkrige - anisotropic filtering + + // jkrige - non power of two + //for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1); + //for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1); + if(npow2_ext == true && gl_texture_non_power_of_two.value == 1.0f /*&& !mipmap*/) + { + scaled_width = width; + scaled_height = height; + } + else + { + for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1); + for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1); + } + // jkrige - non power of two + + if ((scaled_width >> (int)gl_picmip.value) && (scaled_height >> (int)gl_picmip.value)) + { + scaled_width >>= (int)gl_picmip.value; + scaled_height >>= (int)gl_picmip.value; + } + //scaled_width >>= (int)gl_picmip.value; + //scaled_height >>= (int)gl_picmip.value; + + if (scaled_width > gl_max_size.value) + scaled_width = gl_max_size.value; + + if (scaled_height > gl_max_size.value) + scaled_height = gl_max_size.value; + + if (scaled_width * scaled_height > sizeof(scaled)/4) + Sys_Error ("GL_LoadTexture: too big"); + + samples = alpha ? gl_alpha_format : gl_solid_format; + +#if 0 + if (mipmap) + gluBuild2DMipmaps (GL_TEXTURE_2D, samples, width, height, GL_RGBA, GL_UNSIGNED_BYTE, trans); + else if (scaled_width == width && scaled_height == height) + glTexImage2D (GL_TEXTURE_2D, 0, samples, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans); + else + { + gluScaleImage (GL_RGBA, width, height, GL_UNSIGNED_BYTE, trans, + scaled_width, scaled_height, GL_UNSIGNED_BYTE, scaled); + glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); + } +#else +texels += scaled_width * scaled_height; + + if (scaled_width == width && scaled_height == height) + { + if (!mipmap) + { + glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + goto done; + } + memcpy (scaled, data, width*height*4); + } + else + GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height); + + glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); + if (mipmap) + { + int miplevel; + + miplevel = 0; + while (scaled_width > 1 || scaled_height > 1) + { + GL_MipMap ((byte *)scaled, scaled_width, scaled_height); + + + // jkrige - non power of two + scaled_width >>= 1; + scaled_height >>= 1; + /*if(npow2_ext == true && gl_texture_non_power_of_two.value == 1.0f && !mipmap) + { + scaled_width = (int)floor (width / pow(2, miplevel+1)); + scaled_height = (int)floor (height / pow (2, miplevel+1)); + } + else + { + scaled_width >>= 1; + scaled_height >>= 1; + }*/ + // jkrige - non power of two + + + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + miplevel++; + glTexImage2D (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); + } + } +done: ; +#endif + + // jkrige - anisotropic filtering + if (mipmap) + { + // jkrige - texture modes + if(floor(gl_texturemode.value) < 0.0f | gl_texturemode.value != floor(gl_texturemode.value)) + { + Con_Printf ("unknown texture mode\n"); + Cvar_Set ("gl_texturemode", "2"); + } + + if(gl_texturemode.value == 0.0f) + i = 0; + + if(gl_texturemode.value == 1.0f) + i = 3; + + if(gl_texturemode.value >= 2.0f) + i = 5; + + if(anisotropic_ext == true) + AnisotropyModes = (int)floor((log(maximumAnisotrophy)/log(2.0f)) + 0.5f); + else + AnisotropyModes = 0; + + if(anisotropic_ext == false) + { + if (gl_texturemode.value > 2.0f) + { + Con_Printf ("unknown texture mode\n"); + Cvar_Set ("gl_texturemode", "2"); + + return; + } + } + + if(anisotropic_ext == true) + { + if (gl_texturemode.value > (2.0f + (float)AnisotropyModes)) + { + Con_Printf ("unknown texture mode\n"); + Cvar_SetValue ("gl_texturemode", (2.0f + (float)AnisotropyModes)); + + return; + } + } + + gl_filter_min = modes[i].minimize; + gl_filter_max = modes[i].maximize; + + if(gl_texturemode.value <= 2.0f) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + if(anisotropic_ext == true) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); + } + + // jkrige - anisotropic filtering + if(gl_texturemode.value > 2.0f && anisotropic_ext == true) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, pow(2.0f, gl_texturemode.value - 2.0f)); + // jkrige - anisotropic filtering + + // jkrige - texture modes + + + /* + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + + // jkrige - anisotropic filtering + for (i = 0; i < 6; i++) + { + if (gl_filter_min == modes[i].minimize) + break; + } + + if(i == 5 && anisotropic_ext == true) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maximumAnisotrophy); + // jkrige - anisotropic filtering + */ + } + else + { + // jkrige - scale2d + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // jkrige - scale2d + + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR /*gl_filter_max*/); // jkrige - change bilinear texture filtering to trilinear texture filtering + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR /*gl_filter_max*/); // jkrige - change bilinear texture filtering to trilinear texture filtering + } + // jkrige - anisotropic filtering + + /*if (mipmap) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } + else + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + }*/ +} + + +// jkrige - no 8bit palette extensions +/*void GL_Upload8_EXT (byte *data, int width, int height, qboolean mipmap, qboolean alpha) +{ + int i, s; + qboolean noalpha; + int p; + static unsigned j; + int samples; + static unsigned char scaled[1024*512]; // [512*256]; + int scaled_width, scaled_height; + + s = width*height; + // if there are no transparent pixels, make it a 3 component + // texture even if it was specified as otherwise + if (alpha) + { + noalpha = true; + for (i=0 ; i>= (int)gl_picmip.value; + scaled_height >>= (int)gl_picmip.value; + + if (scaled_width > gl_max_size.value) + scaled_width = gl_max_size.value; + if (scaled_height > gl_max_size.value) + scaled_height = gl_max_size.value; + + if (scaled_width * scaled_height > sizeof(scaled)) + Sys_Error ("GL_LoadTexture: too big"); + + samples = 1; // alpha ? gl_alpha_format : gl_solid_format; + + texels += scaled_width * scaled_height; + + if (scaled_width == width && scaled_height == height) + { + if (!mipmap) + { + glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data); + goto done; + } + memcpy (scaled, data, width*height); + } + else + GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height); + + glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled); + if (mipmap) + { + int miplevel; + + miplevel = 0; + while (scaled_width > 1 || scaled_height > 1) + { + GL_MipMap8Bit ((byte *)scaled, scaled_width, scaled_height); + scaled_width >>= 1; + scaled_height >>= 1; + if (scaled_width < 1) + scaled_width = 1; + if (scaled_height < 1) + scaled_height = 1; + miplevel++; + glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled); + } + } +done: ; + + + if (mipmap) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } + else + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + } +}*/ +// jkrige - no 8bit palette extensions + +// jkrige - doubled textures +//static unsigned trans[640 * 480]; // jkrige - FIXME, temporary +static unsigned trans[2048 * 2048]; +// jkrige - doubled textures + +/* +=============== +GL_Upload8 +=============== +*/ +void GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean alpha) +{ + int i, s; + qboolean noalpha; + int p; + //static unsigned trans[640*480]; // FIXME, temporary + + + // jkrige - doubled textures + byte *dtdata; + int x, y; + + if (mipmap) + { + width *= 2; + height *= 2; + + s = width * height; + dtdata = malloc(s); + + for (y = 0; y < height / 2; y++) + { + for (x = 0; x < width / 2; x++) + { + dtdata[(y * (width * 2)) + (x * 2) + 0] = data[(y * (width / 2)) + x]; + dtdata[(y * (width * 2)) + (x * 2) + 1] = data[(y * (width / 2)) + x]; + + dtdata[(y * (width * 2)) + (x * 2) + 0 + width] = data[(y * (width / 2)) + x]; + dtdata[(y * (width * 2)) + (x * 2) + 1 + width] = data[(y * (width / 2)) + x]; + } + } + } + else + { + s = width * height; + dtdata = data; + } + //s = width * height; + // jkrige - doubled textures + + + // if there are no transparent pixels, make it a 3 component + // texture even if it was specified as otherwise + if (alpha) + { + noalpha = true; + for (i=0 ; iidentifier)) + { + if (width != glt->width || height != glt->height) + Sys_Error ("GL_LoadTexture: cache mismatch"); + return gltextures[i].texnum; + } + } + } + //else { // jkrige - threewave? + glt = &gltextures[numgltextures]; + numgltextures++; + //} + + strcpy (glt->identifier, identifier); + glt->texnum = texture_extension_number; + glt->width = width; + glt->height = height; + glt->mipmap = mipmap; + + GL_Bind(texture_extension_number ); + + GL_Upload8 (data, width, height, mipmap, alpha); + + texture_extension_number++; + + return texture_extension_number-1; +}*/ + +int lhcsumtable[256]; +int GL_LoadTexture (char *identifier, char *textype, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel) +{ + //qboolean noalpha; + int i, /*p,*/ s, lhcsum; + gltexture_t *glt; + + + // jkrige - fullbright pixels + byte *data2 = data; + // jkrige - fullbright pixels + + + // occurances. well this isn't exactly a checksum, it's better than that but + // not following any standards. + lhcsum = 0; + s = width*height*bytesperpixel; + //s = width*height; + for (i = 0;i < 256;i++) lhcsumtable[i] = i + 1; + for (i = 0;i < s;i++) lhcsum += (lhcsumtable[data[i] & 255]++); + + // see if the texture is allready present + if (identifier[0]) + { + for (i=0, glt=gltextures ; i < numgltextures ; i++, glt++) + { + if (!strcmp (identifier, glt->identifier)) + { + if (lhcsum != glt->lhcsum || width != glt->width || height != glt->height) + { + Con_DPrintf("GL_LoadTexture: cache mismatch\n"); + goto GL_LoadTexture_setup; + } + return glt->texnum; + } + } + } + // whoever at id or threewave must've been half asleep... + glt = &gltextures[numgltextures]; + numgltextures++; + + strcpy (glt->identifier, identifier); + glt->texnum = texture_extension_number; + texture_extension_number++; + + GL_LoadTexture_setup: + glt->lhcsum = lhcsum; + glt->width = width; + glt->height = height; + glt->mipmap = mipmap; + + // jkrige - luma textures (reset) + glt->tex_luma = false; + glt->tex_luma8bit = false; + // jkrige - luma textures (reset) + + if (!isDedicated) + { + GL_Bind(glt->texnum); + + //if (strcmp (textype, "bloom")) + { + if (bytesperpixel == 1) + { + GL_Upload8 (data, width, height, mipmap, alpha); + } + else if (bytesperpixel == 3 | bytesperpixel == 4) + { + if(image_alpha == 3) + GL_Upload32 ((void *)data, width, height, mipmap, false); + else + GL_Upload32 ((void *)data, width, height, mipmap, true); + } + else + Sys_Error("GL_LoadTexture: unknown bytes per pixel\n"); + } + + // jkrige - reset external image + image_width = 0; + image_height = 0; + image_bits = 8; + image_alpha = 3; + // jkrige - reset external image + + + // jkrige - luma textures + if (!strcmp (textype, "texture")) + { + char *ch_dot = strrchr(identifier, '.'); + + if (ch_dot != NULL) + { + char *ident; + char ch_name[MAX_PATH]; + byte *lumadata; + + i = 0; + ident = identifier; + + while (*identifier && *identifier != '.') + ch_name[i++] = *identifier++; + ch_name[i++] = 0; + + strcat(ch_name, "_luma"); + strcat(ch_name, ch_dot); + identifier = ident; + + if ((lumadata = LoadImagePixels (ch_name, false))) + { + GL_Bind(JK_LUMA_TEX + glt->texnum); + GL_Upload32((unsigned int *)lumadata, width, height, mipmap, true); + free(lumadata); + + glt->tex_luma = true; + } + } + } + // jkrige - luma textures + + + // jkrige - fullbright pixels + if ((!strcmp(textype, "texture") || !strcmp(textype, "skin")) && bytesperpixel == 1) + { + // if fullbright pixels are detected a new texture will + // be generated and it will be used asif its a luma texture + qboolean fullbright; + byte *fbdata; + + fbdata = malloc(width * height * 4); + + if (GL_FullbrightTexture(data, fbdata, width, height) == true) + { + GL_Bind(JK_LUMA_TEX + glt->texnum); + GL_Upload32((unsigned int *)fbdata, width, height, mipmap, alpha); + + glt->tex_luma = true; + glt->tex_luma8bit = true; + } + + if (fbdata) + free(fbdata); + } + // jkrige - fullbright pixels + + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + + return glt->texnum; +} +// jkrige - memleak & texture mismatch + +/* +================ +GL_LoadPicTexture +================ +*/ +int GL_LoadPicTexture (qpic_t *pic) +{ + int i; + + // jkrige - external texture loading + //i = GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true); + i = GL_LoadTexture ("", "", pic->width, pic->height, pic->data, false, true, 1); + // jkrige - external texture loading + + // jkrige - scale2d + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // jkrige - scale2d + + return i; +} + + + + +// jkrige - external texture loading +int image_width; +int image_height; +int image_bits; +int image_alpha; + +byte Convert24to8(byte *palette, byte Red, byte Green, byte Blue) +{ + int i; + + for(i=0; i<768; i+=3) + { + if(palette[i] == Red && palette[i+1] == Green && palette[i+2] == Blue) + return 255-(i/3); + } + + return 0; +} + +/* +======== +LoadJPG +======== +*/ +byte *LoadJPG ( const char *filename) +{ + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + unsigned char *out; + byte *fbuffer; + byte *bbuf; + + /* In this example we want to open the input file before doing anything else, + * so that the setjmp() error recovery below can assume the file is open. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to read binary files. + */ + + + // jkrige - pk3 file support + int len; + FILE *f; + byte *pic; + + // + // load the file + // + len = COM_FOpenFile (( char * )filename, &f); + if(len < 1) + return NULL; + + fbuffer = COM_FReadFile(f, len); + if (!fbuffer) + return NULL; + + pic = NULL; + // jkrige - pk3 file support + + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, fbuffer); + + /* Step 3: read file parameters with jpeg_read_header() */ + + (void) jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + + out = malloc(cinfo.output_width*cinfo.output_height*cinfo.output_components); + + // jkrige + // *pic = out; + // *width = cinfo.output_width; + // *height = cinfo.output_height; + pic = out; + image_width = cinfo.image_width; + image_height = cinfo.image_height; + // jkrige + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) + { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + bbuf = ((out+(row_stride*cinfo.output_scanline))); + buffer = &bbuf; + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + } + + // clear all the alphas to 255 + { + int i, j; + byte *buf; + + buf = pic; + + j = cinfo.output_width * cinfo.output_height * 4; + for ( i = 3 ; i < j ; i+=4 ) + { + buf[i] = 255; + } + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + + image_bits = 32; + image_alpha = 3; + + free (fbuffer); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ + return pic; +} + + +/* +============= +TARGA LOADING +============= +*/ + +typedef struct _TargaHeader +{ + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} TargaHeader; + + +TargaHeader targa_header; + +int fgetLittleShort (FILE *f) +{ + byte b1, b2; + + b1 = fgetc(f); + b2 = fgetc(f); + + return (short)(b1 + b2*256); +} + +int fgetLittleLong (FILE *f) +{ + byte b1, b2, b3, b4; + + b1 = fgetc(f); + b2 = fgetc(f); + b3 = fgetc(f); + b4 = fgetc(f); + + return b1 + (b2<<8) + (b3<<16) + (b4<<24); +} + + +/* +======== +LoadTGA +======== +*/ +byte *LoadTGA ( const char *name) +{ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + TargaHeader targa_header; + byte *targa_rgba; + + // jkrige - bitsperpixel check + int i; + // jkrige - bitsperpixel check + + + // jkrige - pk3 file support + int len; + FILE *f; + byte *pic; + // jkrige - pk3 file support + + + // *pic = NULL; // jkrige + pic = NULL; + buffer = NULL; + + // + // load the file + // + len = COM_FOpenFile (( char * )name, &f); + if(len < 1) + return NULL; + + buffer = COM_FReadFile(f, len); + + + if (!buffer) + return NULL; + + buf_p = buffer; + + targa_header.id_length = *buf_p++; + targa_header.colormap_type = *buf_p++; + targa_header.image_type = *buf_p++; + + targa_header.colormap_index = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.colormap_length = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.colormap_size = *buf_p++; + targa_header.x_origin = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.y_origin = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.width = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.height = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.pixel_size = *buf_p++; + targa_header.attributes = *buf_p++; + + if (targa_header.image_type!=2 && targa_header.image_type!=10 && targa_header.image_type != 3 ) + { + Sys_Error ("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n"); + } + + if ( targa_header.colormap_type != 0 ) + { + Sys_Error ("LoadTGA: colormaps not supported\n" ); + } + + if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) + { + Sys_Error ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + } + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + // jkrige + /*if (width) + *width = columns; + if (height) + *height = rows;*/ + image_width = columns; + image_height = rows; + // jkrige + + targa_rgba = malloc (numPixels*4); + // *pic = targa_rgba; // jkrige + pic = targa_rgba; + + if (targa_header.id_length != 0) + buf_p += targa_header.id_length; // skip TARGA image comment + + if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) + { + // Uncompressed RGB or gray scale image + for(row=rows-1; row>=0; row--) + { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column=0; row--) + { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else + { // non run-length packet + for(j=0;j0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + } + breakOut:; + } + } + +//#if 0 + // TTimo: this is the chunk of code to ensure a behavior that meets TGA specs + // bk0101024 - fix from Leonardo + // bit 5 set => top-down + if (targa_header.attributes & 0x20) + { + unsigned char *flip = (unsigned char*)malloc (columns*4); + unsigned char *src, *dst; + + for (row = 0; row < rows/2; row++) + { + src = targa_rgba + row * 4 * columns; + dst = targa_rgba + (rows - row - 1) * 4 * columns; + + memcpy (flip, src, columns*4); + memcpy (src, dst, columns*4); + memcpy (dst, flip, columns*4); + } + free (flip); + } +//#endif + // instead we just print a warning + //if (targa_header.attributes & 0x20) + //{ + // Con_Printf("WARNING: '%s' TGA file header declares top-down image, ignoring\n", name); + //} + + + // jkrige - bitsperpixel check + image_bits = 32; + image_alpha = gl_solid_format; + for (i = 0;i < image_width*image_height;i++) + { + if (targa_rgba[i*4+3] < 255) + { + image_alpha = gl_alpha_format; + break; + } + } + // jkrige - bitsperpixel check + + + free (buffer); + + return pic; +} + +byte* LoadImagePixels (char* filename, qboolean complain) +{ + char basename[128], name[128]; + byte *data; + + COM_StripExtension(filename, basename); // strip the extension to allow more filetypes + + sprintf (name, "%s.tga", basename); + data = LoadTGA(name); + if(data) + return data; + + sprintf (name, "%s.jpg", basename); + data = LoadJPG(name); + if(data) + return data; + + if (complain) + Con_Printf ("Couldn't load %s\n", name); + + return NULL; +} + +int LoadTextureImage (char* filename, char *textype, int matchwidth, int matchheight, qboolean complain, qboolean mipmap) +{ + int texnum; + int i; + qboolean alpha; + byte *data; + + if (!(data = LoadImagePixels (filename, complain))) + return 0; + + if(image_alpha == 4) + alpha = true; + else + alpha = false; + + if(image_bits != 32) + texnum = GL_LoadTexture (filename, textype, image_width, image_height, data, mipmap, true, 1); + else + texnum = GL_LoadTexture (filename, textype, image_width, image_height, data, mipmap, alpha, image_alpha); + + if (data) + free(data); + + return texnum; +} +// jkrige - external texture loading + + + + + + + + +// jkrige - remove multitexture +/*static GLenum oldtarget = TEXTURE0_SGIS; + +void GL_SelectTexture (GLenum target) +{ + if (!gl_mtexable) + return; + qglSelectTextureSGIS(target); + if (target == oldtarget) + return; + cnttextures[oldtarget-TEXTURE0_SGIS] = currenttexture; + currenttexture = cnttextures[target-TEXTURE0_SGIS]; + oldtarget = target; +}*/ +// jkrige - remove multitexture \ No newline at end of file diff --git a/engine/code/gl_fullbright.c b/engine/code/gl_fullbright.c new file mode 100644 index 0000000..1797018 --- /dev/null +++ b/engine/code/gl_fullbright.c @@ -0,0 +1,88 @@ +/* +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. + +*/ +// gl_fullbright.c: fullbright pixel processing + +// Developed by Jacques Krige +// Ultimate Quake Engine +// http://www.jacqueskrige.com + + +#include "quakedef.h" + + +qboolean GL_FullbrightTexture (byte *in, byte *out, int width, int height) +{ + int i, j; + int p; + int numpixels; + qboolean fbtex; + + numpixels = width * height; + fbtex = false; + + // check if this texture has fullbrights + for (i = 0; i < numpixels; i++) + { + p = in[i]; + + if (p > 238 && p != 255) + { + fbtex = true; + break; + } + } + + + // replace non fullbrights with black + if (fbtex == true) + { + for (i = 0, j = 0; i < numpixels; i++, j+=4) + { + if (in[i] < 239) + in[i] = 0; + + p = in[i]; + + if (p == 0) + { + out[j+0] = 0; + out[j+1] = 0; + out[j+2] = 0; + out[j+3] = 255; + } + else if (p == 255) + { + out[j+0] = 0; + out[j+1] = 0; + out[j+2] = 0; + out[j+3] = 0; + } + else + { + out[j+0] = host_basepal[(p*3)+0]; + out[j+1] = host_basepal[(p*3)+1]; + out[j+2] = host_basepal[(p*3)+2]; + out[j+3] = 255; + } + } + } + + return fbtex; +} diff --git a/engine/code/gl_fullbright.h b/engine/code/gl_fullbright.h new file mode 100644 index 0000000..8e89e13 --- /dev/null +++ b/engine/code/gl_fullbright.h @@ -0,0 +1,27 @@ +/* +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. + +*/ +// gl_fullbright.h: fullbright pixel processing + +// Developed by Jacques Krige +// Ultimate Quake Engine +// http://www.jacqueskrige.com + + +qboolean GL_FullbrightTexture (byte *in, byte *out, int width, int height); diff --git a/engine/code/gl_mesh.c b/engine/code/gl_mesh.c new file mode 100644 index 0000000..a62fa48 --- /dev/null +++ b/engine/code/gl_mesh.c @@ -0,0 +1,362 @@ +/* +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. + +*/ +// 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; + mtriangle_t *last, *check; + int m1, m2; + int striplength; + trivertx_t *v; + mtriangle_t *tv; + float s, t; + int index; + 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; + maliasgroup_t *paliasgroup; + int *cmds; + trivertx_t *verts; + char cache[MAX_QPATH], fullpath[MAX_OSPATH], *c; + FILE *f; + int len; + byte *data; + + aliasmodel = m; + paliashdr = hdr; // (aliashdr_t *)Mod_Extradata (m); + + // jkrige - mdl meshing removal + // + // 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 (); // trifans or lists + + // + // 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); + } + }*/ + BuildTris (); + // jkrige - mdl meshing removal + + // save the data out + + paliashdr->poseverts = numorder; + + cmds = Hunk_Alloc (numcommands * 4); + paliashdr->commands = (byte *)cmds - (byte *)paliashdr; + memcpy (cmds, commands, numcommands * 4); + + verts = Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts + * sizeof(trivertx_t) ); + paliashdr->posedata = (byte *)verts - (byte *)paliashdr; + for (i=0 ; inumposes ; i++) + for (j=0 ; jcache); + 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; +} + +/* +================== +Mod_FindName + +================== +*/ +model_t *Mod_FindName (char *name) +{ + int i; + model_t *mod; + + if (!name[0]) + Sys_Error ("Mod_ForName: NULL name"); + +// +// 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_NumForName: %s not found", mod->name); + 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_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; + + // jkrige - external texture loading + FILE *f2; + //int pcxmip[4]; + char texname[MAX_QPATH]; + // jkrige - external texture loading + + // jkrige - fullbright pixels + char fbr_name[64]; + int fbr_pixels; + // jkrige - fullbright pixels + + if (!l->filelen) + { + loadmodel->textures = NULL; + return; + } + m = (dmiptexlump_t *)(mod_base + l->fileofs); + + m->nummiptex = LittleLong (m->nummiptex); + + loadmodel->numtextures = m->nummiptex; + loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname); + + for (i=0 ; inummiptex ; i++) + { + m->dataofs[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); + + // jkrige - fullbright pixels + fbr_pixels = pixels; + // jkrige - fullbright pixels + + + if (!Q_strncmp(mt->name,"sky",3)) + R_InitSky (tx); + else + { + // jkrige - luma textures + tx->tex_luma = false; + // jkrige - luma textures + + + texture_mode = GL_LINEAR_MIPMAP_NEAREST; //_LINEAR; + + + // jkrige - external texture loading + if(mt->name[0] == '*' || mt->name[0] == '#') + { + //sprintf (texname, "textures/%s.tga", strnset(mt_wal->name, '-', 1)); + + sprintf (texname, "textures/%s/%s.tga", sv.name, strnset(mt->name , '#', 1)); + tx->gl_texturenum = LoadTextureImage (texname, "texture", 0, 0, false, true); + + if (tx->gl_texturenum == 0) + { + sprintf (texname, "textures/%s.tga", strnset(mt->name , '#', 1)); + tx->gl_texturenum = LoadTextureImage (texname, "texture", 0, 0, false, true); + } + } + else + { + //sprintf (texname, "textures/%s.tga", mt_wal->name); + + sprintf (texname, "textures/%s/%s.tga", sv.name, mt->name); + tx->gl_texturenum = LoadTextureImage (texname, "texture", 0, 0, false, true); + + if (tx->gl_texturenum == 0) + { + sprintf (texname, "textures/%s.tga", mt->name); + tx->gl_texturenum = LoadTextureImage (texname, "texture", 0, 0, false, true); + } + } + + + //tx->gl_texturenum = GL_LoadTexture (mt->name, tx->width, tx->height, (byte *)(tx+1), true, false); + if (tx->gl_texturenum == 0)// did not find a matching external texture... + { + tx->gl_texturenum = GL_LoadTexture (mt->name, "texture", tx->width, tx->height, (byte *)(tx+1), true, false, 1); + } + + + // jkrige - fullbright pixels + // jkrige - luma textures + for(j = 0; j < numgltextures; j++) + { + if(tx->gl_texturenum == gltextures[j].texnum) + { + tx->tex_luma = gltextures[j].tex_luma; + tx->tex_luma8bit = gltextures[j].tex_luma8bit; + + break; + } + } + // jkrige - luma textures + // jkrige - fullbright pixels + + + texture_mode = GL_LINEAR; + } + } + +// +// sequence the animations +// + for (i=0 ; inummiptex ; i++) + { + tx = loadmodel->textures[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 ; jnummiptex ; j++) + { + tx2 = loadmodel->textures[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 +================= +*/ +// jkrige - .lit colored lights +void Mod_LoadLighting (lump_t *l) +{ + // LordHavoc: .lit support + int i; + byte *in, *out, *data; + byte d; + char litfilename[MAX_QPATH]; + + GL_SetupLightmapFmt(false); // setup the lightmap format to reflect any + // changes via the cvar gl_lightmapfmt + + // bound the gl_coloredlight value + if (gl_coloredlight.value < 0) + Cvar_SetValue ("gl_coloredlight", 0); + gl_coloredstatic = gl_coloredlight.value; + + if (gl_lightmap_format == GL_RGBA) + { + loadmodel->lightdata = NULL; + + if (gl_coloredlight.value == 1) + { // LordHavoc: check for a .lit file + strcpy(litfilename, loadmodel->name); + COM_StripExtension(litfilename, litfilename/*, sizeof(litfilename)*/); + strcat(litfilename, ".lit"); + Con_DPrintf("trying to load %s\n", litfilename); + 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\n", litfilename); + + Con_DPrintf("Mod_LoadLighting: Loaded colored light (32-bit)\n"); + + if ( gl_coloredlight.value == 1 ) + { + loadmodel->lightdata = data + 8; + return; + } + else + { + int min_light = 8; + int k = 0; + int mark, j, r, g, b; + float l2lc = 0; + float lc = 0; + float li = 0; + + if (!l->filelen) + { + loadmodel->lightdata = data + 8; + Con_DPrintf("Mod_LoadLighting: No white light data. Using colored only\n"); + return; + } + Con_DPrintf("Mod_LoadLighting: Loaded white light.\n"); + + // allocate memory and load light data from .bsp + mark = Hunk_LowMark(); + loadmodel->lightdata = /*(byte *)*/ Hunk_AllocName (l->filelen, "light"); + memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); + + for (i = 0, j = 0, k = 0; i < l->filelen * 3; i += 3, j += 3) + { + // set some minimal light level + r = max(data[8+i], min_light); + g = max(data[8+i+1], min_light); + b = max(data[8+i+2], min_light); + + // compute brightness of colored ligths present in .lit file + lc = (r + g + b) / 3.0f; + li = (float) loadmodel->lightdata[k]; + + if (li == 0) + li = min_light; + if (lc == 0) + lc = min_light; + + // compute light amplification level + l2lc = (float) li/lc; + if ( l2lc < 1.5f ) + l2lc = 1; + + // update colors + data[8+j] = (byte) min(max( ceil(r*l2lc), min_light ),255); + data[8+j+1] = (byte) min(max( ceil(g*l2lc), min_light ),255); + data[8+j+2] = (byte) min(max( ceil(b*l2lc), min_light ),255); + k++; + } + Hunk_FreeToLowMark(mark); + + loadmodel->lightdata = data + 8; + Con_DPrintf("Mod_LoadLighting: Blended lightmaps.\n"); + + return; + } + } + else + { + Con_DPrintf("Mod_LoadLighting: Unknown .lit file version (%d)\n", i); + } + } + else + { + Con_DPrintf("Mod_LoadLighting: Corrupt .lit file (old version?), ignoring\n"); + } + } + } + // no .lit found, expand the white lighting data to color + if (!l->filelen) + { + //loadmodel->lightdata = NULL; + return; + } + loadmodel->lightdata = /*(byte *)*/ Hunk_AllocName ( l->filelen*3, "light" /*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; + } + Con_DPrintf("Mod_LoadLighting: Loaded white light (32-bit)\n"); + } + else + { + if (!l->filelen) + { + loadmodel->lightdata = NULL; + return; + } + loadmodel->lightdata = /*(byte *)*/ Hunk_AllocName ( l->filelen, "light"); + memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); + Con_DPrintf("Mod_LoadLighting: Loaded white light (8-bit)\n"); + } +} + +/*void Mod_LoadLighting (lump_t *l) +{ + if (!l->filelen) + { + loadmodel->lightdata = NULL; + return; + } + loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname); + memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); +}*/ +// jkrige - .lit colored lights + + +/* +================= +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 +================= +*/ +// jkrige - load external .ent files +void Mod_LoadEntities (lump_t *l) +{ + char entfilename[MAX_QPATH]; + char *ents; + int mark; + + strcpy(entfilename, loadmodel->name); + COM_StripExtension(entfilename, entfilename); + strcat(entfilename, ".ent"); + Con_DPrintf("trying to load %s\n", entfilename); + mark = Hunk_LowMark(); + ents = (char *) COM_LoadHunkFile (entfilename); + if (ents) + { + loadmodel->entities = ents; + Con_DPrintf("Loaded external entity file %s\n", entfilename); + return; + } + + if (!l->filelen) + { + loadmodel->entities = NULL; + return; + } + loadmodel->entities = (char *) Hunk_AllocName ( l->filelen, "entities"); + memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen); +} + +/*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); +}*/ +// jkrige - load external .ent files + + +/* +================= +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_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); + } +} + +/* +================= +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; + int miptex; + float len1, len2; + + 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); + + if (!loadmodel->textures) + { + out->texture = r_notexture_mip; // checkerboard texture + out->flags = 0; + } + else + { + if (miptex >= loadmodel->numtextures) + Sys_Error ("miptex >= loadmodel->numtextures"); + out->texture = loadmodel->textures[miptex]; + if (!out->texture) + { + out->texture = r_notexture_mip; // texture not found + out->flags = 0; + } + } + } +} + +/* +================ +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] > 512 /* 256 */ ) + Sys_Error ("Bad surface extents"); + } +} + + +/* +================= +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); + + 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); + + // lighting info + + for (i=0 ; istyles[i] = in->styles[i]; + i = LittleLong(in->lightofs); + if (i == -1) + { + out->samples = NULL; + } + else + { + // jkrige - .lit colored lights + if (gl_lightmap_format == GL_RGBA) + out->samples = loadmodel->lightdata + (i * 3); // LordHavoc + else + out->samples = loadmodel->lightdata + i; + //out->samples = loadmodel->lightdata + i; + // jkrige - .lit colored lights + } + + + // jkrige - overbrights + if (gl_overbright.value) + out->overbright = true; + else + out->overbright = false; + // jkrige - overbrights + + + // set the drawing flags flag + + if (!Q_strncmp(out->texinfo->texture->name,"sky",3)) // sky + { + out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); +#ifndef QUAKE2 + GL_SubdivideSurface (out); // cut up polygon for warps +#endif + continue; + } + + if (!Q_strncmp(out->texinfo->texture->name,"*",1)) // turbulent + { + out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED); + for (i=0 ; i<2 ; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + } + GL_SubdivideSurface (out); // cut up polygon for warps + continue; + } + + } +} + + +/* +================= +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); + + 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 = LittleShort (in->firstface); + out->numsurfaces = LittleShort (in->numfaces); + + for (j=0 ; j<2 ; j++) + { + p = LittleShort (in->children[j]); + if (p >= 0) + out->children[j] = loadmodel->nodes + p; + else + out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p)); + } + } + + 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); + + 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 + + LittleShort(in->firstmarksurface); + out->nummarksurfaces = LittleShort(in->nummarksurfaces); + + 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]; + + // gl underwater warp + if (out->contents != CONTENTS_EMPTY) + { + for (j=0 ; jnummarksurfaces ; j++) + out->firstmarksurface[j]->flags |= SURF_UNDERWATER; + } + } +} + +/* +================= +Mod_LoadClipnodes +================= +*/ +void Mod_LoadClipnodes (lump_t *l) +{ + dclipnode_t *in, *out; + 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); + + 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); + out->children[0] = LittleShort(in->children[0]); + out->children[1] = LittleShort(in->children[1]); + } +} + +/* +================= +Mod_MakeHull0 + +Deplicate the drawing hull structure as a clipping hull +================= +*/ +void Mod_MakeHull0 (void) +{ + mnode_t *in, *child; + dclipnode_t *out; + 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; + + 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_LoadBrushModel +================= +*/ +void Mod_LoadBrushModel (model_t *mod, void *buffer) +{ + int i, j; + dheader_t *header; + dmodel_t *bm; + + loadmodel->type = mod_brush; + + + header = (dheader_t *)buffer; + + i = LittleLong (header->version); + + // jkrige - bsp version crash + //if (i != BSPVERSION) + // Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION); + if (i != BSPVERSION) + { + Con_Printf("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION); + mod->numvertexes = -1; // HACK - incorrect BSP version is no longer fatal + return; + } + // jkrige - bsp version crash + +// 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) +// + 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); + + mod->radius = RadiusFromBounds (mod->mins, mod->maxs); + + 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; + +int aliasbboxmins[3], aliasbboxmaxs[3]; // jkrige - fix bounding boxes on models + +/* +================= +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->bboxmin.v[i] = pdaliasframe->bboxmax.v[i]; + + // jkrige - fix bounding boxes on models + aliasbboxmins[i] = min (frame->bboxmin.v[i], aliasbboxmins[i]); + aliasbboxmaxs[i] = max (frame->bboxmax.v[i], aliasbboxmaxs[i]); + // jkrige - fix bounding boxes on models + } + + 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->bboxmin.v[i] = pingroup->bboxmax.v[i]; + + // jkrige - fix bounding boxes on models + aliasbboxmins[i] = min (frame->bboxmin.v[i], aliasbboxmins[i]); + aliasbboxmaxs[i] = max (frame->bboxmax.v[i], aliasbboxmaxs[i]); + // jkrige - fix bounding boxes on models + } + + 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; + + // jkrige - external texture loading + //char name[32]; + char name[64], model[64], model2[64]; + // jkrige - external texture loading + + int s; + byte *copy; + byte *skin; + byte *texels; + daliasskingroup_t *pinskingroup; + int groupskins; + daliasskininterval_t *pinskinintervals; + + skin = (byte *)(pskintype + 1); + + if (numskins < 1 || numskins > MAX_SKINS) + Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins); + + s = 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 + // if (!strcmp(loadmodel->name,"progs/player.mdl")) { + texels = Hunk_AllocName(s, loadname); + pheader->texels[i] = texels - (byte *)pheader; + memcpy (texels, (byte *)(pskintype + 1), s); + // } + sprintf (name, "%s_%i", loadmodel->name, i); + + + // jkrige - external texture loading + //pheader->gl_texturenum[i][0] = + //pheader->gl_texturenum[i][1] = + //pheader->gl_texturenum[i][2] = + //pheader->gl_texturenum[i][3] = + // GL_LoadTexture (name, pheader->skinwidth, pheader->skinheight, (byte *)(pskintype + 1), true, false); + + COM_StripExtension(loadmodel->name, model); + sprintf (model2, "%s_%i", model, i); + pheader->gl_texturenum[i][0] = + pheader->gl_texturenum[i][1] = + pheader->gl_texturenum[i][2] = + pheader->gl_texturenum[i][3] = + LoadTextureImage (model2, "skin", 0, 0, false, true); + + if (pheader->gl_texturenum[i][0] == 0)// did not find a matching external texture... + { + pheader->gl_texturenum[i][0] = + pheader->gl_texturenum[i][1] = + pheader->gl_texturenum[i][2] = + pheader->gl_texturenum[i][3] = + GL_LoadTexture (name, "skin", pheader->skinwidth, pheader->skinheight, (byte *)(pskintype + 1), true, false, 1); + } + // jkrige - external texture loading + + + // jkrige - fullbright pixels + // jkrige - luma textures + for(j = 0; j < numgltextures; j++) + { + if(pheader->gl_texturenum[i][0] == gltextures[j].texnum) + { + pheader->skin_luma[i] = gltextures[j].tex_luma; + pheader->skin_luma8bit[i] = gltextures[j].tex_luma8bit; + + break; + } + } + // jkrige - luma textures + // jkrige - fullbright pixels + + + pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); + } + 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(s, loadname); + pheader->texels[i] = texels - (byte *)pheader; + memcpy (texels, (byte *)(pskintype), s); + } + sprintf (name, "%s_%i_%i", loadmodel->name, i, j); + + + // jkrige - external texture loading + //pheader->gl_texturenum[i][j&3] = GL_LoadTexture (name, pheader->skinwidth, pheader->skinheight, (byte *)(pskintype), true, false); + + COM_StripExtension(loadmodel->name, model); + sprintf (model2, "%s_%i_%i", model, i, j); + pheader->gl_texturenum[i][j&3] = LoadTextureImage (model2, "skin", 0, 0, false, true); + + if (pheader->gl_texturenum[i][j&3] == 0)// did not find a matching external texture... + pheader->gl_texturenum[i][j&3] = GL_LoadTexture (name, "skin", pheader->skinwidth, pheader->skinheight, (byte *)(pskintype), true, false, 1); + // jkrige - external texture loading + + + // jkrige - fullbright pixels + // jkrige - luma textures + for(k = 0; k < numgltextures; k++) + { + if(pheader->gl_texturenum[i][j&3] == gltextures[k].texnum) + { + pheader->skin_luma[i] = gltextures[k].tex_luma; + pheader->skin_luma8bit[i] = gltextures[k].tex_luma8bit; + + break; + } + } + // jkrige - luma textures + // jkrige - fullbright pixels + + + pskintype = (daliasskintype_t *)((byte *)(pskintype) + s); + } + k = j; + for (/* */; j < 4; j++) + pheader->gl_texturenum[i][j&3] = pheader->gl_texturenum[i][j - k]; + } + } + + return (void *)pskintype; +} + +//========================================================================= + +/* +================= +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; + int size; + daliasframetype_t *pframetype; + daliasskintype_t *pskintype; + int start, end, total; + + start = Hunk_LowMark (); + + pinmodel = (mdl_t *)buffer; + + 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]; + + // jkrige - fix bounding boxes on models + aliasbboxmins[0] = aliasbboxmins[1] = aliasbboxmins[2] = -128; + aliasbboxmaxs[0] = aliasbboxmaxs[1] = aliasbboxmaxs[2] = 128; + // jkrige - fix bounding boxes on models + + 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; + + // jkrige - fix bounding boxes on models + //mod->mins[0] = mod->mins[1] = mod->mins[2] = -16; + //mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16; + for (i = 0; i < 3; i++) + { + mod->mins[i] = aliasbboxmins[i] * pheader->scale[i]; + mod->maxs[i] = aliasbboxmaxs[i] * pheader->scale[i]; + + if((mod->maxs[i] - mod->mins[i]) < 32.0f) + { + mod->mins[i] = -16; + mod->maxs[i] = 16; + } + } + // jkrige - fix bounding boxes on models + + // + // 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 i, width, height, size, origin[2]; + unsigned short *ppixout; + byte *ppixin; + char name[64]; + + + // jkrige - external texture loading + char sprite[64]; + char sprite2[64]; + FILE *f2; + int FileFound = -1; + qboolean ExtOK = false; + + COM_FileBase(loadmodel->name, sprite); + + if(FileFound == -1) + { + sprintf (sprite2, "sprites/%s_%i.tga", sprite, framenum); + FileFound = COM_FOpenFile(sprite2, &f2); + } + if(FileFound == -1) + { + sprintf (sprite2, "sprites/%s_%i.jpg", sprite, framenum); + FileFound = COM_FOpenFile(sprite2, &f2); + } + if(FileFound == -1) + { + sprintf (sprite2, "sprites/%s_%i.pcx", sprite, framenum); + FileFound = COM_FOpenFile(sprite2, &f2); + } + // jkrige - external texture loading + + + 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]; + + //sprintf (name, "%s_%i", loadmodel->name, framenum); + //pspriteframe->gl_texturenum = GL_LoadTexture (name, width, height, (byte *)(pinframe + 1), true, true); + + + // jkrige - external texture loading + pspriteframe->gl_texturenum = LoadTextureImage (sprite2, "sprite", 0, 0, false, true); + if (pspriteframe->gl_texturenum == 0) // did not find a matching external files... + { + sprintf (name, "%s_%i", loadmodel->name, framenum); + pspriteframe->gl_texturenum = GL_LoadTexture (name, "sprite", width, height, (byte *)(pinframe + 1), true, true, 1); + } + // jkrige - external texture loading + + + 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; + + 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_Printf ("Cached models:\n"); + for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++) + { + Con_Printf ("%8p : %s\n",mod->cache.data, mod->name); + } +} + + diff --git a/engine/code/gl_model.h b/engine/code/gl_model.h new file mode 100644 index 0000000..4a5b71c --- /dev/null +++ b/engine/code/gl_model.h @@ -0,0 +1,454 @@ +/* +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. + +*/ + +#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; + int gl_texturenum; + + qboolean tex_luma; // jkrige - luma textures + qboolean tex_luma8bit; // jkrige - fullbright pixels + + struct msurface_s *texturechain; // for gl_texsort drawing + 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 + +// !!! 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; + int flags; // for SURF_UNDERWATER + float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2) +} glpoly_t; + +typedef struct msurface_s +{ + int visframe; // should be drawn when node is crossed + + 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; + + // jkrige - luma textures + qboolean luma_mark; + // jkrige - luma textures + +// lighting info + int dlightframe; + // jkrige - increase dlights + //int dlightbits; + byte dlightbits[(MAX_DLIGHTS + 7) / 8]; + // jkrige - increase dlights + + 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] + + // jkrige - overbrights + qboolean overbright; + // jkrige - overbrights + +} 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; + +// !!! if this is changed, it must be changed in asm_i386.h too !!! +typedef struct +{ + dclipnode_t *clipnodes; + 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; + int height; + float up, down, left, right; + int gl_texturenum; +} 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 + int gl_texturenum[MAX_SKINS][4]; + int texels[MAX_SKINS]; // only for player skins + + // jkrige - fullbright pixels + qboolean skin_luma[MAX_SKINS]; + qboolean skin_luma8bit[MAX_SKINS]; + // jkrige - fullbright pixels + + + maliasframedesc_t frames[1]; // variable sized +} aliashdr_t; + +#define MAXALIASVERTS 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 + +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; + 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; + dclipnode_t *clipnodes; + + 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/engine/code/gl_refrag.c b/engine/code/gl_refrag.c new file mode 100644 index 0000000..1b060b3 --- /dev/null +++ b/engine/code/gl_refrag.c @@ -0,0 +1,234 @@ +/* +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. + +*/ +// 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) + { + Con_Printf ("Too many efrags!\n"); + 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_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_StoreEfrags + +// FIXME: a lot of this goes away with edge-based +================ +*/ +void R_StoreEfrags (efrag_t **ppefrag) +{ + entity_t *pent; + model_t *clmodel; + efrag_t *pefrag; + + + while ((pefrag = *ppefrag) != NULL) + { + pent = pefrag->entity; + clmodel = pent->model; + + switch (clmodel->type) + { + case mod_alias: + case mod_brush: + case mod_sprite: + pent = pefrag->entity; + + if ((pent->visframe != r_framecount) && + (cl_numvisedicts < MAX_VISEDICTS)) + { + cl_visedicts[cl_numvisedicts++] = pent; + + // mark that we've recorded this entity for this frame + pent->visframe = r_framecount; + } + + ppefrag = &pefrag->leafnext; + break; + + default: + Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type); + } + } +} + + diff --git a/engine/code/gl_rlight.c b/engine/code/gl_rlight.c new file mode 100644 index 0000000..c142135 --- /dev/null +++ b/engine/code/gl_rlight.c @@ -0,0 +1,579 @@ +/* +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. + +*/ +// r_light.c + +#include "quakedef.h" + +int r_dlightframecount; + + +/* +================== +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 (); +}*/ +// jkrige - flashblend removal + + +// jkrige - flashblend removal +/* +============= +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); +}*/ +// jkrige - flashblend removal + +/* +============================================================================= + +DYNAMIC LIGHTS + +============================================================================= +*/ + +/* +============= +R_MarkLights +============= +*/ +void R_MarkLights (dlight_t *light, int lnum, mnode_t *node) +{ + mplane_t *splitplane; + float dist; + msurface_t *surf; + int i; + + // jkrige - fix dynamic light shine through + int sidebit; + // jkrige - fix dynamic light shine through + + // jkrige - speed increase + float l, maxdist; + int j, s, t; + vec3_t impact; +loc0: + // jkrige - speed increase + + if (node->contents < 0) + return; + + splitplane = node->plane; + + // jkrige - speed increase + if (splitplane->type < 3) + dist = light->origin[splitplane->type] - splitplane->dist; + else + dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; + //dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; + // jkrige - speed increase + + if (dist > light->radius) + { + // jkrige - speed increase + node = node->children[0]; + goto loc0; + //R_MarkLights (light, lnum, node->children[0]); + //return; + // jkrige - speed increase + } + if (dist < -light->radius) + { + // jkrige - speed increase + node = node->children[1]; + goto loc0; + //R_MarkLights (light, lnum, node->children[1]); + //return; + // jkrige - speed increase + } + + // jkrige - speed increase + maxdist = light->radius*light->radius; + // jkrige - speed increase + +// mark the polygons + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + // jkrige - fix dynamic light shine through + if (r_dynamic_sidemark.value) + { + if (dist >= 0) + sidebit = 0; + else + sidebit = SURF_PLANEBACK; + + if ( (surf->flags & SURF_PLANEBACK) != sidebit ) + continue; + } + // jkrige - fix dynamic light shine through + + + // jkrige - speed increase + 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; + // jkrige - speed increase + + + // jkrige - increase dlights + //if (surf->dlightframe != r_dlightframecount) + //{ + // surf->dlightbits = 0; + // surf->dlightframe = r_dlightframecount; + //} + //surf->dlightbits |= lnum; // jkrige - was bit + + + if ((s*s+t*t+dist*dist) < maxdist) // jkrige - speed increase + { + if (surf->dlightframe != r_dlightframecount) + { + // init a new dlight on the surf + int j; + + for (j = 0; j < MAX_DLIGHTS; j += 8) + surf->dlightbits[(j >> 3)] = 0; + + surf->dlightframe = r_dlightframecount; + } + + + // mark it + surf->dlightbits[(lnum >> 3)] |= (1 << (lnum & 7)); + } + // jkrige - increase dlights + } + + // jkrige - speed increase + if (node->children[0]->contents >= 0) + R_MarkLights (light, lnum, node->children[0]); + if (node->children[1]->contents >= 0) + R_MarkLights (light, lnum, node->children[1]); + //R_MarkLights (light, lnum, node->children[0]); + //R_MarkLights (light, lnum, node->children[1]); + // jkrige - speed increase +} + + +/* +============= +R_PushDlights +============= +*/ +void R_PushDlights (void) +{ + int i; + dlight_t *l; + + // jkrige - flashblend removal + //if (gl_flashblend.value) + // return; + // jkrige - flashblend removal + + 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; + + // jkrige - increase dlights + //R_MarkLights ( l, 1<nodes ); + R_MarkLights ( l, i, cl.worldmodel->nodes ); + // jkrige - increase dlights + } +} + + +/* +============================================================================= + +LIGHT SAMPLING + +============================================================================= +*/ + +mplane_t *lightplane; +vec3_t lightspot; + +// jkrige - .lit colored lights +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); + } +} + +/*int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) +{ + int r; + float front, back, frac; + int side; + mplane_t *plane; + vec3_t mid; + msurface_t *surf; + int s, t, ds, dt; + int i; + mtexinfo_t *tex; + byte *lightmap; + unsigned scale; + int maps; + + if (node->contents < 0) + return -1; // didn't hit anything + +// calculate mid point + +// FIXME: optimize for axial + plane = node->plane; + front = DotProduct (start, plane->normal) - plane->dist; + back = DotProduct (end, plane->normal) - plane->dist; + side = front < 0; + + if ( (back < 0) == side) + return RecursiveLightPoint (node->children[side], start, end); + + 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 + r = RecursiveLightPoint (node->children[side], start, mid); + if (r >= 0) + return r; // hit something + + if ( (back < 0) == side ) + return -1; // didn't hit anuthing + +// check for impact on this node + VectorCopy (mid, lightspot); + lightplane = plane; + + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->flags & SURF_DRAWTILED) + continue; // no lightmaps + + tex = surf->texinfo; + + s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; + t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];; + + if (s < surf->texturemins[0] || + t < surf->texturemins[1]) + continue; + + ds = s - surf->texturemins[0]; + dt = t - surf->texturemins[1]; + + if ( ds > surf->extents[0] || dt > surf->extents[1] ) + continue; + + if (!surf->samples) + return 0; + + ds >>= 4; + dt >>= 4; + + lightmap = surf->samples; + r = 0; + if (lightmap) + { + + lightmap += dt * ((surf->extents[0]>>4)+1) + ds; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + r += *lightmap * scale; + lightmap += ((surf->extents[0]>>4)+1) * + ((surf->extents[1]>>4)+1); + } + + r >>= 8; + } + + return r; + } + +// go down back side + return RecursiveLightPoint (node->children[!side], mid, end); +}*/ +// jkrige - .lit colored lights + + +// jkrige - .lit colored lights +vec3_t lightcolor; // jkrige - used by model rendering +int R_LightPoint (vec3_t p) +{ + vec3_t end; + + if (r_fullbright.value || !cl.worldmodel->lightdata) + { + lightcolor[0] = lightcolor[1] = lightcolor[2] = 255; + return 255; + } + + end[0] = p[0]; + end[1] = p[1]; + end[2] = p[2] - 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)); +} + +/*int R_LightPoint (vec3_t p) +{ + vec3_t end; + int r; + + if (!cl.worldmodel->lightdata) + return 255; + + end[0] = p[0]; + end[1] = p[1]; + end[2] = p[2] - 2048; + + r = RecursiveLightPoint (cl.worldmodel->nodes, p, end); + + if (r == -1) + r = 0; + + return r; +}*/ +// jkrige - .lit colored lights \ No newline at end of file diff --git a/engine/code/gl_rmain.c b/engine/code/gl_rmain.c new file mode 100644 index 0000000..a9ec689 --- /dev/null +++ b/engine/code/gl_rmain.c @@ -0,0 +1,1683 @@ +/* +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. + +*/ +// r_main.c + +#include "quakedef.h" + +// jkrige - scale2d +#ifdef _WIN32 +#include "winquake.h" +#endif +// jkrige - scale2d + +entity_t r_worldentity; + +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]; + +int c_brush_polys, c_alias_polys; + +qboolean envmap; // true during envmap command capture + +int currenttexture = -1; // to avoid unnecessary texture sets + +int cnttextures[2] = {-1, -1}; // cached + +int particletexture_linear; // little dot for particles (jkrige - was named "particletexture") + +// jkrige - texture mode +int particletexture_point; +// jkrige - texture mode + +int playertextures; // up to 16 color translated skins + +int mirrortexturenum; // quake texturenum, not gltexturenum +qboolean mirror; +mplane_t *mirror_plane; + +// +// 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]; + +// +// screen size info +// +refdef_t r_refdef; + +mleaf_t *r_viewleaf, *r_oldviewleaf; + +texture_t *r_notexture_mip; + +int d_lightstylevalue[256]; // 8.8 fraction of base light value + +// jkrige - .lit colored lights +int gl_coloredstatic; // used to store what type of static light we loaded in Mod_LoadLighting() +// jkrige - .lit colored lights + +void R_MarkLeaves (void); + +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"}; // jkrige - removed alias shadows +cvar_t r_mirroralpha = {"r_mirroralpha","1"}; +cvar_t r_wateralpha = {"r_wateralpha","1"}; +cvar_t r_dynamic = {"r_dynamic","1"}; +cvar_t r_novis = {"r_novis","0"}; + +// jkrige - fix dynamic light shine through +cvar_t r_dynamic_sidemark = {"r_dynamic_sidemark", "1", true}; +// jkrige - fix dynamic light shine through + +// jkrige - remove gl_finish +//cvar_t gl_finish = {"gl_finish","0"}; +// jkrige - remove gl_finish + +// jkrige - changed gl_clear default value +//cvar_t gl_clear = {"gl_clear", "0"}; +cvar_t gl_clear = {"gl_clear", "1", true}; +// jkrige - changed gl_clear default value + +cvar_t gl_cull = {"gl_cull","1"}; +cvar_t gl_texsort = {"gl_texsort","1"}; +cvar_t gl_smoothmodels = {"gl_smoothmodels","1"}; +cvar_t gl_affinemodels = {"gl_affinemodels","0"}; +cvar_t gl_polyblend = {"gl_polyblend","1"}; + +// jkrige - flashblend removal +//cvar_t gl_flashblend = {"gl_flashblend","1"}; +// jkrige - flashblend removal + +cvar_t gl_playermip = {"gl_playermip","0"}; +cvar_t gl_nocolors = {"gl_nocolors","0"}; + +// jkrige - disabled tjunction removal +//cvar_t gl_keeptjunctions = {"gl_keeptjunctions","0"}; +//cvar_t gl_reporttjunctions = {"gl_reporttjunctions","0"}; +// jkrige - disabled tjunction removal + +cvar_t gl_skytype = {"gl_skytype", "0"}; // jkrige - skybox : 0 = default, 1 = skybox + +cvar_t gl_doubleeyes = {"gl_doubleeys", "1"}; + +// jkrige - texture mode +cvar_t gl_texturemode = {"gl_texturemode", "0", true}; +// jkrige - texture mode + +// jkrige - wireframe +cvar_t gl_wireframe = {"gl_wireframe", "0"}; +// jkrige - wireframe + +// jkrige - .lit colored lights +cvar_t gl_coloredlight = {"gl_coloredlight", "0", true}; +// jkrige - .lit colored lights + +extern cvar_t gl_ztrick; + +/* +================= +R_CullBox + +Returns true if the box is completely outside the frustom +================= +*/ +qboolean R_CullBox (vec3_t mins, vec3_t maxs) +{ + int i; + + for (i=0 ; i<4 ; i++) + if (BoxOnPlaneSide (mins, maxs, &frustum[i]) == 2) + return true; + return false; +} + + +void R_RotateForEntity (entity_t *e) +{ + glTranslatef (e->origin[0], e->origin[1], e->origin[2]); + + glRotatef (e->angles[1], 0, 0, 1); + glRotatef (-e->angles[0], 0, 1, 0); + glRotatef (e->angles[2], 1, 0, 0); +} + +/* +============================================================= + + SPRITE MODELS + +============================================================= +*/ + +/* +================ +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 + +================= +*/ +void R_DrawSpriteModel (entity_t *e) +{ + vec3_t point; + mspriteframe_t *frame; + float *up, *right; + vec3_t v_forward, v_right, v_up; + msprite_t *psprite; + + // don't even bother culling, because it's just a single + // polygon without a surface cache + frame = R_GetSpriteFrame (e); + psprite = currententity->model->cache.data; + + if (psprite->type == SPR_ORIENTED) + { // bullet marks on walls + AngleVectors (currententity->angles, v_forward, v_right, v_up); + up = v_up; + right = v_right; + } + else + { // normal sprite + up = vup; + right = vright; + } + + glColor3f (1,1,1); + + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + GL_Bind(frame->gl_texturenum); + + glEnable (GL_ALPHA_TEST); + glBegin (GL_QUADS); + + glTexCoord2f (0, 1); + VectorMA (e->origin, frame->down, up, point); + VectorMA (point, frame->left, right, point); + glVertex3fv (point); + + glTexCoord2f (0, 0); + VectorMA (e->origin, frame->up, up, point); + VectorMA (point, frame->left, right, point); + glVertex3fv (point); + + glTexCoord2f (1, 0); + VectorMA (e->origin, frame->up, up, point); + VectorMA (point, frame->right, right, point); + glVertex3fv (point); + + glTexCoord2f (1, 1); + VectorMA (e->origin, frame->down, up, point); + VectorMA (point, frame->right, right, point); + glVertex3fv (point); + + glEnd (); + + glDisable (GL_ALPHA_TEST); +} + +/* +============================================================= + + ALIAS MODELS + +============================================================= +*/ + + +#define NUMVERTEXNORMALS 162 + +float r_avertexnormals[NUMVERTEXNORMALS][3] = { +#include "anorms.h" +}; + +// jkrige - removed alias shadows +//vec3_t shadevector; +// jkrige - removed alias shadows + +// jkrige - .lit colored lights +//float shadelight, ambientlight; +float shadelight; +// jkrige - .lit colored lights + + + +// precalculated dot products for quantized angles +#define SHADEDOT_QUANT 16 +float r_avertexnormal_dots[SHADEDOT_QUANT][256] = +#include "anorm_dots.h" +; + +float *shadedots = r_avertexnormal_dots[0]; + +// jkrige - static light vector +float cm_pitch; +float lightvec[3] = {0.0f, 0.0f, 0.0f}; +// jkrige - static light vector + + +// jkrige - light lerping +float *shadedots2 = r_avertexnormal_dots[0]; +float lightlerpoffset; +// jkrige - light lerping + + + +int lastposenum; + +// jkrige - .lit colored lights +extern vec3_t lightcolor; +// jkrige - .lit colored lights + + +// jkrige - fullbright pixels +void GL_DrawAliasFrame2 (aliashdr_t *paliashdr, int posenum, int anim, qboolean fullbrights) +{ + float s, t; + float l; + int i, j; + int index; + trivertx_t *v, *verts; + int list; + int *order; + vec3_t point; + float *normal; + int count; + + // jkrige - static light vector + float dir_light; + // jkrige - static light vector + + // jkrige - light lerping + float l1, l2, diff; + // jkrige - light lerping + + lastposenum = posenum; + + verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); + verts += posenum * paliashdr->poseverts; + order = (int *)((byte *)paliashdr + paliashdr->commands); + + if (fullbrights == true) + { + if (r_fullbright.value) + return; + + if(gl_lumatex_render.value != 1) + return; + + GL_Bind (JK_LUMA_TEX + paliashdr->gl_texturenum[currententity->skinnum][anim]); + + glDepthMask (GL_FALSE); + glEnable(GL_BLEND); + + glBlendFunc (GL_ONE, GL_ONE); + } + + while (1) + { + // get the vertex count and primitive type + count = *order++; + if (!count) + break; // done + if (count < 0) + { + count = -count; + glBegin (GL_TRIANGLE_FAN); + } + else + glBegin (GL_TRIANGLE_STRIP); + + do + { + // texture coordinates come from the draw list + glTexCoord2f (((float *)order)[0], ((float *)order)[1]); + order += 2; + + // normals and vertexes come from the frame list + + if (fullbrights == false) + { + // jkrige - static light vector + dir_light = DotProduct(r_avertexnormals[verts->lightnormalindex], lightvec); + if (dir_light > 0.0f) + { + // jkrige - light lerping + l1 = (shadedots[verts->lightnormalindex] * shadelight) + dir_light; + l2 = (shadedots2[verts->lightnormalindex] * shadelight) + dir_light; + //l = ambientlight + dir_light; + // jkrige - light lerping + } + else + { + // jkrige - light lerping + l1 = shadedots[verts->lightnormalindex] * shadelight; + l2 = shadedots2[verts->lightnormalindex] * shadelight; + //l = ambientlight; + // jkrige - light lerping + } + // jkrige - static light vector + + + // jkrige - light lerping + if (l1 != l2) + { + if (l1 > l2) + { + diff = l1 - l2; + diff *= lightlerpoffset; + l = l1 - diff; + } + else + { + diff = l2 - l1; + diff *= lightlerpoffset; + l = l1 + diff; + } + } + else + { + l = l1; + } + // jkrige - light lerping + + // jkrige - wireframe + if (gl_wireframe.value) + l = 1; + // jkrige - wireframe + + // jkrige - .lit colored lights + //l = shadedots[verts->lightnormalindex]; + glColor3f (l * lightcolor[0], l * lightcolor[1], l * lightcolor[2]); + //l = shadedots[verts->lightnormalindex] * shadelight; + //glColor3f (l, l, l); + // jkrige - .lit colored lights + } + else + { + glColor3f (1.0f, 1.0f, 1.0f); + } + + + glVertex3f (verts->v[0], verts->v[1], verts->v[2]); + verts++; + } while (--count); + + glEnd (); + } + + if (fullbrights == true) + { + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable(GL_BLEND); + glDepthMask (GL_TRUE); + } +} +// jkrige - fullbright pixels + +/* +============= +GL_DrawAliasFrame +============= +*/ +void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum, int skinnum, int anim) +{ + GL_DrawAliasFrame2(paliashdr, posenum, anim, false); + + if (paliashdr->skin_luma[skinnum] == true) + { + GL_DrawAliasFrame2(paliashdr, posenum, anim, true); + + if (paliashdr->skin_luma8bit[skinnum] == false) + GL_DrawAliasFrame2(paliashdr, posenum, anim, true); + } +} + + +/* +============= +GL_DrawAliasShadow +============= +*/ +//extern vec3_t lightspot; +// jkrige - removed alias shadows +/*void GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum) +{ + float s, t, l; + int i, j; + int index; + trivertx_t *v, *verts; + int list; + int *order; + vec3_t point; + float *normal; + float height, lheight; + int count; + + lheight = currententity->origin[2] - lightspot[2]; + + height = 0; + verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); + verts += posenum * paliashdr->poseverts; + order = (int *)((byte *)paliashdr + paliashdr->commands); + + height = -lheight + 1.0; + + while (1) + { + // get the vertex count and primitive type + count = *order++; + if (!count) + break; // done + if (count < 0) + { + count = -count; + glBegin (GL_TRIANGLE_FAN); + } + else + glBegin (GL_TRIANGLE_STRIP); + + do + { + // texture coordinates come from the draw list + // (skipped for shadows) glTexCoord2fv ((float *)order); + order += 2; + + // normals and vertexes come from the frame list + point[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0]; + point[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1]; + point[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2]; + + point[0] -= shadevector[0]*(point[2]+lheight); + point[1] -= shadevector[1]*(point[2]+lheight); + point[2] = height; +// height -= 0.001; + glVertex3fv (point); + + verts++; + } while (--count); + + glEnd (); + } +}*/ +// jkrige - removed alias shadows + + +/* +================= +R_SetupAliasFrame + +================= +*/ +void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr, int skinnum, int anim) +{ + int pose, numposes; + float interval; + + if ((frame >= paliashdr->numframes) || (frame < 0)) + { + Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); + frame = 0; + } + + pose = paliashdr->frames[frame].firstpose; + numposes = paliashdr->frames[frame].numposes; + + if (numposes > 1) + { + interval = paliashdr->frames[frame].interval; + pose += (int)(cl.time / interval) % numposes; + } + + GL_DrawAliasFrame (paliashdr, pose, skinnum, anim); +} + + +// jkrige - armabody.mdl hack +void R_DrawArmaBodyHack(entity_t *e) +{ + int i; + int anim; + aliashdr_t *paliashdr; + + if (currententity->frame == 97) + return; + + if (strcmp(currententity->model->name, "progs/armalegs.mdl")) + return; + + paliashdr = (aliashdr_t *)Mod_Extradata(currententity->model - 1); + + c_alias_polys += paliashdr->numtris; + + // + // draw all the triangles + // + + glPushMatrix(); + + R_RotateForEntity(e); + + if (!strcmp(currententity->model->name, "progs/eyes.mdl") && gl_doubleeyes.value) + { + glTranslatef(paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8)); + + // double size of eyes, since they are really hard to see in gl + glScalef(paliashdr->scale[0] * 2, paliashdr->scale[1] * 2, paliashdr->scale[2] * 2); + } + else + { + glTranslatef(paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); + glScalef(paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); + } + + anim = (int)(cl.time * 10) & 3; + GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]); + + // we can't dynamically colormap textures, so they are cached + // seperately for the players. Heads are just uncolored. + if (currententity->colormap != vid.colormap && !gl_nocolors.value) + { + i = currententity - cl_entities; + if (i >= 1 && i <= cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) + GL_Bind(playertextures - 1 + i); + } + + if (gl_smoothmodels.value) + glShadeModel(GL_SMOOTH); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + if (gl_affinemodels.value) + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + + + R_SetupAliasFrame(currententity->frame, paliashdr, currententity->skinnum, anim); + + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glShadeModel(GL_FLAT); + if (gl_affinemodels.value) + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + + glPopMatrix(); +} +// jkrige - armabody.mdl hack + + +/* +================= +R_DrawAliasModel + +================= +*/ +void R_DrawAliasModel (entity_t *e) +{ + int i, j; + int lnum; + vec3_t dist; + float add; + model_t *clmodel; + vec3_t mins, maxs; + aliashdr_t *paliashdr; + trivertx_t *verts, *v; + int index; + float s, t, an; + int anim; + + // jkrige - light lerping + float ang_ceil, ang_floor; + // jkrige - light lerping + + clmodel = currententity->model; + + VectorAdd (currententity->origin, clmodel->mins, mins); + VectorAdd (currententity->origin, clmodel->maxs, maxs); + + if (R_CullBox (mins, maxs)) + return; + + + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + // + // get lighting information + // + + // jkrige - .lit colored lights + shadelight = R_LightPoint(currententity->origin); + //ambientlight = shadelight = R_LightPoint (currententity->origin); + // jkrige - .lit colored lights + + // allways give the gun some light + // jkrige - reduced amount of minimum light on gun (view weapon) + //if (e == &cl.viewent && ambientlight < 24) + // ambientlight = shadelight = 24; + + // jkrige - .lit colored lights + if (e == &cl.viewent) + { + if (lightcolor[0] < 10) + lightcolor[0] = 10; + if (lightcolor[1] < 10) + lightcolor[1] = 10; + if (lightcolor[2] < 10) + lightcolor[2] = 10; + + if(shadelight < 8) + shadelight = 8; + } + //if (e == &cl.viewent && ambientlight < 10) + // ambientlight = shadelight = 10; + // jkrige - .lit colored lights + + // jkrige - reduced amount of minimum light on gun (view weapon) + + + // jkrige - glowing rotating items + if (currententity->model->flags & EF_ROTATE) + { + float shadelightdelta = (255.0f - shadelight) / 2.0f; + lightcolor[0] = lightcolor[1] = lightcolor[2] = shadelight + ((shadelightdelta * sin(cl.time * 3.5f)) + shadelightdelta) / 2.0f; + } + // jkrige - glowing rotating items + + + for (lnum=0 ; lnum= cl.time) + { + VectorSubtract (currententity->origin, cl_dlights[lnum].origin, dist); + add = cl_dlights[lnum].radius - Length(dist); + + // jkrige - .lit colored lights + if (add > 0) + { + lightcolor[0] += add * cl_dlights[lnum].color[0]; + lightcolor[1] += add * cl_dlights[lnum].color[1]; + lightcolor[2] += add * cl_dlights[lnum].color[2]; + + //ambientlight += add; + //ZOID models should be affected by dlights as well + //shadelight += add; + } + // jkrige - .lit colored lights + } + } + + + // jkrige - static light vector + // Set up light direction (from above) + cm_pitch = currententity->angles[PITCH] * ((float)M_PI / 180.0f); + lightvec[0] = sin(cm_pitch); + lightvec[2] = cos(cm_pitch); + // jkrige - static light vector + + + // clamp lighting so it doesn't overbright as much + // jkrige - static light vector + //if (ambientlight > 128) + // ambientlight = 128; + //if (ambientlight + shadelight > 192) + // shadelight = 192 - ambientlight; + // jkrige - static light vector + + // ZOID: never allow players to go totally black + i = currententity - cl_entities; + if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) + { + // jkrige - .lit colored lights + if (lightcolor[0] < 10) + lightcolor[0] = 10; + if (lightcolor[1] < 10) + lightcolor[1] = 10; + if (lightcolor[2] < 10) + lightcolor[2] = 10; + + if(shadelight < 8) + shadelight = 8; + //if (ambientlight < 8) + // ambientlight = shadelight = 8; + // jkrige - .lit colored lights + } + + // HACK HACK HACK -- no fullbright colors, so make torches full light + if ( + !strcmp (clmodel->name, "progs/flame2.mdl") + | !strcmp (clmodel->name, "progs/flame.mdl") + | !strcmp (clmodel->name, "progs/lavaball.mdl") // jkrige - lavaball fullbright + | !strcmp (clmodel->name, "progs/bolt.mdl") // jkrige - lightning bolt fullbright + | !strcmp (clmodel->name, "progs/bolt2.mdl") // jkrige - lightning bolt fullbright + | !strcmp (clmodel->name, "progs/bolt3.mdl") // jkrige - lightning bolt fullbright + | !strcmp (clmodel->name, "progs/k_spike.mdl") // jkrige - death knight spike fullbright + | !strcmp (clmodel->name, "progs/laser.mdl") // jkrige - enforcer laser fullbright + | !strcmp (clmodel->name, "progs/v_spike.mdl") // jkrige - vore spike fullbright + | !strcmp (clmodel->name, "progs/spike.mdl") // jkrige - nailgun spike fullbright + | !strcmp (clmodel->name, "progs/missile.mdl") // jkrige - rocket launcher missile fullbright + | !strcmp (clmodel->name, "progs/w_spike.mdl") // jkrige - scrag spike fullbright + | !strcmp (clmodel->name, "progs/b_g_key.mdl") // jkrige - b_g_key fullbright + | !strcmp (clmodel->name, "progs/b_s_key.mdl") // jkrige - b_s_key fullbright + | !strcmp (clmodel->name, "progs/m_g_key.mdl") // jkrige - b_g_key fullbright + | !strcmp (clmodel->name, "progs/m_s_key.mdl") // jkrige - b_s_key fullbright + | !strcmp (clmodel->name, "progs/w_g_key.mdl") // jkrige - w_g_key fullbright + | !strcmp (clmodel->name, "progs/w_s_key.mdl") // jkrige - w_s_key fullbright + | !strcmp (clmodel->name, "progs/boss.mdl") // jkrige - boss fullbright + | !strcmp (clmodel->name, "progs/end1.mdl") // jkrige - end1 fullbright + | !strcmp (clmodel->name, "progs/end2.mdl") // jkrige - end1 fullbright + | !strcmp (clmodel->name, "progs/end3.mdl") // jkrige - end1 fullbright + | !strcmp (clmodel->name, "progs/end4.mdl") // jkrige - end1 fullbright + ) + { + lightcolor[0] = lightcolor[1] = lightcolor[2] = 256; + shadelight = 256; + //ambientlight = shadelight = 256; + } + + + // jkrige - wireframe + if (gl_wireframe.value) + { + lightcolor[0] = lightcolor[1] = lightcolor[2] = 256; + shadelight = 256; + } + // jkrige - wireframe + + + // jkrige - light lerping + lightlerpoffset = e->angles[YAW] * (SHADEDOT_QUANT / 360.0); + ang_ceil = ceil(lightlerpoffset); + ang_floor = floor(lightlerpoffset); + + lightlerpoffset = ang_ceil - lightlerpoffset; + //shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; + shadedots = r_avertexnormal_dots[(int)ang_ceil & (SHADEDOT_QUANT - 1)]; + shadedots2 = r_avertexnormal_dots[(int)ang_floor & (SHADEDOT_QUANT - 1)]; + // jkrige - light lerping + + + // jkrige - .lit colored lights + VectorScale(lightcolor, 1.0f / 192.0f, lightcolor); + shadelight = shadelight / 192.0; + // jkrige - .lit colored lights + + + // jkrige - removed alias shadows + //an = e->angles[1]/180*M_PI; + //shadevector[0] = cos(-an); + //shadevector[1] = sin(-an); + //shadevector[2] = 1; + //VectorNormalize (shadevector); + // jkrige - removed alias shadows + + // + // locate the proper data + // + + paliashdr = (aliashdr_t *)Mod_Extradata(currententity->model); + + c_alias_polys += paliashdr->numtris; + + // + // draw all the triangles + // + + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + glPushMatrix(); + + + R_RotateForEntity(e); + + if (!strcmp(clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) + { + glTranslatef(paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8)); + + // double size of eyes, since they are really hard to see in gl + glScalef(paliashdr->scale[0] * 2, paliashdr->scale[1] * 2, paliashdr->scale[2] * 2); + } + else + { + glTranslatef(paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); + glScalef(paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); + } + + anim = (int)(cl.time * 10) & 3; + GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]); + + // we can't dynamically colormap textures, so they are cached + // seperately for the players. Heads are just uncolored. + if (currententity->colormap != vid.colormap && !gl_nocolors.value) + { + i = currententity - cl_entities; + if (i >= 1 && i <= cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) + GL_Bind(playertextures - 1 + i); + } + + if (gl_smoothmodels.value) + glShadeModel(GL_SMOOTH); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + if (gl_affinemodels.value) + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + + + R_SetupAliasFrame(currententity->frame, paliashdr, currententity->skinnum, anim); + + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glShadeModel(GL_FLAT); + if (gl_affinemodels.value) + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + + glPopMatrix(); + + // jkrige - armabody.mdl hack + R_DrawArmaBodyHack(e); + // jkrige - armabody.mdl hack + + + // jkrige - removed alias shadows + /*if (r_shadows.value) + { + glPushMatrix (); + R_RotateForEntity (e); + glDisable (GL_TEXTURE_2D); + glEnable (GL_BLEND); + glColor4f (0,0,0,0.5); + GL_DrawAliasShadow (paliashdr, lastposenum); + glEnable (GL_TEXTURE_2D); + glDisable (GL_BLEND); + glColor4f (1,1,1,1); + glPopMatrix (); + }*/ + // jkrige - removed alias shadows + +} + +//================================================================================== + +/* +============= +R_DrawEntitiesOnList +============= +*/ +void R_DrawEntitiesOnList (void) +{ + int i; + + if (!r_drawentities.value) + return; + + // draw sprites seperately, because of alpha blending + for (i=0 ; imodel->type) + { + case mod_alias: + R_DrawAliasModel (currententity); + break; + + case mod_brush: + R_DrawBrushModel (currententity); + break; + + default: + break; + } + } + + for (i=0 ; imodel->type) + { + case mod_sprite: + R_DrawSpriteModel (currententity); + break; + } + } +} + +/* +============= +R_DrawViewModel +============= +*/ +void R_DrawViewModel (void) +{ + // jkrige - weirdly enough most of the code in this function is useless + // the min lighting is already handled within the "R_DrawAliasModel" function + + // jkrige - min light level + //float ambient[4], diffuse[4]; + //int j; + // jkrige - min light level + + //int lnum; + //vec3_t dist; + //float add; + //dlight_t *dl; + + // jkrige - min light level + //int ambientlight, shadelight; + // jkrige - min light level + + if (!r_drawviewmodel.value) + return; + + // jkrige - removed chase + //if (chase_active.value) + // return; + // jkrige - removed chase + + if (envmap) + return; + + if (!r_drawentities.value) + return; + + if (cl.items & IT_INVISIBILITY) + return; + + if (cl.stats[STAT_HEALTH] <= 0) + return; + + currententity = &cl.viewent; + if (!currententity->model) + return; + + // jkrige - min light level + //j = R_LightPoint (currententity->origin); + //if (j < 24) + // j = 24; // allways give some light on gun + //ambientlight = j; + //shadelight = j; + //ambientlight = 0.75f * R_LightPoint(currententity->origin); + //ambientlight = 0.01f; + // jkrige - min light level + +// add dynamic lights + /*for (lnum=0 ; lnumradius) + continue; + if (!dl->radius) + continue; + if (dl->die < cl.time) + continue; + + VectorSubtract (currententity->origin, dl->origin, dist); + add = dl->radius - Length(dist); + if (add > 0) + ambientlight += add; + }*/ + + // jkrige - min light level + //cl.light_level = (ambientlight > 255) ? 255 : ((ambientlight < 18) ? 18 : ambientlight); + // jkrige - min light level + + //ambient[0] = ambient[1] = ambient[2] = ambient[3] = (float)ambientlight / 128; + //diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight / 128; + + // hack the depth range to prevent view model from poking into walls + glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); + R_DrawAliasModel (currententity); + glDepthRange (gldepthmin, gldepthmax); +} + + +/* +============ +R_PolyBlend +============ +*/ +// jkrige - 2D polyblend +void R_PolyBlend (void) +{ + if (!gl_polyblend.value) + return; + + if (!v_blend[3]) + return; + + glAlphaFunc(GL_ALWAYS, 0); + + glLoadIdentity (); + + glEnable (GL_BLEND); + glDisable (GL_TEXTURE_2D); + + glColor4fv (v_blend); + + glBegin (GL_QUADS); + glVertex2f (0,0); + glVertex2f (vid.width, 0); + glVertex2f (vid.width, vid.height); + glVertex2f (0, vid.height); + glEnd (); + + glColor4f (1,1,1,1); + + glEnable (GL_TEXTURE_2D); + glDisable (GL_BLEND); + + glAlphaFunc(GL_GREATER, 0.632); +} +/*void R_PolyBlend (void) +{ + if (!gl_polyblend.value) + return; + if (!v_blend[3]) + return; + + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + glDisable (GL_ALPHA_TEST); + glEnable (GL_BLEND); + glDisable (GL_DEPTH_TEST); + glDisable (GL_TEXTURE_2D); + + glLoadIdentity (); + + glRotatef (-90, 1, 0, 0); // put Z going up + glRotatef (90, 0, 0, 1); // put Z going up + + glColor4fv (v_blend); + + glBegin (GL_QUADS); + + glVertex3f (10, 100, 100); + glVertex3f (10, -100, 100); + glVertex3f (10, -100, -100); + glVertex3f (10, 100, -100); + glEnd (); + + glDisable (GL_BLEND); + glEnable (GL_TEXTURE_2D); + glEnable (GL_ALPHA_TEST); +}*/ +// jkrige - 2D polyblend + + +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< 1) + Cvar_Set ("r_fullbright", "0"); + + R_AnimateLight (); + + r_framecount++; + +// build the transformation matrix for the given view angles + VectorCopy (r_refdef.vieworg, r_origin); + + AngleVectors (r_refdef.viewangles, vpn, vright, vup); + +// current viewleaf + r_oldviewleaf = r_viewleaf; + r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel); + + V_SetContentsColor (r_viewleaf->contents); + V_CalcBlend (); + + r_cache_thrash = false; + + c_brush_polys = 0; + c_alias_polys = 0; + +} + + +void MYgluPerspective( GLdouble fovy, GLdouble aspect, + GLdouble zNear, GLdouble zFar ) +{ + GLdouble xmin, xmax, ymin, ymax; + + ymax = zNear * tan( fovy * M_PI / 360.0 ); + ymin = -ymax; + + xmin = ymin * aspect; + xmax = ymax * aspect; + + glFrustum( xmin, xmax, ymin, ymax, zNear, zFar ); +} + + +/* +============= +R_SetupGL +============= +*/ +void R_SetupGL (void) +{ + float screenaspect; + float yfov; + int i; + extern int glwidth, glheight; + int x, x2, y2, y, w, h; + + // jkrige - water warp (contents) + double f; + // jkrige - water warp (contents) + + + // + // set up viewpoint + // + glMatrixMode(GL_PROJECTION); + glLoadIdentity (); + + // jkrige - scale2d + //x = r_refdef.vrect.x * glwidth/vid.width; + //x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width; + //y = (vid.height-r_refdef.vrect.y) * glheight/vid.height; + //y2 = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height; + if (Scale2DFactor > 1.0f) + { + x = r_refdef.vrect.x * glwidth/modelist[(int)vid_mode.value].width /*320*/; + x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/modelist[(int)vid_mode.value].width /*320*/; + y = (modelist[(int)vid_mode.value].height /*200*/ -r_refdef.vrect.y) * glheight/modelist[(int)vid_mode.value].height /*200*/; + y2 = (modelist[(int)vid_mode.value].height /*200*/ - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/modelist[(int)vid_mode.value].height /*200*/; + } + else + { + // jkrige - scale2d (original) + x = r_refdef.vrect.x * glwidth/vid.width /*320*/; + x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width /*320*/; + y = (vid.height/*200*/-r_refdef.vrect.y) * glheight/vid.height /*200*/; + y2 = (vid.height/*200*/ - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height /*200*/; + // jkrige - scale2d (original) + } + // jkrige - scale2d + + + // fudge around because of frac screen scale + if (x > 0) + x--; + if (x2 < glwidth) + x2++; + if (y2 < 0) + y2--; + if (y < glheight) + y++; + + w = x2 - x; + h = y - y2; + + if (envmap) + { + x = y2 = 0; + w = h = 256; + } + + glViewport (glx + x, gly + y2, w, h); + + // jkrige - field of view (fov) fix + //screenaspect = (float)r_refdef.vrect.width/(float)r_refdef.vrect.height; + //yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI; + screenaspect = (float)vid.width/(float)vid.height; + yfov = r_refdef.fov_y; + // jkrige - field of view (fov) fix + + + // jkrige - water warp (contents) + if ((r_viewleaf->contents == CONTENTS_WATER || r_viewleaf->contents == CONTENTS_LAVA || r_viewleaf->contents == CONTENTS_SLIME)) + { + f = sin(realtime * 0.15 * (M_PI * 2.7)); + screenaspect = screenaspect - (1 - f) * 0.05 * 1; + yfov = r_refdef.fov_y - (1 + f) * 1; + } + // jkrige - water warp (contents) + + + // jkrige - updated near & far planes + MYgluPerspective (yfov, screenaspect, 2, 6144); + //MYgluPerspective (r_refdef.fov_y, screenaspect, 4, 4096); + // jkrige - updated near & far planes + + + if (mirror) + { + if (mirror_plane->normal[2]) + glScalef (1, -1, 1); + else + glScalef (-1, 1, 1); + glCullFace(GL_BACK); + } + else + glCullFace(GL_FRONT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity (); + + glRotatef (-90, 1, 0, 0); // put Z going up + glRotatef (90, 0, 0, 1); // put Z going up + glRotatef (-r_refdef.viewangles[2], 1, 0, 0); + glRotatef (-r_refdef.viewangles[0], 0, 1, 0); + glRotatef (-r_refdef.viewangles[1], 0, 0, 1); + glTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]); + + glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix); + + // + // set drawing parms + // + if (gl_cull.value) + glEnable(GL_CULL_FACE); + else + glDisable(GL_CULL_FACE); + + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glEnable(GL_DEPTH_TEST); +} + +/* +================ +R_RenderScene + +r_refdef must be set before the first call +================ +*/ +void R_RenderScene (void) +{ + R_SetupFrame (); + + R_SetFrustum (); + + R_SetupGL (); + + R_MarkLeaves (); // done here so we know if we're in water + + R_DrawWorld (); // adds static entities to the list + + S_ExtraUpdate (); // don't let sound get messed up if going slow + + R_DrawEntitiesOnList (); + + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + // jkrige - flashblend removal + //R_RenderDlights (); + // jkrige - flashblend removal + + R_DrawParticles (); + +#ifdef GLTEST + Test_Draw (); +#endif + +} + + +/* +============= +R_Clear +============= +*/ +void R_Clear (void) +{ + if (r_mirroralpha.value != 1.0) + { + if (gl_clear.value) + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + else + glClear (GL_DEPTH_BUFFER_BIT); + gldepthmin = 0; + gldepthmax = 0.5; + glDepthFunc (GL_LEQUAL); + } + else if (gl_ztrick.value) + { + static int trickframe; + + if (gl_clear.value) + glClear (GL_COLOR_BUFFER_BIT); + + trickframe++; + if (trickframe & 1) + { + gldepthmin = 0; + gldepthmax = 0.49999; + glDepthFunc (GL_LEQUAL); + } + else + { + gldepthmin = 1; + gldepthmax = 0.5; + glDepthFunc (GL_GEQUAL); + } + } + else + { + if (gl_clear.value) + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + else + glClear (GL_DEPTH_BUFFER_BIT); + gldepthmin = 0; + gldepthmax = 1; + glDepthFunc (GL_LEQUAL); + } + + glDepthRange (gldepthmin, gldepthmax); +} + +/* +============= +R_Mirror +============= +*/ +void R_Mirror (void) +{ + float d; + msurface_t *s; + entity_t *ent; + + if (!mirror) + return; + + memcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix)); + + d = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist; + VectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg); + + d = DotProduct (vpn, mirror_plane->normal); + VectorMA (vpn, -2*d, mirror_plane->normal, vpn); + + r_refdef.viewangles[0] = -asin (vpn[2])/M_PI*180; + r_refdef.viewangles[1] = atan2 (vpn[1], vpn[0])/M_PI*180; + r_refdef.viewangles[2] = -r_refdef.viewangles[2]; + + ent = &cl_entities[cl.viewentity]; + if (cl_numvisedicts < MAX_VISEDICTS) + { + cl_visedicts[cl_numvisedicts] = ent; + cl_numvisedicts++; + } + + gldepthmin = 0.5; + gldepthmax = 1; + glDepthRange (gldepthmin, gldepthmax); + glDepthFunc (GL_LEQUAL); + + R_RenderScene (); + R_DrawWaterSurfaces (); + + gldepthmin = 0; + gldepthmax = 0.5; + glDepthRange (gldepthmin, gldepthmax); + glDepthFunc (GL_LEQUAL); + + // blend on top + glEnable (GL_BLEND); + glMatrixMode(GL_PROJECTION); + if (mirror_plane->normal[2]) + glScalef (1,-1,1); + else + glScalef (-1,1,1); + glCullFace(GL_FRONT); + glMatrixMode(GL_MODELVIEW); + + glLoadMatrixf (r_base_world_matrix); + + glColor4f (1,1,1,r_mirroralpha.value); + s = cl.worldmodel->textures[mirrortexturenum]->texturechain; + for ( ; s ; s=s->texturechain) + R_RenderBrushPoly (s); + cl.worldmodel->textures[mirrortexturenum]->texturechain = NULL; + glDisable (GL_BLEND); + glColor4f (1,1,1,1); +} + +/* +================ +R_RenderView + +r_refdef must be set before the first call +================ +*/ +void R_RenderView (void) +{ + double time1, time2; + GLfloat colors[4] = {(GLfloat) 0.0, (GLfloat) 0.0, (GLfloat) 1, (GLfloat) 0.20}; + + if (r_norefresh.value) + return; + + if (!r_worldentity.model || !cl.worldmodel) + Sys_Error ("R_RenderView: NULL worldmodel"); + + if (r_speeds.value) + { + glFinish (); + time1 = Sys_FloatTime (); + c_brush_polys = 0; + c_alias_polys = 0; + } + + mirror = false; + + // jkrige - remove gl_finish + //if (gl_finish.value) + // glFinish (); + // jkrige - remove gl_finish + + // jkrige - scale2d + COM_SetScale2D(); + // jkrige - scale2d + + R_Clear (); + + // render normal view + + /***** Experimental silly looking fog ****** + ****** Use r_fullbright if you enable ****** + glFogi(GL_FOG_MODE, GL_LINEAR); + glFogfv(GL_FOG_COLOR, colors); + glFogf(GL_FOG_END, 512.0); + glEnable(GL_FOG); + ********************************************/ + + + // jkrige - wireframe + if (gl_wireframe.value != 0.0f && gl_wireframe.value != 1.0f) + Cvar_Set("gl_wireframe", "0"); + + if (cl.gametype == GAME_DEATHMATCH) + Cvar_Set("gl_wireframe", "0"); + + if (gl_wireframe.value) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + // jkrige - wireframe + + + R_RenderScene (); + R_DrawViewModel (); + R_DrawWaterSurfaces (); + +// More fog right here :) +// glDisable(GL_FOG); +// End of all fog code... + + // render mirror view + R_Mirror (); + + // jkrige - 2D polyblend + //R_PolyBlend (); + // jkrige - 2D polyblend + + // jkrige - wireframe + if (gl_wireframe.value) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + // jkrige - wireframe + + if (r_speeds.value) + { +// glFinish (); + time2 = Sys_FloatTime (); + Con_Printf ("%3i ms %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys); + } +} diff --git a/engine/code/gl_rmisc.c b/engine/code/gl_rmisc.c new file mode 100644 index 0000000..b18f894 --- /dev/null +++ b/engine/code/gl_rmisc.c @@ -0,0 +1,543 @@ +/* +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. + +*/ +// r_misc.c + +#include "quakedef.h" + + + +/* +================== +R_InitTextures +================== +*/ +void R_InitTextures (void) +{ + int x,y, m; + byte *dest; + +// create a simple checkerboard texture for the default + r_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture"); + + r_notexture_mip->width = r_notexture_mip->height = 16; + r_notexture_mip->offsets[0] = sizeof(texture_t); + r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16; + r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8; + r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4; + + for (m=0 ; m<4 ; m++) + { + dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m]; + for (y=0 ; y< (16>>m) ; y++) + for (x=0 ; x< (16>>m) ; x++) + { + if ( (y< (8>>m) ) ^ (x< (8>>m) ) ) + *dest++ = 0; + else + *dest++ = 0xff; + } + } +} + +byte dottexture[8][8] = +{ + {0,1,1,0,0,0,0,0}, + {1,1,1,1,0,0,0,0}, + {1,1,1,1,0,0,0,0}, + {0,1,1,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, +}; + +// jkrige - texture mode +byte dottexture_point[8][8] = +{ + {1,1,1,0,0,0,0,0}, + {1,1,1,0,0,0,0,0}, + {1,1,1,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, +}; + +void R_InitParticleTexture_Linear (void) +{ + int x,y; + byte data[8][8][4]; + + // + // particle texture + // + particletexture_linear = texture_extension_number++; + GL_Bind(particletexture_linear); + + for (x=0 ; x<8 ; x++) + { + for (y=0 ; y<8 ; y++) + { + data[y][x][0] = 255; + data[y][x][1] = 255; + data[y][x][2] = 255; + data[y][x][3] = dottexture[x][y]*255; + } + } + glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +} + +void R_InitParticleTexture_Point (void) +{ + int x,y; + byte data[8][8][4]; + + // + // particle texture + // + particletexture_point = texture_extension_number++; + GL_Bind(particletexture_point); + + for (x=0 ; x<8 ; x++) + { + for (y=0 ; y<8 ; y++) + { + data[y][x][0] = 255; + data[y][x][1] = 255; + data[y][x][2] = 255; + data[y][x][3] = dottexture_point[x][y]*255; + } + } + glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +} + +void R_InitParticleTexture (void) +{ + R_InitParticleTexture_Point(); + R_InitParticleTexture_Linear(); +} +// jkrige - texture mode + +/* +=============== +R_Envmap_f + +Grab six views for environment mapping tests +=============== +*/ +void R_Envmap_f (void) +{ + byte buffer[256*256*4]; + char name[1024]; + + 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; + + // jkrige - remove gl_finish + //extern cvar_t gl_finish; + // jkrige - remove gl_finish + + Cmd_AddCommand ("timerefresh", R_TimeRefresh_f); + Cmd_AddCommand ("envmap", R_Envmap_f); + Cmd_AddCommand ("pointfile", R_ReadPointFile_f); + + Cvar_RegisterVariable (&r_norefresh); + Cvar_RegisterVariable (&r_lightmap); + Cvar_RegisterVariable (&r_fullbright); + Cvar_RegisterVariable (&r_drawentities); + Cvar_RegisterVariable (&r_drawviewmodel); + //Cvar_RegisterVariable (&r_shadows); // jkrige - removed alias shadows + Cvar_RegisterVariable (&r_mirroralpha); + Cvar_RegisterVariable (&r_wateralpha); + Cvar_RegisterVariable (&r_dynamic); + Cvar_RegisterVariable (&r_novis); + Cvar_RegisterVariable (&r_speeds); + + // jkrige - fix dynamic light shine through + Cvar_RegisterVariable (&r_dynamic_sidemark); + // jkrige - fix dynamic light shine through + + // jkrige - remove gl_finish + //Cvar_RegisterVariable (&gl_finish); + // jkrige - remove gl_finish + + Cvar_RegisterVariable (&gl_clear); + Cvar_RegisterVariable (&gl_texsort); + + // jkrige - remove multitexture + //if (gl_mtexable) + // Cvar_SetValue ("gl_texsort", 0.0); + // jkrige - remove multitexture + + Cvar_RegisterVariable (&gl_cull); + Cvar_RegisterVariable (&gl_smoothmodels); + Cvar_RegisterVariable (&gl_affinemodels); + Cvar_RegisterVariable (&gl_polyblend); + + // jkrige - flashblend removal + //Cvar_RegisterVariable (&gl_flashblend); + // jkrige - flashblend removal + + + Cvar_RegisterVariable (&gl_playermip); + Cvar_RegisterVariable (&gl_nocolors); + + // jkrige - disabled tjunction removal + //Cvar_RegisterVariable (&gl_keeptjunctions); + //Cvar_RegisterVariable (&gl_reporttjunctions); + // jkrige - disabled tjunction removal + + Cvar_RegisterVariable (&gl_skytype); // jkrige - skybox + + Cvar_RegisterVariable (&gl_doubleeyes); + + // jkrige - texture mode + Cvar_RegisterVariable (&gl_texturemode); + // jkrige - texture mode + + // jkrige - wireframe + Cvar_RegisterVariable(&gl_wireframe); + // jkrige - wireframe + + // jkrige - .lit colored lights + Cvar_RegisterVariable (&gl_lightmapfmt); + Cvar_RegisterVariable (&gl_coloredlight); + // jkrige - .lit colored lights + + R_InitParticles (); + R_InitParticleTexture (); + +#ifdef GLTEST + Test_Init (); +#endif + + playertextures = texture_extension_number; + texture_extension_number += 16; +} + +/* +=============== +R_TranslatePlayerSkin + +Translates a skin texture by the per-player color lookup +=============== +*/ +void R_TranslatePlayerSkin (int playernum) +{ + int top, bottom; + byte translate[256]; + unsigned translate32[256]; + int i, j, s; + model_t *model; + aliashdr_t *paliashdr; + byte *original; + unsigned pixels[512*256], *out; + unsigned scaled_width, scaled_height; + int inwidth, inheight; + byte *inrow; + unsigned frac, fracstep; + extern byte **player_8bit_texels_tbl; + + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + top = cl.scores[playernum].colors & 0xf0; + bottom = (cl.scores[playernum].colors &15)<<4; + + for (i=0 ; i<256 ; i++) + translate[i] = i; + + for (i=0 ; i<16 ; i++) + { + if (top < 128) // the artists made some backwards ranges. sigh. + translate[TOP_RANGE+i] = top+i; + else + translate[TOP_RANGE+i] = top+15-i; + + if (bottom < 128) + translate[BOTTOM_RANGE+i] = bottom+i; + else + translate[BOTTOM_RANGE+i] = bottom+15-i; + } + + // + // locate the original skin pixels + // + currententity = &cl_entities[1+playernum]; + model = currententity->model; + if (!model) + return; // player doesn't have a model yet + if (model->type != mod_alias) + return; // only translate skins on alias models + + paliashdr = (aliashdr_t *)Mod_Extradata (model); + s = paliashdr->skinwidth * paliashdr->skinheight; + if (currententity->skinnum < 0 || currententity->skinnum >= paliashdr->numskins) { + Con_Printf("(%d): Invalid player skin #%d\n", playernum, currententity->skinnum); + original = (byte *)paliashdr + paliashdr->texels[0]; + } else + original = (byte *)paliashdr + paliashdr->texels[currententity->skinnum]; + if (s & 3) + Sys_Error ("R_TranslateSkin: s&3"); + + inwidth = paliashdr->skinwidth; + inheight = paliashdr->skinheight; + + // because this happens during gameplay, do it fast + // instead of sending it through gl_upload 8 + GL_Bind(playertextures + playernum); + +#if 0 + byte translated[320*200]; + + for (i=0 ; iskinwidth, paliashdr->skinheight, false, false, true); +#else + scaled_width = gl_max_size.value < 512 ? gl_max_size.value : 512; + scaled_height = gl_max_size.value < 256 ? gl_max_size.value : 256; + + // allow users to crunch sizes down even more if they want + scaled_width >>= (int)gl_playermip.value; + scaled_height >>= (int)gl_playermip.value; + + // jkrige - no 8bit palette extensions + /*if (VID_Is8bit()) { // 8bit texture upload + byte *out2; + + out2 = (byte *)pixels; + memset(pixels, 0, sizeof(pixels)); + fracstep = inwidth*0x10000/scaled_width; + for (i=0 ; i> 1; + for (j=0 ; j>16]]; + frac += fracstep; + out2[j+1] = translate[inrow[frac>>16]]; + frac += fracstep; + out2[j+2] = translate[inrow[frac>>16]]; + frac += fracstep; + out2[j+3] = translate[inrow[frac>>16]]; + frac += fracstep; + } + } + + GL_Upload8_EXT ((byte *)pixels, scaled_width, scaled_height, false, false); + return; + }*/ + // jkrige - no 8bit palette extensions + + for (i=0 ; i<256 ; i++) + translate32[i] = d_8to24table[translate[i]]; + + out = pixels; + fracstep = inwidth*0x10000/scaled_width; + for (i=0 ; i> 1; + for (j=0 ; j>16]]; + frac += fracstep; + out[j+1] = translate32[inrow[frac>>16]]; + frac += fracstep; + out[j+2] = translate32[inrow[frac>>16]]; + frac += fracstep; + out[j+3] = translate32[inrow[frac>>16]]; + frac += fracstep; + } + } + glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#endif + +} + + +/* +=============== +R_NewMap +=============== +*/ +void R_NewMap (void) +{ + int i; + + for (i=0 ; i<256 ; i++) + d_lightstylevalue[i] = 264; // normal light value + + memset (&r_worldentity, 0, sizeof(r_worldentity)); + r_worldentity.model = cl.worldmodel; + +// clear out efrags in case the level hasn't been reloaded +// FIXME: is this one short? + for (i=0 ; inumleafs ; i++) + cl.worldmodel->leafs[i].efrags = NULL; + + r_viewleaf = NULL; + R_ClearParticles (); + + GL_BuildLightmaps (); + + // identify sky texture + skytexturenum = -1; + mirrortexturenum = -1; + for (i=0 ; inumtextures ; i++) + { + if (!cl.worldmodel->textures[i]) + continue; + if (!Q_strncmp(cl.worldmodel->textures[i]->name,"sky",3) ) + skytexturenum = i; + if (!Q_strncmp(cl.worldmodel->textures[i]->name,"window02_1",10) ) + mirrortexturenum = i; + cl.worldmodel->textures[i]->texturechain = NULL; + } +//#ifdef QUAKE2 // jkrige - skybox +// R_LoadSkys (); +//#endif +} + + +/* +==================== +R_TimeRefresh_f + +For program optimization +==================== +*/ +void R_TimeRefresh_f (void) +{ + int i; + float start, stop, time; + 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/engine/code/gl_rsurf.c b/engine/code/gl_rsurf.c new file mode 100644 index 0000000..3c59de9 --- /dev/null +++ b/engine/code/gl_rsurf.c @@ -0,0 +1,2230 @@ +/* +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. + +*/ +// r_surf.c: surface-related refresh code + +#include "quakedef.h" + +int skytexturenum; + +#ifndef GL_RGBA4 +#define GL_RGBA4 0 +#endif + + +// jkrige - .lit colored lights +int gl_lightmap_format = GL_RGBA; +cvar_t gl_lightmapfmt = {"gl_lightmapfmt", "GL_RGBA", true}; +int lightmap_bytes = 4; // 1, 2, or 4. default is 4 for GL_RGBA +GLuint lightmap_textures; +//int lightmap_bytes; // 1, 2, or 4 +//int lightmap_textures; +// jkrige - .lit colored lights + + +unsigned blocklights[18*18]; + +// jkrige - .lit colored lights +static unsigned int blocklightscolor[18*18*3]; // colored light support. *3 for RGB to the definitions at the top +// jkrige - .lit colored lights + +#define BLOCK_WIDTH 128 +#define BLOCK_HEIGHT 128 + +#define MAX_LIGHTMAPS 64 +int active_lightmaps; + +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]; + +// For gl_texsort 0 +msurface_t *skychain = NULL; +msurface_t *waterchain = NULL; + +void R_RenderDynamicLightmaps (msurface_t *fa); + +/* +=============== +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; + + // jkrige - .lit colored lights + float cred, cgreen, cblue, brightness; + unsigned int *bl; + // jkrige - .lit colored lights + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=0 ; lnumdlightbits & (1<dlightbits[(lnum >> 3)] & (1 << (lnum & 7)))) + continue; + // jkrige - increase dlights + + rad = cl_dlights[lnum].radius; + dist = DotProduct (cl_dlights[lnum].origin, surf->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]; + + + // jkrige - .lit colored lights + bl = blocklightscolor; + cred = cl_dlights[lnum].color[0] * 256.0f; + cgreen = cl_dlights[lnum].color[1] * 256.0f; + cblue = cl_dlights[lnum].color[2] * 256.0f; + + for (t = 0; t < tmax; t++) + { + td = local[1] - t*16; + if (td < 0) + td = -td; + for (s = 0; s < smax; s++) + { + sd = local[0] - s*16; + if (sd < 0) + sd = -sd; + if (sd > td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); + if (dist < minlight) + { + brightness = rad - dist; + bl[0] += (int) (brightness * cred); + bl[1] += (int) (brightness * cgreen); + bl[2] += (int) (brightness * cblue); + + blocklights[t*smax + s] += (rad - dist)*256; + } + + bl += 3; + } + } + /*for (t = 0 ; t td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); + if (dist < minlight) + blocklights[t*smax + s] += (rad - dist)*256; + } + }*/ + // jkrige - .lit colored lights + } +} + + +// jkrige - .lit colored lights +/* +=============== +GL_SetupLightmapFmt + +Used to setup the lightmap_format and lightmap_bytes +at every level change and at first video initialization. +Best to be called from Mod_LoadLighting() in gl_model.c +=============== +*/ +void GL_SetupLightmapFmt (qboolean check_cmdline) +{ + // only GL_LUMINANCE and GL_RGBA are actually supported + // commenting out other options + if (!Q_strcasecmp(gl_lightmapfmt.string, "GL_LUMINANCE")) + gl_lightmap_format = GL_LUMINANCE; + else if (!Q_strcasecmp(gl_lightmapfmt.string, "GL_RGBA")) + gl_lightmap_format = GL_RGBA; +#if 0 + else if (!Q_strcasecmp(gl_lightmapfmt.string, "GL_ALPHA")) + gl_lightmap_format = GL_ALPHA; + else if (!Q_strcasecmp(gl_lightmapfmt.string, "GL_INTENSITY")) + gl_lightmap_format = GL_INTENSITY; +#endif + else + { + gl_lightmap_format = GL_RGBA; + Cvar_Set ("gl_lightmapfmt", "GL_RGBA"); + } + + // check for commandline overrides + if (check_cmdline) + { + if (COM_CheckParm ("-lm_1")) + { + gl_lightmap_format = GL_LUMINANCE; + Cvar_Set ("gl_lightmapfmt", "GL_LUMINANCE"); + } + else if (COM_CheckParm ("-lm_4")) + { + gl_lightmap_format = GL_RGBA; + Cvar_Set ("gl_lightmapfmt", "GL_RGBA"); + } +#if 0 +// else if (COM_CheckParm ("-lm_2")) +// { +// gl_lightmap_format = GL_RGBA4; +// Cvar_Set ("gl_lightmapfmt", "GL_RGBA4"); +// } + else if (COM_CheckParm ("-lm_a")) + { + gl_lightmap_format = GL_ALPHA; + Cvar_Set ("gl_lightmapfmt", "GL_ALPHA"); + } + else if (COM_CheckParm ("-lm_i")) + { + gl_lightmap_format = GL_INTENSITY; + Cvar_Set ("gl_lightmapfmt", "GL_INTENSITY"); + } +#endif + } + + switch (gl_lightmap_format) + { + case GL_RGBA: + lightmap_bytes = 4; + break; +// case GL_RGBA4: +// lightmap_bytes = 2; +// break; + case GL_LUMINANCE: + case GL_INTENSITY: + case GL_ALPHA: + lightmap_bytes = 1; + break; + } +} +// jkrige - .lit colored lights + + +/* +=============== +R_BuildLightMap + +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; + // jkrige - .lit colored lights + int r, s, q; + // jkrige - .lit colored lights + int i, j, size; + byte *lightmap; + unsigned scale; + int maps; + //int lightadj[4]; + + // jkrige - .lit colored lights + //unsigned *bl; + unsigned int *bl, *blcr, *blcg, *blcb; + // jkrige - .lit colored lights + + // jkrige - overbrights + int lightshift; + + if (gl_overbright.value) + lightshift = 8; + else + lightshift = 7; + // jkrige - overbrights + + + 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; + +// set to full bright if no light data + if (r_fullbright.value || !cl.worldmodel->lightdata) + { + // jkrige - .lit colored lights + for (i = 0; i < size; i++) + { + if (gl_lightmap_format == GL_RGBA) + blocklightscolor[i*3+0] = + blocklightscolor[i*3+1] = + blocklightscolor[i*3+2] = 65280; + else + blocklights[i] = 255*256; + } + //for (i=0 ; istyles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + + // jkrige - .lit colored lights + if (gl_lightmap_format == GL_RGBA) + { + for (i = 0, j = 0; i < size; i++) + { + blocklightscolor[i*3+0] += lightmap[j] * scale; + blocklightscolor[i*3+1] += lightmap[++j] * scale; + blocklightscolor[i*3+2] += lightmap[++j] * scale; + j++; + } + + lightmap += size * 3; + } + else + { + for (i = 0; i < size; i++) + blocklights[i] += lightmap[i] * scale; + lightmap += size; // skip to next lightmap + } + //for (i=0 ; idlightframe == r_framecount) + R_AddDynamicLights (surf); + +// bound, invert, and shift +store: + switch (gl_lightmap_format) + { + case GL_RGBA: + stride -= (smax<<2); + + // jkrige - .lit colored lights + blcr = &blocklightscolor[0]; + blcg = &blocklightscolor[1]; + blcb = &blocklightscolor[2]; + //bl = blocklights; + // jkrige - .lit colored lights + + for (i=0 ; i>= 7; + q >>= lightshift; + // jkrige - overbrights + + r = *blcg; + // jkrige - overbrights + //r >>= 7; + r >>= lightshift; + // jkrige - overbrights + + s = *blcb; + // jkrige - overbrights + //s >>= 7; + s >>= lightshift; + // jkrige - overbrights + + if (q > 255) + q = 255; + if (r > 255) + r = 255; + if (s > 255) + s = 255; + + if (gl_coloredlight.value == 1) + { + dest[0] = q; //255 - q; + dest[1] = r; //255 - r; + dest[2] = s; //255 - s; + dest[3] = 255; //(q+r+s)/3; + } + else + { + t = (int) ( ((float)q * 0.33f) + ((float)s * 0.33f) + ((float)r * 0.33f) ); + + if (t > 255) + t = 255; + dest[0] = t; + dest[1] = t; + dest[2] = t; + dest[3] = 255; //t; + } + + dest += 4; + + blcr += 3; + blcg += 3; + blcb += 3; + + //t = *bl++; + //t >>= 7; + //if (t > 255) + // t = 255; + //dest[3] = 255-t; + //dest += 4; + // jkrige - .lit colored lights + } + } + break; + case GL_ALPHA: + case GL_LUMINANCE: + case GL_INTENSITY: + bl = blocklights; + for (i=0 ; i>= 7; + t >>= lightshift; + // jkrige - overbrights + if (t > 255) + t = 255; + dest[j] = 255-t; + } + } + break; + default: + Sys_Error ("Bad lightmap format"); + } +} + + +/* +=============== +R_TextureAnimation + +Returns the proper texture for a given time and base texture +=============== +*/ +texture_t *R_TextureAnimation (texture_t *base) +{ + int reletive; + int count; + + if (currententity->frame) + { + if (base->alternate_anims) + base = base->alternate_anims; + } + + if (!base->anim_total) + return base; + + reletive = (int)(cl.time*10) % base->anim_total; + + count = 0; + while (base->anim_min > reletive || base->anim_max <= reletive) + { + base = base->anim_next; + if (!base) + Sys_Error ("R_TextureAnimation: broken cycle"); + if (++count > 100) + Sys_Error ("R_TextureAnimation: infinite cycle"); + } + + return base; +} + + +/* +============================================================= + + BRUSH MODELS + +============================================================= +*/ + + +extern int solidskytexture; +extern int alphaskytexture; +extern float speedscale; // for top sky and bottom sky + +void DrawGLWaterPoly (glpoly_t *p); +void DrawGLWaterPolyLightmap (glpoly_t *p); + +// jkrige - remove multitexture +/*lpMTexFUNC qglMTexCoord2fSGIS = NULL; +lpSelTexFUNC qglSelectTextureSGIS = NULL; + +qboolean mtexenabled = false; + +void GL_SelectTexture (GLenum target); + +void GL_DisableMultitexture(void) +{ + if (mtexenabled) { + glDisable(GL_TEXTURE_2D); + GL_SelectTexture(TEXTURE0_SGIS); + mtexenabled = false; + } +} + +void GL_EnableMultitexture(void) +{ + if (gl_mtexable) { + GL_SelectTexture(TEXTURE1_SGIS); + glEnable(GL_TEXTURE_2D); + mtexenabled = true; + } +}*/ +// jkrige - remove multitexture + +#if 0 +/* +================ +R_DrawSequentialPoly + +Systems that have fast state and texture changes can +just do everything as it passes with no need to sort +================ +*/ +void R_DrawSequentialPoly (msurface_t *s) +{ + glpoly_t *p; + float *v; + int i; + texture_t *t; + + // + // normal lightmaped poly + // + if (! (s->flags & (SURF_DRAWSKY|SURF_DRAWTURB/*|SURF_UNDERWATER*/) ) ) // jkrige - waterwarp removal + { + p = s->polys; + + t = R_TextureAnimation (s->texinfo->texture); + GL_Bind (t->gl_texturenum); + glBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (v[3], v[4]); + glVertex3fv (v); + } + glEnd (); + + GL_Bind (lightmap_textures + s->lightmaptexturenum); + glEnable (GL_BLEND); + glBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (v[5], v[6]); + glVertex3fv (v); + } + glEnd (); + + glDisable (GL_BLEND); + + return; + } + + // + // subdivided water surface warp + // + if (s->flags & SURF_DRAWTURB) + { + GL_Bind (s->texinfo->texture->gl_texturenum); + EmitWaterPolys (s); + return; + } + + // + // subdivided sky warp + // + if (s->flags & SURF_DRAWSKY) + { + GL_Bind (solidskytexture); + speedscale = realtime*8; + speedscale -= (int)speedscale; + + EmitSkyPolys (s); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_Bind (alphaskytexture); + speedscale = realtime*16; + speedscale -= (int)speedscale; + EmitSkyPolys (s); + if (gl_lightmap_format == GL_LUMINANCE) + glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + + glDisable (GL_BLEND); + } + + // + // underwater warped with lightmap + // + p = s->polys; + + t = R_TextureAnimation (s->texinfo->texture); + GL_Bind (t->gl_texturenum); + DrawGLWaterPoly (p); + + GL_Bind (lightmap_textures + s->lightmaptexturenum); + glEnable (GL_BLEND); + DrawGLWaterPolyLightmap (p); + glDisable (GL_BLEND); +} +#else +/* +================ +R_DrawSequentialPoly + +Systems that have fast state and texture changes can +just do everything as it passes with no need to sort +================ +*/ +void R_DrawSequentialPoly (msurface_t *s) +{ + glpoly_t *p; + float *v; + int i; + texture_t *t; + vec3_t nv, dir; + float ss, ss2, length; + float s1, t1; + glRect_t *theRect; + + // + // normal lightmaped poly + // + + if (! (s->flags & (SURF_DRAWSKY|SURF_DRAWTURB/*|SURF_UNDERWATER*/) ) ) // jkrige - waterwarp removal + { + R_RenderDynamicLightmaps (s); + /*if (gl_mtexable) { // jkrige - remove multitexture + p = s->polys; + + t = R_TextureAnimation (s->texinfo->texture); + // Binds world to texture env 0 + GL_SelectTexture(TEXTURE0_SGIS); + GL_Bind (t->gl_texturenum); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + // Binds lightmap to texenv 1 + GL_EnableMultitexture(); // Same as SelectTexture (TEXTURE1) + GL_Bind (lightmap_textures + s->lightmaptexturenum); + i = s->lightmaptexturenum; + if (lightmap_modified[i]) + { + lightmap_modified[i] = false; + theRect = &lightmap_rectchange[i]; + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, + BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, + lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes); + theRect->l = BLOCK_WIDTH; + theRect->t = BLOCK_HEIGHT; + theRect->h = 0; + theRect->w = 0; + } + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); + glBegin(GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]); + qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]); + glVertex3fv (v); + } + glEnd (); + return; + } else {*/ // jkrige - remove multitexture + p = s->polys; + + t = R_TextureAnimation (s->texinfo->texture); + GL_Bind (t->gl_texturenum); + glBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (v[3], v[4]); + glVertex3fv (v); + } + glEnd (); + + GL_Bind (lightmap_textures + s->lightmaptexturenum); + glEnable (GL_BLEND); + + // jkrige - .lit colored lights + if (gl_lightmap_format == GL_LUMINANCE) + { + glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + } + else if (gl_lightmap_format == GL_INTENSITY) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f (0.0f,0.0f,0.0f,1.0f); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else if (gl_lightmap_format == GL_RGBA) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f (1.0f,1.0f,1.0f, 1.0f); + glBlendFunc(GL_ZERO, GL_SRC_COLOR); + } + // jkrige - .lit colored lights + + glBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (v[5], v[6]); + glVertex3fv (v); + } + glEnd (); + + glDisable (GL_BLEND); + //} // jkrige - remove multitexture + + return; + } + + // + // subdivided water surface warp + // + + if (s->flags & SURF_DRAWTURB) + { + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + GL_Bind (s->texinfo->texture->gl_texturenum); + EmitWaterPolys (s); + return; + } + + // + // subdivided sky warp + // + if (s->flags & SURF_DRAWSKY) + { + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + GL_Bind (solidskytexture); + speedscale = realtime*8; + speedscale -= (int)speedscale & ~127; + EmitSkyPolys (s); + + glEnable (GL_BLEND); + GL_Bind (alphaskytexture); + speedscale = realtime*16; + speedscale -= (int)speedscale & ~127; + EmitSkyPolys (s); + + glDisable (GL_BLEND); + return; + } + + // + // underwater warped with lightmap + // + R_RenderDynamicLightmaps (s); + /*if (gl_mtexable) { // jkrige - remove multitexture + p = s->polys; + + t = R_TextureAnimation (s->texinfo->texture); + GL_SelectTexture(TEXTURE0_SGIS); + GL_Bind (t->gl_texturenum); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + GL_EnableMultitexture(); + GL_Bind (lightmap_textures + s->lightmaptexturenum); + i = s->lightmaptexturenum; + if (lightmap_modified[i]) + { + lightmap_modified[i] = false; + theRect = &lightmap_rectchange[i]; + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, + BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, + lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes); + theRect->l = BLOCK_WIDTH; + theRect->t = BLOCK_HEIGHT; + theRect->h = 0; + theRect->w = 0; + } + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); + glBegin (GL_TRIANGLE_FAN); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]); + qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]); + + nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime); + nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime); + nv[2] = v[2]; + + glVertex3fv (nv); + } + glEnd (); + + } else {*/ // jkrige - remove multitexture + p = s->polys; + + t = R_TextureAnimation (s->texinfo->texture); + GL_Bind (t->gl_texturenum); + DrawGLWaterPoly (p); + + GL_Bind (lightmap_textures + s->lightmaptexturenum); + glEnable (GL_BLEND); + + // jkrige - .lit colored lights + if (gl_lightmap_format == GL_LUMINANCE) + { + glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + } + else if (gl_lightmap_format == GL_INTENSITY) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f (0.0f,0.0f,0.0f,1.0f); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else if (gl_lightmap_format == GL_RGBA) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f (1.0f,1.0f,1.0f, 1.0f); + glBlendFunc(GL_ZERO, GL_SRC_COLOR); + } + // jkrige - .lit colored lights + + DrawGLWaterPolyLightmap (p); + glDisable (GL_BLEND); + + // jkrige - .lit colored lights + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + // jkrige - .lit colored lights + + // jkrige - luma textures + s->luma_mark = true; + // jkrige - luma textures + + + //} // jkrige - remove multitexture +} +#endif + + +/* +================ +DrawGLWaterPoly + +Warp the vertex coordinates +================ +*/ +void DrawGLWaterPoly (glpoly_t *p) +{ + int i; + float *v; + float s, t, os, ot; + vec3_t nv; + + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + glBegin (GL_TRIANGLE_FAN); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (v[3], v[4]); + + // jkrige - waterwarp removal + nv[0] = v[0]; // + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime); + nv[1] = v[1]; // + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime); + nv[2] = v[2]; + // jkrige - waterwarp removal + + glVertex3fv (nv); + } + glEnd (); +} + +void DrawGLWaterPolyLightmap (glpoly_t *p) +{ + int i; + float *v; + float s, t, os, ot; + vec3_t nv; + + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + glBegin (GL_TRIANGLE_FAN); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (v[5], v[6]); + + // jkrige - waterwarp removal + nv[0] = v[0]; // + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime); + nv[1] = v[1]; // + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime); + nv[2] = v[2]; + // jkrige - waterwarp removal + + glVertex3fv (nv); + } + glEnd (); +} + +/* +================ +DrawGLPoly +================ +*/ +void DrawGLPoly (glpoly_t *p) +{ + int i; + float *v; + + glBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (v[3], v[4]); + glVertex3fv (v); + } + glEnd (); +} + + +/* +================ +R_BlendLightmaps +================ +*/ +void R_BlendLightmaps (void) +{ + int i, j; + glpoly_t *p; + float *v; + glRect_t *theRect; + + if (r_fullbright.value) + return; + + // jkrige - wireframe + if (gl_wireframe.value) + return; + // jkrige - wireframe + + if (!gl_texsort.value) + return; + + glDepthMask (0); // don't bother writing Z + + if (gl_lightmap_format == GL_LUMINANCE) + { + glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + } + else if (gl_lightmap_format == GL_INTENSITY) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f (0,0,0,1); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + // jkrige - .lit colored lights + else if (gl_lightmap_format == GL_RGBA) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f (1.0f,1.0f,1.0f, 1.0f); + //glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + glBlendFunc(GL_ZERO, GL_SRC_COLOR); + } + // jkrige - .lit colored lights + + + // jkrige - overbrights + if (gl_overbright.value) + glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + // jkrige - overbrights + + if (!r_lightmap.value) + { + glEnable (GL_BLEND); + } + + for (i=0 ; ih, 0, +// gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+(i*BLOCK_HEIGHT+theRect->t)*BLOCK_WIDTH*lightmap_bytes); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, + BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, + lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes); + theRect->l = BLOCK_WIDTH; + theRect->t = BLOCK_HEIGHT; + theRect->h = 0; + theRect->w = 0; + } + for ( ; p ; p=p->chain) + { + if (p->flags & SURF_UNDERWATER) + DrawGLWaterPolyLightmap (p); + else + { + glBegin (GL_POLYGON); + v = p->verts[0]; + for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) + { + glTexCoord2f (v[5], v[6]); + glVertex3fv (v); + } + glEnd (); + } + } + } + + glDisable (GL_BLEND); + /* + if (gl_lightmap_format == GL_LUMINANCE) + { + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else if (gl_lightmap_format == GL_INTENSITY) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glColor4f (1,1,1,1); + } + // jkrige - .lit colored lights + else if (gl_lightmap_format == GL_RGBA) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + // jkrige - .lit colored lights + */ + + // jkrige - .lit colored lights + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glColor4f (1,1,1,1); + // jkrige - .lit colored lights + + glDepthMask (1); // back to normal Z buffering +} + +// jkrige - luma textures +void R_DrawLumaSurfaces (msurface_t *s, int num_surfaces) +{ + int i; + msurface_t *fa; + texture_t *t; + qboolean luma_found = false; + + if (r_fullbright.value) + return; + + // jkrige - wireframe + if (gl_wireframe.value) + return; + // jkrige - wireframe + + if(gl_lumatex_render.value != 1) + return; + + for (fa = s, i = 0; i < num_surfaces; fa++, i++) + { + // find the correct texture + t = R_TextureAnimation (fa->texinfo->texture); + + if(fa->luma_mark == true && t->tex_luma == true) + { + if(luma_found == false) + { + glDepthMask (GL_FALSE); + glEnable (GL_BLEND); + + //glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc (GL_ONE, GL_ONE); + + luma_found = true; + } + + GL_Bind (JK_LUMA_TEX + t->gl_texturenum); + DrawGLPoly (fa->polys); + + // draw luma textures more than once to add more brightness to external textures (hacky?) + if (t->tex_luma8bit == false) + DrawGLPoly (fa->polys); + + fa->luma_mark = false; + } + } + + if(luma_found == true) + { + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable (GL_BLEND); + glDepthMask (GL_TRUE); + } +} +// jkrige - luma textures + +/* +================ +R_RenderBrushPoly +================ +*/ +void R_RenderBrushPoly (msurface_t *fa) +{ + texture_t *t; + byte *base; + int maps; + glRect_t *theRect; + int smax, tmax; + + c_brush_polys++; + + if (fa->flags & SURF_DRAWSKY) + { // warp texture, no lightmaps + EmitBothSkyLayers (fa); + return; + } + + t = R_TextureAnimation (fa->texinfo->texture); + GL_Bind (t->gl_texturenum); + + if (fa->flags & SURF_DRAWTURB) + { // warp texture, no lightmaps + EmitWaterPolys (fa); + return; + } + + + // jkrige - external brushmodel lighting + if(currententity->model != cl.worldmodel && strlen(currententity->model->name) > 0 && currententity->model->name[0] != '*') + { + //float shadelight; + //shadelight = (float)R_LightPoint (currententity->origin); + //shadelight = shadelight / 128.0f; // dividing by 256 makes the brush models seem darker than the surrounding + // environment so we divide by 128, doubling the light strength + + //if(shadelight < 0.0f) + // shadelight = 0.0f; + + //if(shadelight > 1.0f) + // shadelight = 1.0f; + + // jkrige - wireframe + if (!gl_wireframe.value) + { + R_LightPoint(currententity->origin); + VectorScale(lightcolor, 1.0f / 176.0f, lightcolor); + } + else + { + lightcolor[0] = lightcolor[1] = lightcolor[2] = 1.0f; + } + // jkrige - wireframe + + //glColor4f (shadelight, shadelight, shadelight, 1.0f); + glColor4f (lightcolor[0], lightcolor[1], lightcolor[2], 1.0f); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + else + { + glColor4f (1.0f, 1.0f, 1.0f, 1.0f); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + // jkrige - external brushmodel lighting + + + if (fa->flags & SURF_UNDERWATER) + DrawGLWaterPoly (fa->polys); + else + DrawGLPoly (fa->polys); + + + // jkrige - luma textures + fa->luma_mark = true; + // jkrige - luma textures + + + // add the poly to the proper lightmap chain + + fa->polys->chain = lightmap_polys[fa->lightmaptexturenum]; + lightmap_polys[fa->lightmaptexturenum] = fa->polys; + + + // jkrige - overbrights (need to rebuild the lightmap if this changes) + if (fa->overbright != (qboolean)gl_overbright.value) + { + fa->overbright = (qboolean)gl_overbright.value; + goto dynamic; + } + // jkrige - overbrights + + + // 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); + } + } +} + +/* +================ +R_RenderDynamicLightmaps +Multitexture +================ +*/ +void R_RenderDynamicLightmaps (msurface_t *fa) +{ + texture_t *t; + byte *base; + int maps; + glRect_t *theRect; + int smax, tmax; + + c_brush_polys++; + + if (fa->flags & ( SURF_DRAWSKY | SURF_DRAWTURB) ) + return; + + fa->polys->chain = lightmap_polys[fa->lightmaptexturenum]; + lightmap_polys[fa->lightmaptexturenum] = fa->polys; + + + // jkrige - overbrights (need to rebuild the lightmap if this changes) + if (fa->overbright != (qboolean)gl_overbright.value) + { + fa->overbright = (qboolean)gl_overbright.value; + goto dynamic; + } + // jkrige - overbrights + + + // 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); + } + } +} + +/* +================ +R_MirrorChain +================ +*/ +void R_MirrorChain (msurface_t *s) +{ + if (mirror) + return; + mirror = true; + mirror_plane = s->plane; +} + + +#if 0 +/* +================ +R_DrawWaterSurfaces +================ +*/ +void R_DrawWaterSurfaces (void) +{ + int i; + msurface_t *s; + texture_t *t; + + if (r_wateralpha.value == 1.0) + return; + + // + // go back to the world matrix + // + glLoadMatrixf (r_world_matrix); + + glEnable (GL_BLEND); + glColor4f (1,1,1,r_wateralpha.value); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + if (!t) + continue; + s = t->texturechain; + if (!s) + continue; + if ( !(s->flags & SURF_DRAWTURB) ) + continue; + + // set modulate mode explicitly + GL_Bind (t->gl_texturenum); + + for ( ; s ; s=s->texturechain) + R_RenderBrushPoly (s); + + t->texturechain = NULL; + } + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glColor4f (1,1,1,1); + glDisable (GL_BLEND); +} +#else +/* +================ +R_DrawWaterSurfaces +================ +*/ +void R_DrawWaterSurfaces (void) +{ + int i; + msurface_t *s; + texture_t *t; + + if (r_wateralpha.value == 1.0 && gl_texsort.value) + return; + + // + // go back to the world matrix + // + + glLoadMatrixf (r_world_matrix); + + if (r_wateralpha.value < 1.0) { + glEnable (GL_BLEND); + glColor4f (1,1,1,r_wateralpha.value); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + + if (!gl_texsort.value) { + if (!waterchain) + return; + + for ( s = waterchain ; s ; s=s->texturechain) { + GL_Bind (s->texinfo->texture->gl_texturenum); + EmitWaterPolys (s); + } + + waterchain = NULL; + } else { + + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + if (!t) + continue; + s = t->texturechain; + if (!s) + continue; + if ( !(s->flags & SURF_DRAWTURB ) ) + continue; + + // set modulate mode explicitly + + GL_Bind (t->gl_texturenum); + + for ( ; s ; s=s->texturechain) + EmitWaterPolys (s); + + t->texturechain = NULL; + } + + } + + if (r_wateralpha.value < 1.0) { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glColor4f (1,1,1,1); + glDisable (GL_BLEND); + } + +} + +#endif + +/* +================ +DrawTextureChains +================ +*/ +void DrawTextureChains (void) +{ + int i; + msurface_t *s; + texture_t *t; + + if (!gl_texsort.value) { + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + if (skychain) { + R_DrawSkyChain(skychain); + skychain = NULL; + } + + return; + } + + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + if (!t) + continue; + s = t->texturechain; + if (!s) + continue; + if (i == skytexturenum) + R_DrawSkyChain (s); + else if (i == mirrortexturenum && r_mirroralpha.value != 1.0) + { + R_MirrorChain (s); + continue; + } + else + { + if ((s->flags & SURF_DRAWTURB) && r_wateralpha.value != 1.0) + continue; // draw translucent water later + for ( ; s ; s=s->texturechain) + R_RenderBrushPoly (s); + } + + t->texturechain = NULL; + } +} + +/* +================= +R_DrawBrushModel +================= +*/ +void R_DrawBrushModel (entity_t *e) +{ + int j, k; + vec3_t mins, maxs; + int i, numsurfaces; + msurface_t *psurf; + float dot; + mplane_t *pplane; + model_t *clmodel; + qboolean rotated; + + currententity = e; + currenttexture = -1; + + clmodel = e->model; + + if (e->angles[0] || e->angles[1] || e->angles[2]) + { + rotated = true; + for (i=0 ; i<3 ; i++) + { + mins[i] = e->origin[i] - clmodel->radius; + maxs[i] = e->origin[i] + clmodel->radius; + } + } + else + { + rotated = false; + VectorAdd (e->origin, clmodel->mins, mins); + VectorAdd (e->origin, clmodel->maxs, maxs); + } + + if (R_CullBox (mins, maxs)) + return; + + glColor3f (1,1,1); + memset (lightmap_polys, 0, sizeof(lightmap_polys)); + + VectorSubtract (r_refdef.vieworg, e->origin, modelorg); + if (rotated) + { + 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*/) // jkrige - flashblend removal + { + for (k=0 ; knodes + clmodel->hulls[0].firstclipnode); + R_MarkLights (&cl_dlights[k], k, clmodel->nodes + clmodel->hulls[0].firstclipnode); + // jkrige - increase dlights + } + } + + // jkrige - brush z-fighting + glEnable(GL_POLYGON_OFFSET_FILL); + // jkrige - brush z-fighting + + glPushMatrix (); + e->angles[0] = -e->angles[0]; // stupid quake bug + R_RotateForEntity (e); + e->angles[0] = -e->angles[0]; // stupid quake bug + + // + // draw texture + // + for (i=0 ; inummodelsurfaces ; i++, psurf++) + { + // find which side of the node we are on + pplane = psurf->plane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + if (gl_texsort.value) + R_RenderBrushPoly (psurf); + else + R_DrawSequentialPoly (psurf); + } + } + + + R_BlendLightmaps (); + + + // jkrige - luma textures + R_DrawLumaSurfaces (&clmodel->surfaces[clmodel->firstmodelsurface], clmodel->nummodelsurfaces); + // jkrige - luma textures + + + glPopMatrix (); + + // jkrige - brush z-fighting + glDisable(GL_POLYGON_OFFSET_FILL); + // jkrige - brush z-fighting +} + +/* +============================================================= + + WORLD MODEL + +============================================================= +*/ + +/* +================ +R_RecursiveWorldNode +================ +*/ +void R_RecursiveWorldNode (mnode_t *node) +{ + int i, c, side, *pindex; + vec3_t acceptpt, rejectpt; + mplane_t *plane; + msurface_t *surf, **mark; + mleaf_t *pleaf; + double d, dot; + vec3_t mins, maxs; + + if (node->contents == CONTENTS_SOLID) + return; // solid + + if (node->visframe != r_visframecount) + return; + if (R_CullBox (node->minmaxs, node->minmaxs+3)) + return; + +// if a leaf node, draw stuff + if (node->contents < 0) + { + pleaf = (mleaf_t *)node; + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if (c) + { + do + { + (*mark)->visframe = r_framecount; + mark++; + } while (--c); + } + + // deal with model fragments in this leaf + if (pleaf->efrags) + R_StoreEfrags (&pleaf->efrags); + + return; + } + +// node is just a decision point, so go down the apropriate sides + +// find which side of the node we are on + plane = node->plane; + + switch (plane->type) + { + case PLANE_X: + dot = modelorg[0] - plane->dist; + break; + case PLANE_Y: + dot = modelorg[1] - plane->dist; + break; + case PLANE_Z: + dot = modelorg[2] - plane->dist; + break; + default: + dot = DotProduct (modelorg, plane->normal) - plane->dist; + break; + } + + if (dot >= 0) + side = 0; + else + side = 1; + +// recurse down the children, front side first + R_RecursiveWorldNode (node->children[side]); + +// draw stuff + c = node->numsurfaces; + + if (c) + { + surf = cl.worldmodel->surfaces + node->firstsurface; + + if (dot < 0 -BACKFACE_EPSILON) + side = SURF_PLANEBACK; + else if (dot > BACKFACE_EPSILON) + side = 0; + { + for ( ; c ; c--, surf++) + { + if (surf->visframe != r_framecount) + continue; + + // don't backface underwater surfaces, because they warp + if ( !(surf->flags & SURF_UNDERWATER) && ( (dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) ) + continue; // wrong side + + // if sorting by texture, just store it out + if (gl_texsort.value) + { + if (!mirror || surf->texinfo->texture != cl.worldmodel->textures[mirrortexturenum]) + { + surf->texturechain = surf->texinfo->texture->texturechain; + surf->texinfo->texture->texturechain = surf; + } + } + else if (surf->flags & SURF_DRAWSKY) + { + surf->texturechain = skychain; + skychain = surf; + } + else if (surf->flags & SURF_DRAWTURB) + { + surf->texturechain = waterchain; + waterchain = surf; + } + else + { + // jkrige - luma textures + surf->luma_mark = true; + // jkrige - luma textures + + R_DrawSequentialPoly (surf); + } + + } + } + + } + +// recurse down the back side + R_RecursiveWorldNode (node->children[!side]); +} + + + +/* +============= +R_DrawWorld +============= +*/ +void R_DrawWorld (void) +{ + entity_t ent; + int i; + + memset (&ent, 0, sizeof(ent)); + ent.model = cl.worldmodel; + + VectorCopy (r_refdef.vieworg, modelorg); + + currententity = &ent; + currenttexture = -1; + + glColor3f (1,1,1); + memset (lightmap_polys, 0, sizeof(lightmap_polys)); + +//#ifdef QUAKE2 // jkrige - skybox +// R_ClearSkyBox (); +//#endif + + // jkrige - skybox (moved upwards, disabled depth checking) + R_DrawSkyBox (); + // jkrige - skybox (moved upwards, disabled depth checking) + + R_RecursiveWorldNode (cl.worldmodel->nodes); + + DrawTextureChains (); + + R_BlendLightmaps (); + + // jkrige - luma textures + R_DrawLumaSurfaces (&cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface], cl.worldmodel->nummodelsurfaces); + // jkrige - luma textures + +//#ifdef QUAKE2 // jkrige - skybox +// R_DrawSkyBox (); +//#endif +} + + +/* +=============== +R_MarkLeaves +=============== +*/ +void R_MarkLeaves (void) +{ + byte *vis; + mnode_t *node; + int i; + byte solid[4096]; + + if (r_oldviewleaf == r_viewleaf && !r_novis.value) + return; + + if (mirror) + return; + + r_visframecount++; + r_oldviewleaf = r_viewleaf; + + if (r_novis.value) + { + vis = solid; + memset (solid, 0xff, (cl.worldmodel->numleafs+7)>>3); + } + else + vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel); + + for (i=0 ; inumleafs ; i++) + { + if (vis[i>>3] & (1<<(i&7))) + { + node = (mnode_t *)&cl.worldmodel->leafs[i+1]; + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } +} + + + +/* +============================================================================= + + LIGHTMAP ALLOCATION + +============================================================================= +*/ + +// 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 bestx; + int texnum; + + 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 ; iedges; + lnumverts = fa->numedges; + vertpage = 0; + + // + // draw texture + // + poly = Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float)); + poly->next = fa->polys; + poly->flags = fa->flags; + 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; + } + + // + // remove co-linear points - Ed + // + // jkrige - disabled tjunction removal + /*if (!gl_keeptjunctions.value && !(fa->flags & SURF_UNDERWATER) ) + { + for (i = 0 ; i < lnumverts ; ++i) + { + vec3_t v1, v2; + float *prev, *this, *next; + float f; + + prev = poly->verts[(i + lnumverts - 1) % lnumverts]; + this = poly->verts[i]; + next = poly->verts[(i + 1) % lnumverts]; + + VectorSubtract( this, prev, v1 ); + VectorNormalize( v1 ); + VectorSubtract( next, prev, v2 ); + VectorNormalize( v2 ); + + // skip co-linear points + #define COLINEAR_EPSILON 0.001 + if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) && + (fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) && + (fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON)) + { + int j; + for (j = i + 1; j < lnumverts; ++j) + { + int k; + for (k = 0; k < VERTEXSIZE; ++k) + poly->verts[j - 1][k] = poly->verts[j][k]; + } + --lnumverts; + ++nColinElim; + // retry next vertex next time, which is now current vertex + --i; + } + } + }*/ + // jkrige - disabled tjunction removal + + poly->numverts = lnumverts; + +} + +/* +======================== +GL_CreateSurfaceLightmap +======================== +*/ +void GL_CreateSurfaceLightmap (msurface_t *surf) +{ + int smax, tmax, s, t, l, i; + byte *base; + + if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) + return; + + smax = (surf->extents[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); +} + + +/* +================== +GL_BuildLightmaps + +Builds the lightmap texture +with all the surfaces from all brush models +================== +*/ +void GL_BuildLightmaps (void) +{ + int i, j; + model_t *m; + extern qboolean isPermedia; + + memset (allocated, 0, sizeof(allocated)); + + r_framecount = 1; // no dlightcache + + if (!lightmap_textures) + { + lightmap_textures = texture_extension_number; + texture_extension_number += MAX_LIGHTMAPS; + } + + // jkrige - .lit colored lights + //gl_lightmap_format = GL_LUMINANCE; + // default differently on the Permedia + //if (isPermedia) + // gl_lightmap_format = GL_RGBA; + // jkrige - .lit colored lights + + + // jkrige - .lit colored lights + /*if (COM_CheckParm ("-lm_1")) + gl_lightmap_format = GL_LUMINANCE; + if (COM_CheckParm ("-lm_a")) + gl_lightmap_format = GL_ALPHA; + if (COM_CheckParm ("-lm_i")) + gl_lightmap_format = GL_INTENSITY; + if (COM_CheckParm ("-lm_2")) + gl_lightmap_format = GL_RGBA4; + if (COM_CheckParm ("-lm_4")) + gl_lightmap_format = GL_RGBA; + + switch (gl_lightmap_format) + { + case GL_RGBA: + lightmap_bytes = 4; + break; + case GL_RGBA4: + lightmap_bytes = 2; + break; + case GL_LUMINANCE: + case GL_INTENSITY: + case GL_ALPHA: + lightmap_bytes = 1; + break; + }*/ + // jkrige - .lit colored lights + + for (j=1 ; jname[0] == '*') + continue; + r_pcurrentvertbase = m->vertexes; + currentmodel = m; + for (i=0 ; inumsurfaces ; i++) + { + GL_CreateSurfaceLightmap (m->surfaces + i); + if ( m->surfaces[i].flags & SURF_DRAWTURB ) + continue; +#ifndef QUAKE2 + if ( m->surfaces[i].flags & SURF_DRAWSKY ) + continue; +#endif + BuildSurfaceDisplayList (m->surfaces + i); + } + } + + // jkrige - remove multitexture + //if (!gl_texsort.value) + // GL_SelectTexture(TEXTURE1_SGIS); + // jkrige - remove multitexture + + // + // upload all lightmaps that were filled + // + for (i=0 ; i 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; + + SCR_DrawCenterString (); +} + +//============================================================================= + +/* +==================== +CalcFov +==================== +*/ +float CalcFov (float fov_x, float width, float height) +{ + float a; + float 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; +} + +// jkrige - field of view (fov) fix +float fov_width; +// jkrige - field of view (fov) fix + +/* +================= +SCR_CalcRefdef + +Must be called whenever vid changes +Internal use only +================= +*/ +static void SCR_CalcRefdef (void) +{ + vrect_t vrect; + //float size; // jkrige - scr_viewsize & statusbar + int h; + + // jkrige - field of view (fov) fix + float fov_monitor; + // jkrige - field of view (fov) fix + + + scr_fullupdate = 0; // force a background redraw + vid.recalc_refdef = 0; + + // jkrige - always draw sbar +// force the status bar to redraw + //Sbar_Changed (); + // jkrige - always draw sbar + +//======================================== + +// bound viewsize + // jkrige - scr_viewsize & statusbar + if (scr_viewsize.value < 100) + Cvar_Set ("viewsize","100"); // jkrige : was 30 + if (scr_viewsize.value > 110) + Cvar_Set ("viewsize","110"); + // jkrige - scr_viewsize & statusbar + + +// bound field of view + // jkrige - field of view (fov) fix + /*if (scr_fov.value < 10) + Cvar_Set ("fov","10"); + if (scr_fov.value > 170) + Cvar_Set ("fov","170");*/ + if (fov_width < 10) + fov_width = 10; + if (fov_width > 170) + fov_width = 170; + // jkrige - field of view (fov) fix + + +// intermission is always full screen + //if (cl.intermission) + // size = 100; + //else + // size = scr_viewsize.value; + + + // jkrige - viewsize & statusbar + if(scr_viewsize.value >= 110) + sb_lines = 24; // no inventory + else + sb_lines = 24 + 16 + 8; + + //if (size >= 110) + // sb_lines = 0; // no status bar at all + //else if (size >= 110) + // sb_lines = 24; // no inventory + //else + // sb_lines = 24 + 16 + 8; + // jkrige - viewsize & statusbar + + + if (cl.intermission) + sb_lines = 0; + + //size /= 100.0; + + + // jkrige - scale2d + if (Scale2DFactor > 1.0f) + { + /*h = modelist[(int)vid_mode.value].height - sb_lines; + r_refdef.vrect.width = modelist[(int)vid_mode.value].width * size; + if (r_refdef.vrect.width < 96) + { + size = 96.0 / modelist[(int)vid_mode.value].width; + r_refdef.vrect.width = 96; // min for icons + } + + r_refdef.vrect.height = modelist[(int)vid_mode.value].height * size; + if (r_refdef.vrect.height > modelist[(int)vid_mode.value].height - sb_lines) + r_refdef.vrect.height = modelist[(int)vid_mode.value].height - sb_lines; + if (r_refdef.vrect.height > modelist[(int)vid_mode.value].height) + r_refdef.vrect.height = modelist[(int)vid_mode.value].height; + + r_refdef.vrect.x = (modelist[(int)vid_mode.value].width - r_refdef.vrect.width)/2; + //r_refdef.vrect.y = (h - r_refdef.vrect.height)/2; + + if (full) + r_refdef.vrect.y = 0; + else + r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;*/ + + + // jkrige - scr_viewsize & statusbar + r_refdef.vrect.width = modelist[(int)vid_mode.value].width; + r_refdef.vrect.height = modelist[(int)vid_mode.value].height; + r_refdef.vrect.x = 0; + r_refdef.vrect.y = 0; + + /*r_refdef.vrect.width = modelist[(int)vid_mode.value].width * size; + r_refdef.vrect.height = modelist[(int)vid_mode.value].height * size; + + r_refdef.vrect.x = (modelist[(int)vid_mode.value].width - r_refdef.vrect.width) / 2; + if(full) + r_refdef.vrect.y = 0; + else + r_refdef.vrect.y = (modelist[(int)vid_mode.value].height - r_refdef.vrect.height) / 2;*/ + // jkrige - scr_viewsize & statusbar + } + else + { + /*h = vid.height - sb_lines; + r_refdef.vrect.width = vid.width * size; + if (r_refdef.vrect.width < 96) + { + size = 96.0 / vid.width; + r_refdef.vrect.width = 96; // min for icons + } + + r_refdef.vrect.height = vid.height * size; + if (r_refdef.vrect.height > vid.height - sb_lines) + r_refdef.vrect.height = vid.height - sb_lines; + if (r_refdef.vrect.height > vid.height) + r_refdef.vrect.height = vid.height; + + r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2; + //r_refdef.vrect.y = (h - r_refdef.vrect.height)/2; + + if (full) + r_refdef.vrect.y = 0; + else + r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;*/ + + + // jkrige - scr_viewsize & statusbar + r_refdef.vrect.width = vid.width; + r_refdef.vrect.height = vid.height; + r_refdef.vrect.x = 0; + r_refdef.vrect.y = 0; + + /*r_refdef.vrect.width = vid.width * size; + r_refdef.vrect.height = vid.height * size; + + r_refdef.vrect.x = (vid.width - r_refdef.vrect.width) / 2; + if (full) + r_refdef.vrect.y = 0; + else + r_refdef.vrect.y = (vid.height - r_refdef.vrect.height) / 2;*/ + // jkrige - scr_viewsize & statusbar + } + // jkrige - scale2d + + + // jkrige - scale2d (quake original) + /*h = vid.height - sb_lines; + r_refdef.vrect.width = vid.width * size; + if (r_refdef.vrect.width < 96) + { + size = 96.0 / r_refdef.vrect.width; + r_refdef.vrect.width = 96; // min for icons + } + + r_refdef.vrect.height = vid.height * size; + if (r_refdef.vrect.height > vid.height - sb_lines) + r_refdef.vrect.height = vid.height - sb_lines; + if (r_refdef.vrect.height > vid.height) + r_refdef.vrect.height = vid.height; + r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2; + if (full) + r_refdef.vrect.y = 0; + else + r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;*/ + // jkrige - scale2d (quake original) + + + + // jkrige - field of view (fov) fix + if (r_refdef.vrect.width == 640 && r_refdef.vrect.height == 480) + r_refdef.vrect.height -= (sb_lines > 24) ? sb_lines - 24 : sb_lines - 8; + + fov_monitor = ((float)r_refdef.vrect.width / (float)r_refdef.vrect.height) / ((float)BASEWIDTH / (float)BASEHEIGHT); + //fov_monitor = ((float)vid.width / (float)vid.height) / ((float)BASEWIDTH / (float)BASEHEIGHT); + fov_width = (2 * atan(fov_monitor * tan(((float)BASEFOV / 2) * (M_PI / 180)))) * (180 / M_PI); + + if (fov_width >= floor(fov_width) + 0.5f) + fov_width = ceil(fov_width); + else + fov_width = floor(fov_width); + + + r_refdef.fov_x = fov_width; + //r_refdef.fov_x = scr_fov.value; + + //r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height); + r_refdef.fov_y = CalcFov (r_refdef.fov_x, vid.width, vid.height); + // jkrige - field of view (fov) fix + + + 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_Init +================== +*/ +void SCR_Init (void) +{ + // jkrige - field of view (fov) fix + //Cvar_RegisterVariable (&scr_fov); + // jkrige - field of view (fov) fix + + Cvar_RegisterVariable (&scr_viewsize); + Cvar_RegisterVariable (&scr_conspeed); + Cvar_RegisterVariable (&scr_showram); + Cvar_RegisterVariable (&scr_showturtle); + Cvar_RegisterVariable (&scr_showpause); + Cvar_RegisterVariable (&scr_centertime); + Cvar_RegisterVariable (&scr_printspeed); + Cvar_RegisterVariable (&gl_triplebuffer); + +// +// register our commands +// + Cmd_AddCommand ("screenshot",SCR_ScreenShot_f); + + Cmd_AddCommand ("sizeup",SCR_SizeUp_f); + Cmd_AddCommand ("sizedown",SCR_SizeDown_f); + + scr_ram = Draw_PicFromWad ("ram"); + scr_net = Draw_PicFromWad ("net"); + scr_turtle = Draw_PicFromWad ("turtle"); + + scr_initialized = true; +} + + + +/* +============== +SCR_DrawRam +============== +*/ +void SCR_DrawRam (void) +{ + if (!scr_showram.value) + return; + + if (!r_cache_thrash) + return; + + 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; + + 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; + + Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net); +} + +// jkrige - fps counter +/* +============== +SCR_DrawFPS +============== +*/ + +void SCR_DrawFPS (void) +{ + extern cvar_t r_fps; + + static double lastframetime; + double t; + extern int fps_count; + static int lastfps; + int x, y; + char st[80]; + + if (!r_fps.value) + return; + + t = Sys_FloatTime (); + + if ((t - lastframetime) >= 1.0) { + lastfps = fps_count; + fps_count = 0; + lastframetime = t; + } + + sprintf(st, "%3d FPS", lastfps); + + x = vid.width - strlen(st) * 8 - 8; + y = 0 ; //vid.height - (sb_lines * (vid.height/240) )- 16; + +// Draw_TileClear(x, y, strlen(st)*16, 16); + Draw_String(x, y, st); +} +// jkrige - fps counter + +/* +============== +DrawPause +============== +*/ +void SCR_DrawPause (void) +{ + qpic_t *pic; + + if (!scr_showpause.value) // turn off for screenshots + return; + + if (!cl.paused) + return; + + pic = Draw_CachePic ("gfx/pause.lmp"); + Draw_Pic ( (vid.width - pic->width)/2, + (vid.height - 48 - pic->height)/2, pic); +} + + + +/* +============== +SCR_DrawLoading +============== +*/ +void SCR_DrawLoading (void) +{ + qpic_t *pic; + + if (!scr_drawloading) + return; + + pic = Draw_CachePic ("gfx/loading.lmp"); + Draw_Pic ( (vid.width - pic->width)/2, + (vid.height - 48 - pic->height)/2, pic); +} + + + +//============================================================================= + + +/* +================== +SCR_SetUpToDrawConsole +================== +*/ +void SCR_SetUpToDrawConsole (void) +{ + 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 = vid.height; // full screen + scr_con_current = scr_conlines; + } + else if (key_dest == key_console) + scr_conlines = vid.height/2; // half screen + else + scr_conlines = 0; // none visible + + if (scr_conlines < scr_con_current) + { + scr_con_current -= scr_conspeed.value*host_frametime; + 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; + if (scr_conlines < scr_con_current) + scr_con_current = scr_conlines; + } + + if (clearconsole++ < vid.numpages) + { + //Sbar_Changed (); // jkrige - always draw sbar + } + else if (clearnotify++ < vid.numpages) + { + } + else + con_notifylines = 0; +} + +/* +================== +SCR_DrawConsole +================== +*/ +void SCR_DrawConsole (void) +{ + if (scr_con_current) + { + scr_copyeverything = 1; + 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 + +============================================================================== +*/ + +typedef struct _TargaHeader { + unsigned char id_length, colormap_type, image_type; + unsigned short colormap_index, colormap_length; + unsigned char colormap_size; + unsigned short x_origin, y_origin, width, height; + unsigned char pixel_size, attributes; +} TargaHeader; + + +/* +================== +SCR_ScreenShot_f +================== +*/ +void SCR_ScreenShot_f (void) +{ + byte *buffer; + char pcxname[80]; + char checkname[MAX_OSPATH]; + int i, c, temp; + + // jkrige - "shots" directory + sprintf (checkname, "%s/shots", com_gamedir); + Sys_mkdir (checkname); + // jkrige - "shots" directory + +// +// find a file name to save it to +// + // jkrige - "shots" directory + //strcpy(pcxname,"quake00.tga"); + strcpy(pcxname,"shots/quake00.tga"); + // jkrige - "shots" directory + + for (i=0 ; i<=99 ; i++) + { + // jkrige - "shots" directory + //pcxname[5] = i/10 + '0'; + //pcxname[6] = i%10 + '0'; + pcxname[11] = i/10 + '0'; + pcxname[12] = i%10 + '0'; + // jkrige - "shots" directory + + sprintf (checkname, "%s/%s", com_gamedir, pcxname); + if (Sys_FileTime(checkname) == -1) + break; // file doesn't exist + } + if (i==100) + { + Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n"); + return; + } + + + buffer = malloc(glwidth*glheight*3 + 18); + memset (buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = glwidth&255; + buffer[13] = glwidth>>8; + buffer[14] = glheight&255; + buffer[15] = glheight>>8; + buffer[16] = 24; // pixel size + + glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); + + // swap rgb to bgr + c = 18+glwidth*glheight*3; + for (i=18 ; i 0 ) && deviceSupportsGamma ) + VG_GammaCorrect( buffer + 18, glwidth * glheight * 3 ); + + + COM_WriteFile (pcxname, buffer, glwidth*glheight*3 + 18 ); + + free (buffer); + Con_Printf ("Wrote %s\n", pcxname); +} + + +//============================================================================= + + +/* +=============== +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; + scr_fullupdate = 0; + //Sbar_Changed (); // jkrige - always draw sbar + SCR_UpdateScreen (); + scr_drawloading = false; + + scr_disabled_for_loading = true; + scr_disabled_time = realtime; + scr_fullupdate = 0; +} + +/* +=============== +SCR_EndLoadingPlaque + +================ +*/ +void SCR_EndLoadingPlaque (void) +{ + scr_disabled_for_loading = false; + scr_fullupdate = 0; + Con_ClearNotify (); +} + +//============================================================================= + +char *scr_notifystring; +qboolean scr_drawdialog; + +void SCR_DrawNotifyString (void) +{ + char *start; + int l; + int j; + int x, y; + + start = scr_notifystring; + + y = vid.height*0.35; + + do + { + // scan the width of the line + for (l=0 ; l<40 ; l++) + if (start[l] == '\n' || !start[l]) + break; + x = (vid.width - l*8)/2; + for (j=0 ; j 1.0f) + divFactor = Scale2DFactor; + else + divFactor = 1.0f; + // jkrige - scale2d + + tileX = r_refdef.vrect.x / divFactor; + tileY = r_refdef.vrect.y / divFactor; + tileWidth = r_refdef.vrect.width / divFactor; + tileHeight = r_refdef.vrect.height / divFactor; + + + if (r_refdef.vrect.x > 0) + { + Draw_TileClear (0, 0, tileX, vid.height); // left + Draw_TileClear (vid.width - tileX, 0, tileX, vid.height); // right + } + if (r_refdef.vrect.y > 0) + { + Draw_TileClear (tileX, 0, vid.width - (tileX * 2), tileY); // top + Draw_TileClear (tileX, tileY + tileHeight, vid.width - (tileX * 2), vid.height - (tileHeight + tileY)); // bottom + } +} + +/* +================== +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) +{ + // jkrige - scr_viewsize removal + //static float oldscr_viewsize; + // jkrige - scr_viewsize removal + + vrect_t vrect; + + if (block_drawing) + return; + + vid.numpages = 2 + gl_triplebuffer.value; + + scr_copytop = 0; + scr_copyeverything = 0; + + 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 + // + // jkrige - field of view (fov) fix + /*if (oldfov != scr_fov.value) + { + oldfov = scr_fov.value; + vid.recalc_refdef = true; + }*/ + if (oldfov != fov_width) + { + oldfov = fov_width; + vid.recalc_refdef = true; + } + // jkrige - field of view (fov) fix + + + // jkrige - scr_viewsize removal + /*if (oldscreensize != scr_viewsize.value) + { + oldscreensize = scr_viewsize.value; + vid.recalc_refdef = true; + }*/ + // jkrige - scr_viewsize removal + + if (vid.recalc_refdef) + SCR_CalcRefdef (); + +// +// do 3D refresh drawing, and then update the screen +// + SCR_SetUpToDrawConsole (); + + V_RenderView (); + + GL_Set2D (); + + // jkrige - 2D polyblend + R_PolyBlend (); + // jkrige - 2D polyblend + + // + // draw any areas not covered by the refresh + // + SCR_TileClear (); + + + if (scr_drawdialog) + { + Sbar_Draw (); + Draw_FadeScreen (); + SCR_DrawNotifyString (); + scr_copyeverything = true; + } + else if (scr_drawloading) + { + SCR_DrawLoading (); + Sbar_Draw (); + } + else if (cl.intermission == 1 && key_dest == key_game) + { + Sbar_IntermissionOverlay (); + } + else if (cl.intermission == 2 && key_dest == key_game) + { + Sbar_FinaleOverlay (); + SCR_CheckDrawCenterString (); + } + else + { + if (crosshair.value) + { + // jkrige - scale2d + //Draw_Character (scr_vrect.x + scr_vrect.width/2, scr_vrect.y + scr_vrect.height/2, '+'); + Draw_Character ((vid.width / 2)-4, (vid.height / 2)-4, '+'); + // jkrige - scale2d + } + + SCR_DrawRam (); + SCR_DrawNet (); + SCR_DrawTurtle (); + SCR_DrawFPS (); // jkrige - fps counter + SCR_DrawPause (); + SCR_CheckDrawCenterString (); + Sbar_Draw (); + SCR_DrawConsole (); + M_Draw (); + } + + V_UpdatePalette (); + + GL_EndRendering (); + + // jkrige - texture mode + Draw_TextureMode_f(); + // jkrige - texture mode +} + diff --git a/engine/code/gl_test.c b/engine/code/gl_test.c new file mode 100644 index 0000000..a3b1027 --- /dev/null +++ b/engine/code/gl_test.c @@ -0,0 +1,182 @@ +/* +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. + +*/ + +#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/engine/code/gl_vidnt.c b/engine/code/gl_vidnt.c new file mode 100644 index 0000000..8495966 --- /dev/null +++ b/engine/code/gl_vidnt.c @@ -0,0 +1,2260 @@ +/* +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. + +*/ +// gl_vidnt.c -- NT GL vid component + +#include "quakedef.h" +#include "winquake.h" +#include "resource.h" +#include + +//#define MAX_MODE_LIST 30 // jkrige - moved to winquake.h +#define VID_ROW_SIZE 3 +#define WARP_WIDTH 320 +#define WARP_HEIGHT 200 + +// jkrige - limit video modes +#define VID_MINWIDTH 320 +#define VID_MINHEIGHT 240 +// jkrige - limit video modes + +#define VID_MAXWIDTH 10000 +#define VID_MAXHEIGHT 10000 +//#define BASEWIDTH 320 // jkrige - moved to winquake.h +//#define BASEHEIGHT 200 // jkrige - moved to winquake.h + +#define MODE_WINDOWED 0 +#define NO_MODE (MODE_WINDOWED - 1) +#define MODE_FULLSCREEN_DEFAULT (MODE_WINDOWED + 1) + +// jkrige - moved to winquake.h +/*typedef struct { + modestate_t type; + int width; + int height; + int modenum; + int dib; + int fullscreen; + int bpp; + int halfscreen; + char modedesc[17]; +} vmode_t;*/ +// jkrige - moved to winquake.h + +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; + +// jkrige - scale2d +//static vmode_t modelist[MAX_MODE_LIST]; +vmode_t modelist[MAX_MODE_LIST]; +// jkrige - scale2d + +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]; + +// jkrige - always draw sbar +//static qboolean fullsbardraw = false; +// jkrige - always draw sbar + +static float vid_gamma = 1.0; + +HGLRC baseRC; +HDC maindc; + +glvert_t glv; + +// jkrige - changed gl_ztrick default to 0 +// this will now default to zero, because of the compatibility problems, +// Z fighting, and the fact that this doesn't necessarily give us +// any performance boost on modern hardware, where it introduces a new +// problem: if video page swaps are too frequent (130+ fps), the OpenGL +// pipeline might not keep up with changing Z test function on each +// frame update, sometimes resulting in flickering or "snow". +//cvar_t gl_ztrick = {"gl_ztrick","1"}; +cvar_t gl_ztrick = {"gl_ztrick","0"}; +// jkrige - changed gl_ztrick default to 0 + +HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); + +viddef_t vid; // global video state + +unsigned short d_8to16table[256]; +unsigned d_8to24table[256]; +unsigned char d_15to8table[65536]; + +float gldepthmin, gldepthmax; + +modestate_t modestate = MS_UNINIT; + +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); + +// jkrige - opengl extensions +//PROC glArrayElementEXT; +//PROC glColorPointerEXT; +//PROC glTexCoordPointerEXT; +//PROC glVertexPointerEXT; +// jkrige - opengl extensions + + +// jkrige - no 8bit palette extensions +//typedef void (APIENTRY *lp3DFXFUNC) (int, int, int, int, int, const void*); +//lp3DFXFUNC glColorTableEXT; +//qboolean is8bit = false; +// jkrige - no 8bit palette extensions + +qboolean isPermedia = false; +//qboolean gl_mtexable = false; // jkrige - remove multitexture + + +// jkrige - overbrights +cvar_t gl_overbright = {"gl_overbright", "1", true}; +// jkrige - overbrights + +//==================================== + +cvar_t vid_mode = {"vid_mode","0", false}; +// Note that 0 is MODE_WINDOWED +cvar_t _vid_default_mode = {"_vid_default_mode","0", true}; +// Note that 3 is MODE_FULLSCREEN_DEFAULT +cvar_t _vid_default_mode_win = {"_vid_default_mode_win","3", true}; +cvar_t vid_wait = {"vid_wait","0"}; +cvar_t vid_nopageflip = {"vid_nopageflip","0", true}; +cvar_t _vid_wait_override = {"_vid_wait_override", "0", true}; +cvar_t vid_config_x = {"vid_config_x","800", true}; +cvar_t vid_config_y = {"vid_config_y","600", true}; +cvar_t vid_stretch_by_2 = {"vid_stretch_by_2","1", true}; +cvar_t _windowed_mouse = {"_windowed_mouse","1", true}; + +// jkrige - non power of two +cvar_t gl_texture_non_power_of_two = {"gl_texture_non_power_of_two", "1", true}; +// jkrige - non power of two + +int window_center_x, window_center_y, window_x, window_y, window_width, window_height; +RECT window_rect; + +// 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) +{ +} + + +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); +} + +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; + + WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | + WS_MINIMIZEBOX; + 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, + "Quake", // jkrige - was "WinQuake" + "Quake", // jkrige - 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); + + + // jkrige - scale2d + /*if (vid.conheight > modelist[modenum].height) + vid.conheight = modelist[modenum].height; + if (vid.conwidth > modelist[modenum].width) + vid.conwidth = modelist[modenum].width; + vid.width = vid.conwidth; + vid.height = vid.conheight;*/ + + if (Scale2DFactor > 1.0f) + { + vid.width = vid.conwidth = conback->width = Scale2DWidth; + vid.height = vid.conheight = conback->height = Scale2DHeight; + } + else + { + vid.width = vid.conwidth = conback->width = modelist[modenum].width; + vid.height = vid.conheight = conback->height = modelist[modenum].height; + } + // jkrige - scale2d + + + vid.numpages = 2; + + mainwindow = dibwindow; + + SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); + SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); + + return true; +} + + +qboolean VID_SetFullDIBMode (int modenum) +{ + HDC hdc; + int lastmodestate, width, height; + RECT rect; + + if (!leavecurrentmode) + { + gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + gdevmode.dmBitsPerPel = modelist[modenum].bpp; + gdevmode.dmPelsWidth = modelist[modenum].width << + modelist[modenum].halfscreen; + gdevmode.dmPelsHeight = modelist[modenum].height; + 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, + "Quake", // jkrige - was "WinQuake" + "Quake", // jkrige - 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); + + + // jkrige - scale2d + /*if (vid.conheight > modelist[modenum].height) + vid.conheight = modelist[modenum].height; + if (vid.conwidth > modelist[modenum].width) + vid.conwidth = modelist[modenum].width; + vid.width = vid.conwidth; + vid.height = vid.conheight;*/ + + if (Scale2DFactor > 1.0f) + { + vid.width = vid.conwidth = conback->width = Scale2DWidth; + vid.height = vid.conheight = conback->height = Scale2DHeight; + } + else + { + vid.width = vid.conwidth = conback->width = modelist[modenum].width; + vid.height = vid.conheight = conback->height = modelist[modenum].height; + } + // jkrige - scale2d + + + 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; +} + + +int VID_SetMode (int modenum, unsigned char *palette) +{ + 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; + + // jkrige - fmod sound system - begin +#ifdef UQE_FMOD + FMOD_MusicPause(); +#else + CDAudio_Pause(); +#endif + // jkrige - fmod sound system - end + + 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"); + } + + window_width = DIBWidth; + window_height = DIBHeight; + VID_UpdateWindowStatus (); + + // jkrige - fmod sound system - begin +#ifdef UQE_FMOD + FMOD_MusicResume(); +#else + CDAudio_Resume(); +#endif + // jkrige - fmod sound system - end + + 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_SetPalette (palette); + vid_modenum = modenum; + Cvar_SetValue ("vid_mode", (float)vid_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_SetPalette (palette); + + vid.recalc_refdef = 1; + + return true; +} + + +/* +================ +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 (); +} + + +//==================================== + +BINDTEXFUNCPTR bindTexFunc; + +#define TEXTURE_EXT_STRING "GL_EXT_texture_object" + + +void CheckTextureExtensions (void) +{ + char *tmp; + qboolean texture_ext; + HINSTANCE hInstGL; + + texture_ext = FALSE; + /* check for texture extension */ + tmp = (unsigned char *)glGetString(GL_EXTENSIONS); + while (*tmp) + { + if (strncmp((const char*)tmp, TEXTURE_EXT_STRING, strlen(TEXTURE_EXT_STRING)) == 0) + texture_ext = TRUE; + tmp++; + } + + if (!texture_ext || COM_CheckParm ("-gl11") ) + { + hInstGL = LoadLibrary("opengl32.dll"); + + if (hInstGL == NULL) + Sys_Error ("Couldn't load opengl32.dll\n"); + + bindTexFunc = (void *)GetProcAddress(hInstGL,"glBindTexture"); + + if (!bindTexFunc) + Sys_Error ("No texture objects!"); + return; + } + +/* load library and get procedure adresses for texture extension API */ + if ((bindTexFunc = (BINDTEXFUNCPTR) + wglGetProcAddress((LPCSTR) "glBindTextureEXT")) == NULL) + { + Sys_Error ("GetProcAddress for BindTextureEXT failed"); + return; + } +} + +#if 0 +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"); +} +#endif + +//int texture_mode = GL_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_LINEAR; +int texture_mode = GL_LINEAR; +//int texture_mode = GL_LINEAR_MIPMAP_NEAREST; +//int texture_mode = GL_LINEAR_MIPMAP_LINEAR; + +int texture_extension_number = 1; + +// jkrige - remove multitexture +/* +#ifdef _WIN32 +void CheckMultiTextureExtensions(void) +{ + if (strstr(gl_extensions, "GL_SGIS_multitexture ") && !COM_CheckParm("-nomtex")) { + Con_Printf("Multitexture extensions found.\n"); + qglMTexCoord2fSGIS = (void *) wglGetProcAddress("glMTexCoord2fSGIS"); + qglSelectTextureSGIS = (void *) wglGetProcAddress("glSelectTextureSGIS"); + gl_mtexable = true; + } +} +#else +void CheckMultiTextureExtensions(void) +{ + gl_mtexable = true; +} +#endif +*/ +// jkrige - remove multitexture + + +// jkrige - gamma +BOOL ( WINAPI * qwglGetDeviceGammaRamp3DFX)( HDC, LPVOID ); +BOOL ( WINAPI * qwglSetDeviceGammaRamp3DFX)( HDC, LPVOID ); + +void Check3DFXGammaExtensions (void) +{ + char *gl_extensions; + HINSTANCE hInstGL; + + gl_extensions = (unsigned char *)glGetString(GL_EXTENSIONS); + + // WGL_3DFX_gamma_control + qwglGetDeviceGammaRamp3DFX = NULL; + qwglSetDeviceGammaRamp3DFX = NULL; + + if ( strstr( gl_extensions, "WGL_3DFX_gamma_control" ) ) + { + //if ( !r_ignorehwgamma->integer && r_ext_gamma_control->integer ) + //{ + qwglGetDeviceGammaRamp3DFX = ( BOOL ( WINAPI * )( HDC, LPVOID ) ) wglGetProcAddress((LPCSTR) "wglGetDeviceGammaRamp3DFX" ); + qwglSetDeviceGammaRamp3DFX = ( BOOL ( WINAPI * )( HDC, LPVOID ) ) wglGetProcAddress((LPCSTR) "wglSetDeviceGammaRamp3DFX" ); + + if ( qwglGetDeviceGammaRamp3DFX && qwglSetDeviceGammaRamp3DFX ) + { + //Con_Printf("using WGL_3DFX_gamma_control\n"); + Con_Printf("WGL_3DFX_gamma_control\n"); + } + else + { + qwglGetDeviceGammaRamp3DFX = NULL; + qwglSetDeviceGammaRamp3DFX = NULL; + } + //} + //else + //{ + // ri.Printf( PRINT_ALL, "...ignoring WGL_3DFX_gamma_control\n" ); + //} + } + //else + //{ + // Con_Printf("WGL_3DFX_gamma_control not found\n"); + //} +} + + +// jkrige - anisotropic filtering +qboolean anisotropic_ext = false; +float maximumAnisotrophy = 1.0f; + +void CheckAnisotropicExtension( void ) +{ + char *tmp; + char *search; + + search = NULL; + search = "GL_EXT_texture_filter_anisotropic"; + if (!search) return; + + + tmp = ( unsigned char * )glGetString( GL_EXTENSIONS ); + while( *tmp ) + { + if (strncmp((const char*)tmp, search, strlen(search)) == 0) + { + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maximumAnisotrophy); + Con_Printf("GL_EXT_texture_filter_anisotropic\n"); + anisotropic_ext = true; + } + tmp++; + } + + //if(!anisotropic_ext) + // Con_Printf("GL_EXT_texture_filter_anisotropic not found\n"); +} +// jkrige - anisotropic filtering + + +// jkrige - non power of two +qboolean npow2_ext = false; + +void CheckNonPowTwoExtension( void ) +{ + unsigned char *tmp; + char *search; + + search = NULL; + search = "GL_ARB_texture_non_power_of_two"; + if (!search) return; + + + tmp = ( unsigned char * )glGetString( GL_EXTENSIONS ); + while( *tmp ) + { + if (strncmp((const char*)tmp, search, strlen(search)) == 0) + { + Con_Printf("GL_ARB_texture_non_power_of_two\n"); + npow2_ext = true; + } + tmp++; + } + + //if(!npow2_ext) + // Con_Printf("GL_ARB_texture_non_power_of_two not found\n"); +} +// jkrige - non power of two + +/* +=============== +GL_Init +=============== +*/ +void GL_Init (void) +{ + gl_vendor = glGetString (GL_VENDOR); + Con_Printf ("GL_VENDOR: %s\n", gl_vendor); + gl_renderer = glGetString (GL_RENDERER); + Con_Printf ("GL_RENDERER: %s\n", gl_renderer); + + gl_version = glGetString (GL_VERSION); + Con_Printf ("GL_VERSION: %s\n", gl_version); + + // jkrige - don't display extension list + gl_extensions = glGetString (GL_EXTENSIONS); + //Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions); + // jkrige - don't display extension list + //Con_Printf("------------------------------------\n"); + Con_Printf("\n------------- Extensions -------------\n"); + +// Con_Printf ("%s %s\n", gl_renderer, gl_version); + + // jkrige - always draw sbar + //if (strnicmp(gl_renderer,"PowerVR",7)==0) + // fullsbardraw = true; + // jkrige - always draw sbar + + if (strnicmp(gl_renderer,"Permedia",8)==0) + isPermedia = true; + + CheckTextureExtensions (); + //CheckMultiTextureExtensions (); // jkrige - remove multitexture + + Check3DFXGammaExtensions (); // jkrige - gamma + CheckNonPowTwoExtension(); // jkrige - non power of two + CheckAnisotropicExtension(); // jkrige - anisotropic filtering + + // jkrige - clear color changed to black (used to be red) + glClearColor(0.0, 0.0, 0.0, 0.0); + //glClearColor (1,0,0,0); + // jkrige - clear color changed to black (used to be red) + glCullFace(GL_FRONT); + glEnable(GL_TEXTURE_2D); + + glEnable(GL_ALPHA_TEST); + // Pa3PyX: to avoid clipping of smaller fonts/graphics + glAlphaFunc(GL_GREATER, 0.632); + //glAlphaFunc(GL_GREATER, 0.666); + + // jkrige - brush z-fighting + glPolygonOffset(0.05, 25); + // jkrige - brush z-fighting + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glShadeModel (GL_FLAT); + + 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); + + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + +// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + +#if 0 + CheckArrayExtensions (); + + glEnable (GL_VERTEX_ARRAY_EXT); + glEnable (GL_TEXTURE_COORD_ARRAY_EXT); + glVertexPointerEXT (3, GL_FLOAT, 0, 0, &glv.x); + glTexCoordPointerEXT (2, GL_FLOAT, 0, 0, &glv.s); + glColorPointerEXT (3, GL_FLOAT, 0, 0, &glv.r); +#endif + + // jkrige - gamma + VG_CheckHardwareGamma(); + VG_SetColorMappings(); + // jkrige - gamma +} + +/* +================= +GL_BeginRendering + +================= +*/ +void GL_BeginRendering (int *x, int *y, int *width, int *height) +{ + extern cvar_t gl_clear; + + *x = *y = 0; + *width = WindowRect.right - WindowRect.left; + *height = WindowRect.bottom - WindowRect.top; + +// if (!wglMakeCurrent( maindc, baseRC )) +// Sys_Error ("wglMakeCurrent failed"); + +// glViewport (*x, *y, *width, *height); +} + + +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 (); + } + } + } + + // jkrige - always draw sbar + //if (fullsbardraw) + // Sbar_Changed(); + // jkrige - always draw sbar +} + +void VID_SetPalette (unsigned char *palette) +{ + byte *pal; + unsigned r,g,b; + unsigned v; + int r1,g1,b1; + int j,k,l,m; + unsigned short i; + unsigned *table; + FILE *f; + char s[255]; + HWND hDlg, hProgress; + float gamma; + +// +// 8 8 8 encoding +// + pal = palette; + table = d_8to24table; + for (i=0 ; i<256 ; i++) + { + r = pal[0]; + g = pal[1]; + b = pal[2]; + pal += 3; + +// v = (255<<24) + (r<<16) + (g<<8) + (b<<0); +// v = (255<<0) + (r<<8) + (g<<16) + (b<<24); + v = (255<<24) + (r<<0) + (g<<8) + (b<<16); + *table++ = v; + } + d_8to24table[255] &= 0xffffff; // 255 is transparent + + // JACK: 3D distance calcs - k is last closest, l is the distance. + // FIXME: Precalculate this and cache to disk. + for (i=0; i < (1<<15); i++) { + /* Maps + 000000000000000 + 000000000011111 = Red = 0x1F + 000001111100000 = Blue = 0x03E0 + 111110000000000 = Grn = 0x7C00 + */ + r = ((i & 0x1F) << 3)+4; + g = ((i & 0x03E0) >> 2)+4; + b = ((i & 0x7C00) >> 7)+4; + pal = (unsigned char *)d_8to24table; + for (v=0,k=0,l=10000*10000; v<256; v++,pal+=4) { + r1 = r-pal[0]; + g1 = g-pal[1]; + b1 = b-pal[2]; + j = (r1*r1)+(g1*g1)+(b1*b1); + if (j', '?', 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 + }; +#endif + + +/* +======= +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]; +} + +/* +=================================================================== + +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 (); +} + +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) + { + // jkrige - fmod sound system - begin +#ifdef UQE_FMOD + FMOD_MusicActivate(false); +#else + CDAudio_Activate(false); +#endif + // jkrige - fmod sound system - end + + S_BlockSound (); + sound_active = false; + } + else if (ActiveApp && !sound_active) + { + // jkrige - fmod sound system - begin +#ifdef UQE_FMOD + FMOD_MusicActivate(true); +#else + CDAudio_Activate(true); +#endif + // jkrige - fmod sound system - end + + 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); + } + } + else if ((modestate == MS_WINDOWED) && _windowed_mouse.value && key_dest == key_game) + { + IN_ActivateMouse (); + IN_HideMouse (); + } + } + + 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 (); + } + } +} + + +/* 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_XBUTTONDOWN: // jkrige - mouse thumb buttons + case WM_XBUTTONUP: // jkrige - mouse thumb buttons + case WM_MOUSEMOVE: + temp = 0; + + if (wParam & MK_LBUTTON) + temp |= 1; + + if (wParam & MK_RBUTTON) + temp |= 2; + + if (wParam & MK_MBUTTON) + temp |= 4; + + // jkrige - mouse thumb buttons + // intellimouse explorer + if (wParam & MK_XBUTTON1) + temp |= 8; + + if (wParam & MK_XBUTTON2) + temp |= 16; + // jkrige - mouse thumb buttons + + 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; + + // jkrige - fmod sound system - begin +#ifndef UQE_FMOD_CDAUDIO + case MM_MCINOTIFY: + lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam); + break; +#endif + // jkrige - fmod sound system - end + + default: + /* pass all unhandled messages to DefWindowProc */ + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + break; + } + + /* return 1 if handled message, 0 if not */ + return lRet; +} + + +/* +================= +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 (%dx%d)", modelist[MODE_FULLSCREEN_DEFAULT].width, modelist[MODE_FULLSCREEN_DEFAULT].height); + pinfo = temp; + } + + return pinfo; +} + + +// KJB: Added this to return the mode driver name in description for console + +char *VID_GetExtModeDescription (int mode) +{ + static char pinfo[100]; // jkrige - might be low + //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 (%dx%d)", + modelist[MODE_FULLSCREEN_DEFAULT].width, + modelist[MODE_FULLSCREEN_DEFAULT].height); + } + } + 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_NumModes_f +================= +*/ +void VID_NumModes_f (void) +{ + + if (nummodes == 1) + Con_Printf ("%d video mode is available\n", nummodes); + else + Con_Printf ("%d video modes are available\n", nummodes); +} + + +/* +================= +VID_DescribeMode_f +================= +*/ +void VID_DescribeMode_f (void) +{ + int t, modenum; + + modenum = Q_atoi (Cmd_Argv(1)); + + t = leavecurrentmode; + leavecurrentmode = 0; + + Con_Printf ("%s\n", VID_GetExtModeDescription (modenum)); + + leavecurrentmode = t; +} + + +/* +================= +VID_DescribeModes_f +================= +*/ +void VID_DescribeModes_f (void) +{ + int i, lnummodes, t; + char *pinfo; + vmode_t *pv; + + lnummodes = VID_NumModes (); + + t = leavecurrentmode; + leavecurrentmode = 0; + + for (i=1 ; i8 bpp modes + originalnummodes = nummodes; + modenum = 0; + + do + { + stat = EnumDisplaySettings (NULL, modenum, &devmode); + + // jkrige - limit video modes + //if ((devmode.dmBitsPerPel >= 15) && + /*(devmode.dmPelsWidth <= VID_MAXWIDTH) && + (devmode.dmPelsHeight <= VID_MAXHEIGHT) && + (nummodes < MAX_MODE_LIST))*/ + if ((devmode.dmBitsPerPel >= 32) && + ( + (devmode.dmPelsWidth == VID_MINWIDTH && devmode.dmPelsHeight == VID_MINHEIGHT) || (devmode.dmPelsWidth >= 640 && devmode.dmPelsHeight >= 480) + ) && + (devmode.dmPelsWidth != 720) && + (devmode.dmPelsWidth <= VID_MAXWIDTH) && + (devmode.dmPelsHeight <= VID_MAXHEIGHT) && + (nummodes < MAX_MODE_LIST)) + // jkrige - limit video modes + { + devmode.dmFields = DM_BITSPERPEL | + DM_PELSWIDTH | + DM_PELSHEIGHT; + + 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; + + // jkrige - limit video modes + //sprintf (modelist[nummodes].modedesc, "%dx%dx%d", devmode.dmPelsWidth, devmode.dmPelsHeight, devmode.dmBitsPerPel); + sprintf (modelist[nummodes].modedesc, "%dx%d", devmode.dmPelsWidth, devmode.dmPelsHeight); + // jkrige - limit video modes + + + // 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; + + // jkrige - limit video modes + //sprintf (modelist[nummodes].modedesc, "%dx%dx%d", modelist[nummodes].width, modelist[nummodes].height, modelist[nummodes].bpp); + sprintf (modelist[nummodes].modedesc, "%dx%d", modelist[nummodes].width, modelist[nummodes].height); + // jkrige - limit video modes + } + } + + for (i=originalnummodes, existingmode = 0 ; i 255) + inf = 255; + palette[i] = inf; + } + + memcpy (pal, palette, sizeof(palette)); +} + +/* +=================== +VID_Init +=================== +*/ +void VID_Init (unsigned char *palette) +{ + int i, existingmode; + int basenummodes, width, height, bpp, findbpp, done; + byte *ptmp; + char gldir[MAX_OSPATH]; + HDC hdc; + DEVMODE devmode; + + memset(&devmode, 0, sizeof(devmode)); + + Cvar_RegisterVariable (&vid_mode); + Cvar_RegisterVariable (&vid_wait); + Cvar_RegisterVariable (&vid_nopageflip); + Cvar_RegisterVariable (&_vid_wait_override); + Cvar_RegisterVariable (&_vid_default_mode); + Cvar_RegisterVariable (&_vid_default_mode_win); + Cvar_RegisterVariable (&vid_config_x); + Cvar_RegisterVariable (&vid_config_y); + Cvar_RegisterVariable (&vid_stretch_by_2); + Cvar_RegisterVariable (&_windowed_mouse); + Cvar_RegisterVariable (&gl_ztrick); + + // jkrige - non power of two + Cvar_RegisterVariable (&gl_texture_non_power_of_two); + // jkrige - non power of two + + // jkrige - overbrights + Cvar_RegisterVariable (&gl_overbright); + // jkrige - overbrights + + Cmd_AddCommand ("vid_nummodes", VID_NumModes_f); + Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f); + Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f); + Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f); + + hIcon = LoadIcon (global_hInstance, MAKEINTRESOURCE (IDI_ICON2)); + + // jkrige - disable common controls + //InitCommonControls(); + // jkrige - disable common controls + + VID_InitDIB (global_hInstance); + basenummodes = nummodes = 1; + + VID_InitFullDIB (global_hInstance); + + if (COM_CheckParm("-window")) + { + hdc = GetDC (NULL); + + if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) + { + Sys_Error ("Can't run in non-RGB mode"); + } + + ReleaseDC (NULL, hdc); + + 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")) + { + modelist[MODE_FULLSCREEN_DEFAULT].width = GetSystemMetrics (SM_CXSCREEN); + modelist[MODE_FULLSCREEN_DEFAULT].height = GetSystemMetrics (SM_CYSCREEN); + vid_default = MODE_FULLSCREEN_DEFAULT; + leavecurrentmode = 1; + } + else + { + if (COM_CheckParm("-width")) + { + width = Q_atoi(com_argv[COM_CheckParm("-width")+1]); + } + else + { + width = 640; + } + + // jkrige - limit video modes + /*if (COM_CheckParm("-bpp")) + { + bpp = Q_atoi(com_argv[COM_CheckParm("-bpp")+1]); + findbpp = 0; + } + else + { + bpp = 15; + findbpp = 1; + }*/ + bpp = 16; + findbpp = 1; + // jkrige - limit video modes + + 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 = MS_FULLDIB; + 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; + + // jkrige - limit video modes + //sprintf (modelist[nummodes].modedesc, "%dx%dx%d", devmode.dmPelsWidth, devmode.dmPelsHeight, devmode.dmBitsPerPel); + sprintf (modelist[nummodes].modedesc, "%dx%d", devmode.dmPelsWidth, devmode.dmPelsHeight); + // jkrige - limit video modes + + for (i=nummodes, existingmode = 0 ; iwidth)/2, 4, p); + + vid_wmodes = 0; + lnummodes = VID_NumModes (); + + for (i=1 ; (i 0) + { + // jkrige - limit video modes + //M_Print (2*8, 36+0*8, "Fullscreen Modes (WIDTHxHEIGHTxBPP)"); + M_Print (4*8, 36+0*8, "Fullscreen Modes (WIDTHxHEIGHT)"); + // jkrige - limit video modes + + column = 8; + row = 36+2*8; + + for (i=0 ; i"); + // jkrige - limit video modes + //M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*4, "and -bpp "); + M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*4, "and -height "); + // jkrige - limit video modes + M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6, "Select windowed mode with -window"); +} + + +/* +================ +VID_MenuKey +================ +*/ +void VID_MenuKey (int key) +{ + switch (key) + { + case K_ESCAPE: + S_LocalSound ("misc/menu1.wav"); + M_Menu_Options_f (); + break; + + default: + break; + } +} diff --git a/engine/code/gl_warp.c b/engine/code/gl_warp.c new file mode 100644 index 0000000..5133f31 --- /dev/null +++ b/engine/code/gl_warp.c @@ -0,0 +1,1182 @@ +/* +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. + +*/ +// gl_warp.c -- sky and water polygons + +#include "quakedef.h" + +extern model_t *loadmodel; + +int skytexturenum; + +int solidskytexture; +int alphaskytexture; +float speedscale; // for top sky and bottom sky + +msurface_t *warpface; + +// jkrige - quake2 warps +//extern cvar_t gl_subdivide_size; +#define SUBDIVIDE_SIZE 64 +// jkrige - quake2 warps + +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; + } +} + +// jkrige - quake2 warps +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; + vec3_t total; + float total_s, total_t; + + if (numverts > 60) + Sys_Error ("numverts = %i", numverts); + + //if (numverts > 60) + // ri.Sys_Error (ERR_DROP, "numverts = %i", numverts); + + BoundPoly (numverts, verts, mins, maxs); + + for (i=0 ; i<3 ; i++) + { + m = (mins[i] + maxs[i]) * 0.5; + m = SUBDIVIDE_SIZE * floor (m/SUBDIVIDE_SIZE + 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; + } + + // add a point in the center to help keep warp valid + poly = Hunk_Alloc (sizeof(glpoly_t) + ((numverts-4)+2) * VERTEXSIZE*sizeof(float)); + poly->next = warpface->polys; + warpface->polys = poly; + poly->numverts = numverts+2; + VectorClear (total); + total_s = 0; + total_t = 0; + for (i=0 ; iverts[i+1]); + s = DotProduct (verts, warpface->texinfo->vecs[0]); + t = DotProduct (verts, warpface->texinfo->vecs[1]); + + total_s += s; + total_t += t; + VectorAdd (total, verts, total); + + poly->verts[i+1][3] = s; + poly->verts[i+1][4] = t; + } + + VectorScale (total, (1.0/numverts), poly->verts[0]); + poly->verts[0][3] = total_s/numverts; + poly->verts[0][4] = total_t/numverts; + + // copy first vertex to last + memcpy (poly->verts[i+1], poly->verts[1], sizeof(poly->verts[0])); +} + +/*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; + warpface->polys = 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; + } +}*/ +// jkrige - quake2 warps + +/* +================ +GL_SubdivideSurface + +Breaks a polygon up along axial 64 unit +boundaries so that turbulent and sky warps +can be done reasonably. +================ +*/ +void GL_SubdivideSurface (msurface_t *fa) +{ + vec3_t verts[64]; + int numverts; + int i; + int lindex; + float *vec; + //texture_t *t; + + warpface = fa; + + // + // 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++; + } + + SubdividePolygon (numverts, verts[0]); +} + +//========================================================= + + + +// speed up sin calculations - Ed +// jkrige - quake2 warps +/*float turbsin[] = +{ + #include "gl_warp_sin.h" +};*/ +// jkrige - quake2 warps +#define TURBSCALE (256.0 / (2 * M_PI)) + +/* +============= +EmitWaterPolys + +Does a water warp on the pre-fragmented glpoly_t chain +============= +*/ +// jkrige - quake2 warps +void EmitWaterPolys (msurface_t *fa) +{ + glpoly_t *p, *bp; + float *v; + int i; + float s, t, os, ot; + //float rdt = realtime; + + for (bp=fa->polys ; bp ; bp=bp->next) + { + p = bp; + + glBegin (GL_TRIANGLE_FAN); + for (i=0,v=p->verts[0] ; inumverts ; i++, v+=VERTEXSIZE) + { + os = v[3]; + ot = v[4]; + + //s = os + turbsin[(int)((ot * 0.125 + realtime) * TURBSCALE) & 255]; + s = os + sin(DEG2RAD((ot * 0.125 + realtime) * TURBSCALE)) * 3.7; + s *= (1.0/64); + + //t = ot + turbsin[(int)((os * 0.125 + realtime) * TURBSCALE) & 255]; + t = ot + sin(DEG2RAD((os * 0.125 + realtime) * TURBSCALE)) * 3.7; + t *= (1.0/64); + + glTexCoord2f (s, t); + glVertex3fv (v); + } + glEnd (); + } +} + +/*void EmitWaterPolys (msurface_t *fa) +{ + glpoly_t *p; + float *v; + int i; + float s, t, os, ot; + + + for (p=fa->polys ; p ; p=p->next) + { + glBegin (GL_POLYGON); + for (i=0,v=p->verts[0] ; inumverts ; i++, v+=VERTEXSIZE) + { + os = v[3]; + ot = v[4]; + + s = os + turbsin[(int)((ot*0.125+realtime) * TURBSCALE) & 255]; + s *= (1.0/64); + + t = ot + turbsin[(int)((os*0.125+realtime) * TURBSCALE) & 255]; + t *= (1.0/64); + + glTexCoord2f (s, t); + glVertex3fv (v); + } + glEnd (); + } +}*/ +// jkrige - quake2 warps + + + +/* +============= +EmitSkyPolys +============= +*/ +void EmitSkyPolys (msurface_t *fa) +{ + glpoly_t *p; + float *v; + int i; + float s, t; + vec3_t dir; + float length; + + // jkrige - wireframe + if (gl_wireframe.value) + return; + // jkrige - wireframe + + for (p=fa->polys ; p ; p=p->next) + { + glBegin (GL_POLYGON); + for (i=0,v=p->verts[0] ; inumverts ; i++, v+=VERTEXSIZE) + { + 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; + + dir[0] *= length; + dir[1] *= length; + + s = (speedscale + dir[0]) * (1.0/128); + t = (speedscale + dir[1]) * (1.0/128); + + glTexCoord2f (s, t); + glVertex3fv (v); + } + glEnd (); + } +} + +/* +=============== +EmitBothSkyLayers + +Does a sky warp on the pre-fragmented glpoly_t chain +This will be called for brushmodels, the world +will have them chained together. +=============== +*/ +void EmitBothSkyLayers (msurface_t *fa) +{ + int i; + int lindex; + float *vec; + + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + // jkrige - wireframe + if (gl_wireframe.value) + return; + // jkrige - wireframe + + GL_Bind (solidskytexture); + speedscale = realtime*8; + speedscale -= (int)speedscale & ~127 ; + + EmitSkyPolys (fa); + + glEnable (GL_BLEND); + GL_Bind (alphaskytexture); + speedscale = realtime*16; + speedscale -= (int)speedscale & ~127 ; + + EmitSkyPolys (fa); + + glDisable (GL_BLEND); +} + +#ifndef QUAKE2 +/* +================= +R_DrawSkyChain +================= +*/ +// jkrige - skybox +/*void R_DrawSkyChain (msurface_t *s) +{ + msurface_t *fa; + + // jkrige - remove multitexture + //GL_DisableMultitexture(); + // jkrige - remove multitexture + + // used when gl_texsort is on + GL_Bind(solidskytexture); + speedscale = realtime*8; + speedscale -= (int)speedscale & ~127 ; + + for (fa=s ; fa ; fa=fa->texturechain) + EmitSkyPolys (fa); + + glEnable (GL_BLEND); + GL_Bind (alphaskytexture); + speedscale = realtime*16; + speedscale -= (int)speedscale & ~127 ; + + for (fa=s ; fa ; fa=fa->texturechain) + EmitSkyPolys (fa); + + glDisable (GL_BLEND); +}*/ +// jkrige - skybox +#endif + +/* +================================================================= + + Quake 2 environment sky + +================================================================= +*/ + +//#ifdef QUAKE2 // jkrige - skybox + + +#define SKY_TEX 2560 // jkrige - skybox + +/* +================== +R_LoadSkys +================== +*/ +char *suf[6] = {"_rt", "_bk", "_lf", "_ft", "_up", "_dn"}; +// jkrige - skybox +/*void R_LoadSkys (void) +{ + int i; + FILE *f; + char name[64]; + + for (i=0 ; i<6 ; i++) + { + GL_Bind (SKY_TEX + i); + sprintf (name, "gfx/env/bkgtst%s.tga", suf[i]); + COM_FOpenFile (name, &f, false); + if (!f) + { + Con_Printf ("Couldn't load %s\n", name); + continue; + } + LoadTGA (f); +// LoadPCX (f); + + glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, targa_rgba); +// glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, pcx_rgb); + + free (targa_rgba); +// free (pcx_rgb); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } +}*/ + +void R_LoadSkys (void) +{ + int i; + char name[64]; + byte *data; + + for (i=0 ; i<6 ; i++) + { + sprintf (name, "skies/%s%s", cl.skybox, suf[i]); + if (!(data = LoadImagePixels (name, true))) + { + Cvar_Set("gl_skytype", "0"); + return; + } + + GL_Bind (SKY_TEX + i); + + if(image_bits == 8) + GL_Upload8 (data, image_width, image_height, false, false); + if(image_bits == 32) + GL_Upload32 ((void*)data, image_width, image_height, false, false); + + free(data); + + // jkrige - texture mode + if(gl_texturemode.value == 0.0f) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + // jkrige - texture mode + } + + Cvar_Set("gl_skytype", "1"); +} +// jkrige - skybox + + +vec3_t skyclip[6] = { + {1,1,0}, + {1,-1,0}, + {0,-1,1}, + {0,1,1}, + {1,0,1}, + {-1,0,1} +}; +int c_sky; + +// 1 = s, 2 = t, 3 = 2048 +int st_to_vec[6][3] = +{ + {3,-1,2}, + {-3,1,2}, + + {1,3,2}, + {-1,-3,2}, + + {-2,-1,3}, // 0 degrees yaw, look straight up + {2,-1,-3} // look straight down + +// {-1,2,3}, +// {1,2,-3} +}; + +// s = [0]/[2], t = [1]/[2] +int vec_to_st[6][3] = +{ + {-2,3,1}, + {2,3,-1}, + + {1,3,2}, + {-1,3,-2}, + + {-2,-1,3}, + {-2,1,-3} + +// {-1,2,3}, +// {1,2,-3} +}; + +#define MAX_CLIP_VERTS 64 +// jkrige - skybox (clipping) +//float skymins[2][6], skymaxs[2][6]; // jkrige - skybox + +/*void DrawSkyPolygon (int nump, vec3_t vecs) +{ + int i,j; + vec3_t v, av; + float s, t, dv; + int axis; + float *vp; + + c_sky++; +#if 0 +glBegin (GL_POLYGON); +for (i=0 ; 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; + } +} + +void ClipSkyPolygon (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 ("ClipSkyPolygon: MAX_CLIP_VERTS"); + if (stage == 6) + { // fully clipped, so draw it + DrawSkyPolygon (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 + ClipSkyPolygon (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 ; itexturechain) + EmitSkyPolys (fa); + + glEnable (GL_BLEND); + GL_Bind (alphaskytexture); + speedscale = realtime*16; + speedscale -= (int)speedscale & ~127; + + for (fa=s ; fa ; fa=fa->texturechain) + EmitSkyPolys (fa); + + glDisable (GL_BLEND); + } +} + + +/* +============== +R_ClearSkyBox +============== +*/ +// jkrige - skybox (clipping) +/*void R_ClearSkyBox (void) +{ + int i; + + for (i=0 ; i<6 ; i++) + { + skymins[0][i] = skymins[1][i] = 9999; + skymaxs[0][i] = skymaxs[1][i] = -9999; + } +}*/ +// jkrige - skybox (clipping) + + +void MakeSkyVec (float s, float t, int axis) +{ + vec3_t v, b; + int j, k; + + // jkrige - skybox (enlarged) + /*b[0] = s*2048; + b[1] = t*2048; + b[2] = 2048;*/ + b[0] = s*2360; + b[1] = t*2360; + b[2] = 2360; + // jkrige - skybox (enlarged) + + 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]; + } + + // avoid bilerp seam + s = (s+1)*0.5; + t = (t+1)*0.5; + + if (s < 1.0/512) + s = 1.0/512; + else if (s > 511.0/512) + s = 511.0/512; + if (t < 1.0/512) + t = 1.0/512; + else if (t > 511.0/512) + t = 511.0/512; + + t = 1.0 - t; + glTexCoord2f (s, t); + glVertex3fv (v); +} + +/* +============== +R_DrawSkyBox +============== +*/ +int skytexorder[6] = {0,2,1,3,4,5}; +void R_DrawSkyBox (void) +{ + int i, j, k; + vec3_t v; + float s, t; + + if(gl_skytype.value != 1) + return; + + // jkrige - wireframe + if (gl_wireframe.value) + return; + // jkrige - wireframe + +//#if 0 +//glEnable (GL_BLEND); +//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +//glColor4f (1,1,1,0.5); +glDisable (GL_DEPTH_TEST); // jkrige - skybox (disabled depth ckecking) +//#endif + + //glGetIntegerv(GL_DEPTH_FUNC, &gld); + //glDepthFunc(GL_GREATER); +//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +//glDisable (GL_DEPTH_TEST); + for (i=0 ; i<6 ; i++) + { + //if (skymins[0][i] >= skymaxs[0][i] + //|| skymins[1][i] >= skymaxs[1][i]) + // continue; + + GL_Bind (SKY_TEX+skytexorder[i]); + +//#if 0 // jkrige - skybox (enabled skybox with fixed mins/maxs) + //if(gl_fullskybox.value == 1) + //{ + // skymins[0][i] = -1; + // skymins[1][i] = -1; + // skymaxs[0][i] = 1; + // skymaxs[1][i] = 1; + //} +//#endif + glBegin (GL_QUADS); + MakeSkyVec (-1 /*skymins[0][i]*/, -1 /*skymins[1][i]*/, i); + MakeSkyVec (-1 /*skymins[0][i]*/, 1 /*skymaxs[1][i]*/, i); + MakeSkyVec (1 /*skymaxs[0][i]*/, 1 /*skymaxs[1][i]*/, i); + MakeSkyVec (1 /*skymaxs[0][i]*/, -1 /*skymins[1][i]*/, i); + glEnd (); + } + //glDepthFunc(gld); +//#if 0 +//glDisable (GL_BLEND); +//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +//glColor4f (1,1,1,0.5); +glEnable (GL_DEPTH_TEST); // jkrige - skybox (disabled depth ckecking) +//#endif +//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +//glEnable (GL_DEPTH_TEST); + + // jkrige - skybox test + //restore matrix and rendering state + //glPopMatrix(); + //glPopAttrib(); + // jkrige - skybox test +} + +//#endif // jkrige - skybox + + + +//=============================================================== + +/* +============= +R_InitSky + +A sky texture is 256*128, with the right side being a masked overlay +============== +*/ +void R_InitSky (texture_t *mt) +{ + int i, j, p; + byte *src; + unsigned trans[128*128]; + unsigned transpix; + int r, g, b; + unsigned *rgba; + extern int skytexturenum; + + + // jkrige - external texture loading + FILE *f2; + //qboolean ExtOK = false; + int FoundSolid = -1; + int FoundAlpha = -1; + char skytex_solid[MAX_QPATH]; + char skytex_alpha[MAX_QPATH]; + byte *skydata; + + // find solid sky texture + if(FoundSolid == -1) + { + sprintf (skytex_solid, "textures/%s/%s_solid.tga", sv.name, mt->name); + FoundSolid = COM_FOpenFile(skytex_solid, &f2); + } + if(FoundSolid == -1) + { + sprintf (skytex_solid, "textures/%s_solid.tga", mt->name); + FoundSolid = COM_FOpenFile(skytex_solid, &f2); + } + if(FoundSolid == -1) + { + sprintf (skytex_solid, "textures/%s/%s_solid.jpg", sv.name, mt->name); + FoundSolid = COM_FOpenFile(skytex_solid, &f2); + } + if(FoundSolid == -1) + { + sprintf (skytex_solid, "textures/%s_solid.jpg", mt->name); + FoundSolid = COM_FOpenFile(skytex_solid, &f2); + } + + // find alpha sky texture + if(FoundAlpha == -1) + { + sprintf (skytex_alpha, "textures/%s/%s_alpha.tga", sv.name, mt->name); + FoundAlpha = COM_FOpenFile(skytex_alpha, &f2); + } + if(FoundAlpha == -1) + { + sprintf (skytex_alpha, "textures/%s_alpha.tga", mt->name); + FoundAlpha = COM_FOpenFile(skytex_alpha, &f2); + } + if(FoundAlpha == -1) + { + sprintf (skytex_alpha, "textures/%s/%s_alpha.jpg", sv.name, mt->name); + FoundAlpha = COM_FOpenFile(skytex_alpha, &f2); + } + if(FoundAlpha == -1) + { + sprintf (skytex_alpha, "textures/%s_alpha.jpg", mt->name); + FoundAlpha = COM_FOpenFile(skytex_alpha, &f2); + } + + + if(FoundSolid != -1 && FoundAlpha != -1) + { + // load solid sky texture + if ((skydata = LoadImagePixels (skytex_solid, false))) + { + if (!solidskytexture) + solidskytexture = texture_extension_number++; + + GL_Bind (solidskytexture); + glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, skydata); + + if(gl_texturemode.value == 0.0f) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + free(skydata); + } + + // load alpha sky texture + if ((skydata = LoadImagePixels (skytex_alpha, false))) + { + if (!alphaskytexture) + alphaskytexture = texture_extension_number++; + + GL_Bind(alphaskytexture); + glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, skydata); + + if(gl_texturemode.value == 0.0f) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + free(skydata); + } + + return; + } + // jkrige - external texture loading + + + src = (byte *)mt + mt->offsets[0]; + + // make an average value for the back to avoid + // a fringe on the top level + + r = g = b = 0; + for (i=0 ; i<128 ; i++) + for (j=0 ; j<128 ; j++) + { + p = src[i*256 + j + 128]; + rgba = &d_8to24table[p]; + trans[(i*128) + j] = *rgba; + r += ((byte *)rgba)[0]; + g += ((byte *)rgba)[1]; + b += ((byte *)rgba)[2]; + } + + ((byte *)&transpix)[0] = r/(128*128); + ((byte *)&transpix)[1] = g/(128*128); + ((byte *)&transpix)[2] = b/(128*128); + ((byte *)&transpix)[3] = 0; + + + if (!solidskytexture) + solidskytexture = texture_extension_number++; + GL_Bind (solidskytexture ); + glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans); + + // jkrige - texture mode + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if(gl_texturemode.value == 0.0f) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + // jkrige - texture mode + + + for (i=0 ; i<128 ; i++) + for (j=0 ; j<128 ; j++) + { + p = src[i*256 + j]; + if (p == 0) + trans[(i*128) + j] = transpix; + else + trans[(i*128) + j] = d_8to24table[p]; + } + + if (!alphaskytexture) + alphaskytexture = texture_extension_number++; + GL_Bind(alphaskytexture); + glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans); + + // jkrige - texture mode + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if(gl_texturemode.value == 0.0f) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + // jkrige - texture mode +} + diff --git a/engine/code/gl_warp_sin.h b/engine/code/gl_warp_sin.h new file mode 100644 index 0000000..22976a7 --- /dev/null +++ b/engine/code/gl_warp_sin.h @@ -0,0 +1,51 @@ +/* +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. + +*/ + 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/engine/code/glext.h b/engine/code/glext.h new file mode 100644 index 0000000..4fcc17a --- /dev/null +++ b/engine/code/glext.h @@ -0,0 +1,12050 @@ +#ifndef __glext_h_ +#define __glext_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2013-2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +/* +** This header is generated from the Khronos OpenGL / OpenGL ES XML +** API Registry. The current version of the Registry, generator scripts +** used to make the header, and the header can be found at +** http://www.opengl.org/registry/ +** +** Khronos $Revision: 32518 $ on $Date: 2016-03-11 05:42:11 -0500 (Fri, 11 Mar 2016) $ +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif +#ifndef GLAPI +#define GLAPI extern +#endif + +#define GL_GLEXT_VERSION 20160311 + +/* Generated C header for: + * API: gl + * Profile: compatibility + * Versions considered: .* + * Versions emitted: 1\.[2-9]|[234]\.[0-9] + * Default extensions included: gl + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_RESCALE_NORMAL 0x803A +#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define GL_SINGLE_COLOR 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif +#endif /* GL_VERSION_1_2 */ + +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define GL_MULTISAMPLE_BIT 0x20000000 +#define GL_NORMAL_MAP 0x8511 +#define GL_REFLECTION_MAP 0x8512 +#define GL_COMPRESSED_ALPHA 0x84E9 +#define GL_COMPRESSED_LUMINANCE 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define GL_COMPRESSED_INTENSITY 0x84EC +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_RGB 0x8582 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_RGB 0x8592 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_RGB_SCALE 0x8573 +#define GL_ADD_SIGNED 0x8574 +#define GL_INTERPOLATE 0x8575 +#define GL_SUBTRACT 0x84E7 +#define GL_CONSTANT 0x8576 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PREVIOUS 0x8578 +#define GL_DOT3_RGB 0x86AE +#define GL_DOT3_RGBA 0x86AF +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img); +typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveTexture (GLenum texture); +GLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); +GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, void *img); +GLAPI void APIENTRY glClientActiveTexture (GLenum texture); +GLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s); +GLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord1f (GLenum target, GLfloat s); +GLAPI void APIENTRY glMultiTexCoord1fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord1i (GLenum target, GLint s); +GLAPI void APIENTRY glMultiTexCoord1iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord1s (GLenum target, GLshort s); +GLAPI void APIENTRY glMultiTexCoord1sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t); +GLAPI void APIENTRY glMultiTexCoord2dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t); +GLAPI void APIENTRY glMultiTexCoord2fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord2i (GLenum target, GLint s, GLint t); +GLAPI void APIENTRY glMultiTexCoord2iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord2s (GLenum target, GLshort s, GLshort t); +GLAPI void APIENTRY glMultiTexCoord2sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r); +GLAPI void APIENTRY glMultiTexCoord3dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r); +GLAPI void APIENTRY glMultiTexCoord3fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r); +GLAPI void APIENTRY glMultiTexCoord3iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r); +GLAPI void APIENTRY glMultiTexCoord3sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI void APIENTRY glMultiTexCoord4dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI void APIENTRY glMultiTexCoord4fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q); +GLAPI void APIENTRY glMultiTexCoord4iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI void APIENTRY glMultiTexCoord4sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *m); +GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *m); +GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *m); +GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m); +#endif +#endif /* GL_VERSION_1_3 */ + +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_GENERATE_MIPMAP 0x8191 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_FOG_COORDINATE_SOURCE 0x8450 +#define GL_FOG_COORDINATE 0x8451 +#define GL_FRAGMENT_DEPTH 0x8452 +#define GL_CURRENT_FOG_COORDINATE 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define GL_FOG_COORDINATE_ARRAY 0x8457 +#define GL_COLOR_SUM 0x8458 +#define GL_CURRENT_SECONDARY_COLOR 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define GL_SECONDARY_COLOR_ARRAY 0x845E +#define GL_TEXTURE_FILTER_CONTROL 0x8500 +#define GL_DEPTH_TEXTURE_MODE 0x884B +#define GL_COMPARE_R_TO_TEXTURE 0x884E +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); +typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); +typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); +typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); +GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); +GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params); +GLAPI void APIENTRY glFogCoordf (GLfloat coord); +GLAPI void APIENTRY glFogCoordfv (const GLfloat *coord); +GLAPI void APIENTRY glFogCoordd (GLdouble coord); +GLAPI void APIENTRY glFogCoorddv (const GLdouble *coord); +GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue); +GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v); +GLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue); +GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *v); +GLAPI void APIENTRY glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue); +GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *v); +GLAPI void APIENTRY glSecondaryColor3i (GLint red, GLint green, GLint blue); +GLAPI void APIENTRY glSecondaryColor3iv (const GLint *v); +GLAPI void APIENTRY glSecondaryColor3s (GLshort red, GLshort green, GLshort blue); +GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *v); +GLAPI void APIENTRY glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue); +GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *v); +GLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue); +GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v); +GLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue); +GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v); +GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y); +GLAPI void APIENTRY glWindowPos2dv (const GLdouble *v); +GLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y); +GLAPI void APIENTRY glWindowPos2fv (const GLfloat *v); +GLAPI void APIENTRY glWindowPos2i (GLint x, GLint y); +GLAPI void APIENTRY glWindowPos2iv (const GLint *v); +GLAPI void APIENTRY glWindowPos2s (GLshort x, GLshort y); +GLAPI void APIENTRY glWindowPos2sv (const GLshort *v); +GLAPI void APIENTRY glWindowPos3d (GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glWindowPos3dv (const GLdouble *v); +GLAPI void APIENTRY glWindowPos3f (GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glWindowPos3fv (const GLfloat *v); +GLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z); +GLAPI void APIENTRY glWindowPos3iv (const GLint *v); +GLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glWindowPos3sv (const GLshort *v); +GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI void APIENTRY glBlendEquation (GLenum mode); +#endif +#endif /* GL_VERSION_1_4 */ + +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +#include +typedef ptrdiff_t GLsizeiptr; +typedef ptrdiff_t GLintptr; +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_FOG_COORD_SRC 0x8450 +#define GL_FOG_COORD 0x8451 +#define GL_CURRENT_FOG_COORD 0x8453 +#define GL_FOG_COORD_ARRAY_TYPE 0x8454 +#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORD_ARRAY_POINTER 0x8456 +#define GL_FOG_COORD_ARRAY 0x8457 +#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D +#define GL_SRC0_RGB 0x8580 +#define GL_SRC1_RGB 0x8581 +#define GL_SRC2_RGB 0x8582 +#define GL_SRC0_ALPHA 0x8588 +#define GL_SRC2_ALPHA 0x858A +typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); +typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data); +typedef void *(APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); +GLAPI GLboolean APIENTRY glIsQuery (GLuint id); +GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id); +GLAPI void APIENTRY glEndQuery (GLenum target); +GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); +GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); +GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); +GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); +GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); +GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); +GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, void *data); +GLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access); +GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); +GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params); +#endif +#endif /* GL_VERSION_1_5 */ + +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +typedef char GLchar; +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_POINT_SPRITE 0x8861 +#define GL_COORD_REPLACE 0x8862 +#define GL_MAX_TEXTURE_COORDS 0x8871 +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); +typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); +typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); +GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); +GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader); +GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); +GLAPI void APIENTRY glCompileShader (GLuint shader); +GLAPI GLuint APIENTRY glCreateProgram (void); +GLAPI GLuint APIENTRY glCreateShader (GLenum type); +GLAPI void APIENTRY glDeleteProgram (GLuint program); +GLAPI void APIENTRY glDeleteShader (GLuint shader); +GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader); +GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index); +GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index); +GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); +GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); +GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); +GLAPI GLboolean APIENTRY glIsProgram (GLuint program); +GLAPI GLboolean APIENTRY glIsShader (GLuint shader); +GLAPI void APIENTRY glLinkProgram (GLuint program); +GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +GLAPI void APIENTRY glUseProgram (GLuint program); +GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0); +GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glUniform1i (GLint location, GLint v0); +GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glValidateProgram (GLuint program); +GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +#endif +#endif /* GL_VERSION_2_0 */ + +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F +#define GL_SLUMINANCE_ALPHA 0x8C44 +#define GL_SLUMINANCE8_ALPHA8 0x8C45 +#define GL_SLUMINANCE 0x8C46 +#define GL_SLUMINANCE8 0x8C47 +#define GL_COMPRESSED_SLUMINANCE 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#endif +#endif /* GL_VERSION_2_1 */ + +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +typedef unsigned short GLhalf; +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_COLOR_ATTACHMENT16 0x8CF0 +#define GL_COLOR_ATTACHMENT17 0x8CF1 +#define GL_COLOR_ATTACHMENT18 0x8CF2 +#define GL_COLOR_ATTACHMENT19 0x8CF3 +#define GL_COLOR_ATTACHMENT20 0x8CF4 +#define GL_COLOR_ATTACHMENT21 0x8CF5 +#define GL_COLOR_ATTACHMENT22 0x8CF6 +#define GL_COLOR_ATTACHMENT23 0x8CF7 +#define GL_COLOR_ATTACHMENT24 0x8CF8 +#define GL_COLOR_ATTACHMENT25 0x8CF9 +#define GL_COLOR_ATTACHMENT26 0x8CFA +#define GL_COLOR_ATTACHMENT27 0x8CFB +#define GL_COLOR_ATTACHMENT28 0x8CFC +#define GL_COLOR_ATTACHMENT29 0x8CFD +#define GL_COLOR_ATTACHMENT30 0x8CFE +#define GL_COLOR_ATTACHMENT31 0x8CFF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_INDEX 0x8222 +#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_CLAMP_VERTEX_COLOR 0x891A +#define GL_CLAMP_FRAGMENT_COLOR 0x891B +#define GL_ALPHA_INTEGER 0x8D97 +typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); +typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void *(APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); +GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); +GLAPI void APIENTRY glEnablei (GLenum target, GLuint index); +GLAPI void APIENTRY glDisablei (GLenum target, GLuint index); +GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index); +GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedback (void); +GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); +GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); +GLAPI void APIENTRY glEndConditionalRender (void); +GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); +GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); +GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y); +GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x); +GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y); +GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); +GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0); +GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); +GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); +GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); +GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index); +GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer); +GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); +GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); +GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer); +GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); +GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); +GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); +GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target); +GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glGenerateMipmap (GLenum target); +GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void *APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glBindVertexArray (GLuint array); +GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); +GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); +GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); +#endif +#endif /* GL_VERSION_3_0 */ + +#ifndef GL_VERSION_3_1 +#define GL_VERSION_3_1 1 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFFu +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); +GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); +GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); +GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#endif +#endif /* GL_VERSION_3_1 */ + +#ifndef GL_VERSION_3_2 +#define GL_VERSION_3_2 1 +typedef struct __GLsync *GLsync; +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glxext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GL_EXT_timer_query extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif +#endif +typedef uint64_t GLuint64; +typedef int64_t GLint64; +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); +typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); +typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); +GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); +GLAPI void APIENTRY glProvokingVertex (GLenum mode); +GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); +GLAPI GLboolean APIENTRY glIsSync (GLsync sync); +GLAPI void APIENTRY glDeleteSync (GLsync sync); +GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *data); +GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); +GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); +GLAPI void APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask); +#endif +#endif /* GL_VERSION_3_2 */ + +#ifndef GL_VERSION_3_3 +#define GL_VERSION_3_3 1 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define GL_SRC1_COLOR 0x88F9 +#define GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_SAMPLER_BINDING 0x8919 +#define GL_RGB10_A2UI 0x906F +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 +#define GL_TIME_ELAPSED 0x88BF +#define GL_TIMESTAMP 0x8E28 +#define GL_INT_2_10_10_10_REV 0x8D9F +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); +typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); +typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); +typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color); +typedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color); +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); +GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); +GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler); +GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler); +GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); +GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); +GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); +GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); +GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); +GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); +GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); +GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target); +GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params); +GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); +GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color); +GLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color); +GLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color); +GLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color); +GLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color); +GLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color); +#endif +#endif /* GL_VERSION_3_3 */ + +#ifndef GL_VERSION_4_0 +#define GL_VERSION_4_0 1 +#define GL_SAMPLE_SHADING 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F +#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F +#define GL_DRAW_INDIRECT_BUFFER 0x8F3F +#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 +#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F +#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A +#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B +#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C +#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D +#define GL_MAX_VERTEX_STREAMS 0x8E71 +#define GL_DOUBLE_VEC2 0x8FFC +#define GL_DOUBLE_VEC3 0x8FFD +#define GL_DOUBLE_VEC4 0x8FFE +#define GL_DOUBLE_MAT2 0x8F46 +#define GL_DOUBLE_MAT3 0x8F47 +#define GL_DOUBLE_MAT4 0x8F48 +#define GL_DOUBLE_MAT2x3 0x8F49 +#define GL_DOUBLE_MAT2x4 0x8F4A +#define GL_DOUBLE_MAT3x2 0x8F4B +#define GL_DOUBLE_MAT3x4 0x8F4C +#define GL_DOUBLE_MAT4x2 0x8F4D +#define GL_DOUBLE_MAT4x3 0x8F4E +#define GL_ACTIVE_SUBROUTINES 0x8DE5 +#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 +#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 +#define GL_MAX_SUBROUTINES 0x8DE7 +#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 +#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A +#define GL_COMPATIBLE_SUBROUTINES 0x8E4B +#define GL_PATCHES 0x000E +#define GL_PATCH_VERTICES 0x8E72 +#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 +#define GL_TESS_GEN_MODE 0x8E76 +#define GL_TESS_GEN_SPACING 0x8E77 +#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 +#define GL_TESS_GEN_POINT_MODE 0x8E79 +#define GL_ISOLINES 0x8E7A +#define GL_FRACTIONAL_ODD 0x8E7B +#define GL_FRACTIONAL_EVEN 0x8E7C +#define GL_MAX_PATCH_VERTICES 0x8E7D +#define GL_MAX_TESS_GEN_LEVEL 0x8E7E +#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F +#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 +#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 +#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 +#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 +#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 +#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 +#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 +#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 +#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A +#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C +#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D +#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E +#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#define GL_TESS_CONTROL_SHADER 0x8E88 +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 +#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 +typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value); +typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect); +typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); +typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params); +typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name); +typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices); +typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); +typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values); +typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); +typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); +typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream); +typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMinSampleShading (GLfloat value); +GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect); +GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect); +GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); +GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); +GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params); +GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name); +GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name); +GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices); +GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params); +GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values); +GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value); +GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values); +GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); +GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); +GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id); +GLAPI void APIENTRY glPauseTransformFeedback (void); +GLAPI void APIENTRY glResumeTransformFeedback (void); +GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id); +GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream); +GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id); +GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index); +GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params); +#endif +#endif /* GL_VERSION_4_0 */ + +#ifndef GL_VERSION_4_1 +#define GL_VERSION_4_1 1 +#define GL_FIXED 0x140C +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_RGB565 0x8D62 +#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#define GL_PROGRAM_BINARY_FORMATS 0x87FF +#define GL_VERTEX_SHADER_BIT 0x00000001 +#define GL_FRAGMENT_SHADER_BIT 0x00000002 +#define GL_GEOMETRY_SHADER_BIT 0x00000004 +#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 +#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 +#define GL_ALL_SHADER_BITS 0xFFFFFFFF +#define GL_PROGRAM_SEPARABLE 0x8258 +#define GL_ACTIVE_PROGRAM 0x8259 +#define GL_PROGRAM_PIPELINE_BINDING 0x825A +#define GL_MAX_VIEWPORTS 0x825B +#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C +#define GL_VIEWPORT_BOUNDS_RANGE 0x825D +#define GL_LAYER_PROVOKING_VERTEX 0x825E +#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F +#define GL_UNDEFINED_VERTEX 0x8260 +typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); +typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); +typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); +typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); +typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); +typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings); +typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); +typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); +typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f); +typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); +typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReleaseShaderCompiler (void); +GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); +GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +GLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f); +GLAPI void APIENTRY glClearDepthf (GLfloat d); +GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); +GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); +GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); +GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); +GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings); +GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); +GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); +GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); +GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); +GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); +GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0); +GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); +GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1); +GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v); +GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v); +GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLdouble n, GLdouble f); +GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data); +GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data); +#endif +#endif /* GL_VERSION_4_1 */ + +#ifndef GL_VERSION_4_2 +#define GL_VERSION_4_2 1 +#define GL_COPY_READ_BUFFER_BINDING 0x8F36 +#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 +#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 +#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 +#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 +#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 +#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A +#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B +#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C +#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D +#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E +#define GL_NUM_SAMPLE_COUNTS 0x9380 +#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC +#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 +#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 +#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 +#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 +#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB +#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE +#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF +#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 +#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 +#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 +#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 +#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC +#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 +#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA +#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 +#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 +#define GL_COMMAND_BARRIER_BIT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 +#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 +#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 +#define GL_ALL_BARRIER_BITS 0xFFFFFFFF +#define GL_MAX_IMAGE_UNITS 0x8F38 +#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 +#define GL_IMAGE_BINDING_NAME 0x8F3A +#define GL_IMAGE_BINDING_LEVEL 0x8F3B +#define GL_IMAGE_BINDING_LAYERED 0x8F3C +#define GL_IMAGE_BINDING_LAYER 0x8F3D +#define GL_IMAGE_BINDING_ACCESS 0x8F3E +#define GL_IMAGE_1D 0x904C +#define GL_IMAGE_2D 0x904D +#define GL_IMAGE_3D 0x904E +#define GL_IMAGE_2D_RECT 0x904F +#define GL_IMAGE_CUBE 0x9050 +#define GL_IMAGE_BUFFER 0x9051 +#define GL_IMAGE_1D_ARRAY 0x9052 +#define GL_IMAGE_2D_ARRAY 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 +#define GL_INT_IMAGE_1D 0x9057 +#define GL_INT_IMAGE_2D 0x9058 +#define GL_INT_IMAGE_3D 0x9059 +#define GL_INT_IMAGE_2D_RECT 0x905A +#define GL_INT_IMAGE_CUBE 0x905B +#define GL_INT_IMAGE_BUFFER 0x905C +#define GL_INT_IMAGE_1D_ARRAY 0x905D +#define GL_INT_IMAGE_2D_ARRAY 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 +#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 +#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C +#define GL_MAX_IMAGE_SAMPLES 0x906D +#define GL_IMAGE_BINDING_FORMAT 0x906E +#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 +#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA +#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB +#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD +#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE +#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F +#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); +typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); +GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); +GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); +GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei instancecount); +GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +#endif +#endif /* GL_VERSION_4_2 */ + +#ifndef GL_VERSION_4_3 +#define GL_VERSION_4_3 1 +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 +#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 +#define GL_COMPRESSED_R11_EAC 0x9270 +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define GL_COMPRESSED_RG11_EAC 0x9272 +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A +#define GL_MAX_ELEMENT_INDEX 0x8D6B +#define GL_COMPUTE_SHADER 0x91B9 +#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB +#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC +#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD +#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 +#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 +#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 +#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 +#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 +#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB +#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE +#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF +#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED +#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE +#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF +#define GL_COMPUTE_SHADER_BIT 0x00000020 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_MAX_UNIFORM_LOCATIONS 0x826E +#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 +#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 +#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 +#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 +#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 +#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 +#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 +#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 +#define GL_INTERNALFORMAT_SUPPORTED 0x826F +#define GL_INTERNALFORMAT_PREFERRED 0x8270 +#define GL_INTERNALFORMAT_RED_SIZE 0x8271 +#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 +#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 +#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 +#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 +#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 +#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 +#define GL_INTERNALFORMAT_RED_TYPE 0x8278 +#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 +#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A +#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B +#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C +#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D +#define GL_MAX_WIDTH 0x827E +#define GL_MAX_HEIGHT 0x827F +#define GL_MAX_DEPTH 0x8280 +#define GL_MAX_LAYERS 0x8281 +#define GL_MAX_COMBINED_DIMENSIONS 0x8282 +#define GL_COLOR_COMPONENTS 0x8283 +#define GL_DEPTH_COMPONENTS 0x8284 +#define GL_STENCIL_COMPONENTS 0x8285 +#define GL_COLOR_RENDERABLE 0x8286 +#define GL_DEPTH_RENDERABLE 0x8287 +#define GL_STENCIL_RENDERABLE 0x8288 +#define GL_FRAMEBUFFER_RENDERABLE 0x8289 +#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A +#define GL_FRAMEBUFFER_BLEND 0x828B +#define GL_READ_PIXELS 0x828C +#define GL_READ_PIXELS_FORMAT 0x828D +#define GL_READ_PIXELS_TYPE 0x828E +#define GL_TEXTURE_IMAGE_FORMAT 0x828F +#define GL_TEXTURE_IMAGE_TYPE 0x8290 +#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 +#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 +#define GL_MIPMAP 0x8293 +#define GL_MANUAL_GENERATE_MIPMAP 0x8294 +#define GL_AUTO_GENERATE_MIPMAP 0x8295 +#define GL_COLOR_ENCODING 0x8296 +#define GL_SRGB_READ 0x8297 +#define GL_SRGB_WRITE 0x8298 +#define GL_FILTER 0x829A +#define GL_VERTEX_TEXTURE 0x829B +#define GL_TESS_CONTROL_TEXTURE 0x829C +#define GL_TESS_EVALUATION_TEXTURE 0x829D +#define GL_GEOMETRY_TEXTURE 0x829E +#define GL_FRAGMENT_TEXTURE 0x829F +#define GL_COMPUTE_TEXTURE 0x82A0 +#define GL_TEXTURE_SHADOW 0x82A1 +#define GL_TEXTURE_GATHER 0x82A2 +#define GL_TEXTURE_GATHER_SHADOW 0x82A3 +#define GL_SHADER_IMAGE_LOAD 0x82A4 +#define GL_SHADER_IMAGE_STORE 0x82A5 +#define GL_SHADER_IMAGE_ATOMIC 0x82A6 +#define GL_IMAGE_TEXEL_SIZE 0x82A7 +#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 +#define GL_IMAGE_PIXEL_FORMAT 0x82A9 +#define GL_IMAGE_PIXEL_TYPE 0x82AA +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF +#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 +#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 +#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 +#define GL_CLEAR_BUFFER 0x82B4 +#define GL_TEXTURE_VIEW 0x82B5 +#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 +#define GL_FULL_SUPPORT 0x82B7 +#define GL_CAVEAT_SUPPORT 0x82B8 +#define GL_IMAGE_CLASS_4_X_32 0x82B9 +#define GL_IMAGE_CLASS_2_X_32 0x82BA +#define GL_IMAGE_CLASS_1_X_32 0x82BB +#define GL_IMAGE_CLASS_4_X_16 0x82BC +#define GL_IMAGE_CLASS_2_X_16 0x82BD +#define GL_IMAGE_CLASS_1_X_16 0x82BE +#define GL_IMAGE_CLASS_4_X_8 0x82BF +#define GL_IMAGE_CLASS_2_X_8 0x82C0 +#define GL_IMAGE_CLASS_1_X_8 0x82C1 +#define GL_IMAGE_CLASS_11_11_10 0x82C2 +#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 +#define GL_VIEW_CLASS_128_BITS 0x82C4 +#define GL_VIEW_CLASS_96_BITS 0x82C5 +#define GL_VIEW_CLASS_64_BITS 0x82C6 +#define GL_VIEW_CLASS_48_BITS 0x82C7 +#define GL_VIEW_CLASS_32_BITS 0x82C8 +#define GL_VIEW_CLASS_24_BITS 0x82C9 +#define GL_VIEW_CLASS_16_BITS 0x82CA +#define GL_VIEW_CLASS_8_BITS 0x82CB +#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC +#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD +#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE +#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF +#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 +#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 +#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 +#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 +#define GL_UNIFORM 0x92E1 +#define GL_UNIFORM_BLOCK 0x92E2 +#define GL_PROGRAM_INPUT 0x92E3 +#define GL_PROGRAM_OUTPUT 0x92E4 +#define GL_BUFFER_VARIABLE 0x92E5 +#define GL_SHADER_STORAGE_BLOCK 0x92E6 +#define GL_VERTEX_SUBROUTINE 0x92E8 +#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 +#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA +#define GL_GEOMETRY_SUBROUTINE 0x92EB +#define GL_FRAGMENT_SUBROUTINE 0x92EC +#define GL_COMPUTE_SUBROUTINE 0x92ED +#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE +#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF +#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 +#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 +#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 +#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 +#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 +#define GL_ACTIVE_RESOURCES 0x92F5 +#define GL_MAX_NAME_LENGTH 0x92F6 +#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 +#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 +#define GL_NAME_LENGTH 0x92F9 +#define GL_TYPE 0x92FA +#define GL_ARRAY_SIZE 0x92FB +#define GL_OFFSET 0x92FC +#define GL_BLOCK_INDEX 0x92FD +#define GL_ARRAY_STRIDE 0x92FE +#define GL_MATRIX_STRIDE 0x92FF +#define GL_IS_ROW_MAJOR 0x9300 +#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 +#define GL_BUFFER_BINDING 0x9302 +#define GL_BUFFER_DATA_SIZE 0x9303 +#define GL_NUM_ACTIVE_VARIABLES 0x9304 +#define GL_ACTIVE_VARIABLES 0x9305 +#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 +#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 +#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 +#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 +#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A +#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B +#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C +#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D +#define GL_LOCATION 0x930E +#define GL_LOCATION_INDEX 0x930F +#define GL_IS_PER_PATCH 0x92E7 +#define GL_SHADER_STORAGE_BUFFER 0x90D2 +#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 +#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 +#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 +#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 +#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 +#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 +#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 +#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA +#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB +#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC +#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD +#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE +#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF +#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 +#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 +#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA +#define GL_TEXTURE_BUFFER_OFFSET 0x919D +#define GL_TEXTURE_BUFFER_SIZE 0x919E +#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F +#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB +#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC +#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD +#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#define GL_VERTEX_ATTRIB_BINDING 0x82D4 +#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 +#define GL_VERTEX_BINDING_DIVISOR 0x82D6 +#define GL_VERTEX_BINDING_OFFSET 0x82D7 +#define GL_VERTEX_BINDING_STRIDE 0x82D8 +#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 +#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA +#define GL_VERTEX_BINDING_BUFFER 0x8F4F +#define GL_DISPLAY_LIST 0x82E7 +typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); +typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); +typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); +typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); +typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); +typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void); +typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClearBufferData (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearBufferSubData (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +GLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect); +GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +GLAPI void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +GLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level); +GLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glInvalidateBufferData (GLuint buffer); +GLAPI void APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); +GLAPI void APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glMultiDrawArraysIndirect (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params); +GLAPI GLuint APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI void APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +GLAPI GLint APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI GLint APIENTRY glGetProgramResourceLocationIndex (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI void APIENTRY glShaderStorageBlockBinding (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +GLAPI void APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureView (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +GLAPI void APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribLFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message); +GLAPI void APIENTRY glPopDebugGroup (void); +GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +#endif +#endif /* GL_VERSION_4_3 */ + +#ifndef GL_VERSION_4_4 +#define GL_VERSION_4_4 1 +#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 +#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 +#define GL_TEXTURE_BUFFER_BINDING 0x8C2A +#define GL_MAP_PERSISTENT_BIT 0x0040 +#define GL_MAP_COHERENT_BIT 0x0080 +#define GL_DYNAMIC_STORAGE_BIT 0x0100 +#define GL_CLIENT_STORAGE_BIT 0x0200 +#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 +#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F +#define GL_BUFFER_STORAGE_FLAGS 0x8220 +#define GL_CLEAR_TEXTURE 0x9365 +#define GL_LOCATION_COMPONENT 0x934A +#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B +#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C +#define GL_QUERY_BUFFER 0x9192 +#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 +#define GL_QUERY_BUFFER_BINDING 0x9193 +#define GL_QUERY_RESULT_NO_WAIT 0x9194 +#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 +typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); +typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); +typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); +typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers); +typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); +typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferStorage (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +GLAPI void APIENTRY glClearTexImage (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glBindBuffersBase (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); +GLAPI void APIENTRY glBindBuffersRange (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); +GLAPI void APIENTRY glBindTextures (GLuint first, GLsizei count, const GLuint *textures); +GLAPI void APIENTRY glBindSamplers (GLuint first, GLsizei count, const GLuint *samplers); +GLAPI void APIENTRY glBindImageTextures (GLuint first, GLsizei count, const GLuint *textures); +GLAPI void APIENTRY glBindVertexBuffers (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +#endif +#endif /* GL_VERSION_4_4 */ + +#ifndef GL_VERSION_4_5 +#define GL_VERSION_4_5 1 +#define GL_CONTEXT_LOST 0x0507 +#define GL_NEGATIVE_ONE_TO_ONE 0x935E +#define GL_ZERO_TO_ONE 0x935F +#define GL_CLIP_ORIGIN 0x935C +#define GL_CLIP_DEPTH_MODE 0x935D +#define GL_QUERY_WAIT_INVERTED 0x8E17 +#define GL_QUERY_NO_WAIT_INVERTED 0x8E18 +#define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19 +#define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A +#define GL_MAX_CULL_DISTANCES 0x82F9 +#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA +#define GL_TEXTURE_TARGET 0x1006 +#define GL_QUERY_TARGET 0x82EA +#define GL_GUILTY_CONTEXT_RESET 0x8253 +#define GL_INNOCENT_CONTEXT_RESET 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET 0x8255 +#define GL_RESET_NOTIFICATION_STRATEGY 0x8256 +#define GL_LOSE_CONTEXT_ON_RESET 0x8252 +#define GL_NO_RESET_NOTIFICATION 0x8261 +#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004 +#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB +#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC +typedef void (APIENTRYP PFNGLCLIPCONTROLPROC) (GLenum origin, GLenum depth); +typedef void (APIENTRYP PFNGLCREATETRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC) (GLuint xfb, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC) (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKIVPROC) (GLuint xfb, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param); +typedef void (APIENTRYP PFNGLCREATEBUFFERSPROC) (GLsizei n, GLuint *buffers); +typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); +typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); +typedef void (APIENTRYP PFNGLCOPYNAMEDBUFFERSUBDATAPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERPROC) (GLuint buffer, GLenum access); +typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFERPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVPROC) (GLuint buffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERI64VPROC) (GLuint buffer, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVPROC) (GLuint buffer, GLenum pname, void **params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); +typedef void (APIENTRYP PFNGLCREATEFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC) (GLuint framebuffer, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC) (GLuint framebuffer, GLenum buf); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC) (GLuint framebuffer, GLenum src); +typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments); +typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value); +typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value); +typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value); +typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +typedef void (APIENTRYP PFNGLBLITNAMEDFRAMEBUFFERPROC) (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC) (GLuint framebuffer, GLenum target); +typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC) (GLuint framebuffer, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLCREATERENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC) (GLuint renderbuffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLCREATETEXTURESPROC) (GLenum target, GLsizei n, GLuint *textures); +typedef void (APIENTRYP PFNGLTEXTUREBUFFERPROC) (GLuint texture, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEPROC) (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFPROC) (GLuint texture, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, const GLfloat *param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIPROC) (GLuint texture, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPPROC) (GLuint texture); +typedef void (APIENTRYP PFNGLBINDTEXTUREUNITPROC) (GLuint unit, GLuint texture); +typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLsizei bufSize, void *pixels); +typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVPROC) (GLuint texture, GLint level, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVPROC) (GLuint texture, GLint level, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLCREATEVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); +typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index); +typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index); +typedef void (APIENTRYP PFNGLVERTEXARRAYELEMENTBUFFERPROC) (GLuint vaobj, GLuint buffer); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERSPROC) (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBBINDINGPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBIFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBLFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYBINDINGDIVISORPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYIVPROC) (GLuint vaobj, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXEDIVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXED64IVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param); +typedef void (APIENTRYP PFNGLCREATESAMPLERSPROC) (GLsizei n, GLuint *samplers); +typedef void (APIENTRYP PFNGLCREATEPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); +typedef void (APIENTRYP PFNGLCREATEQUERIESPROC) (GLenum target, GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +typedef void (APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC) (GLbitfield barriers); +typedef void (APIENTRYP PFNGLGETTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels); +typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC) (void); +typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint lod, GLsizei bufSize, void *pixels); +typedef void (APIENTRYP PFNGLGETNTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +typedef void (APIENTRYP PFNGLGETNUNIFORMDVPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMFVPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +typedef void (APIENTRYP PFNGLREADNPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +typedef void (APIENTRYP PFNGLGETNMAPDVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); +typedef void (APIENTRYP PFNGLGETNMAPFVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); +typedef void (APIENTRYP PFNGLGETNMAPIVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); +typedef void (APIENTRYP PFNGLGETNPIXELMAPFVPROC) (GLenum map, GLsizei bufSize, GLfloat *values); +typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVPROC) (GLenum map, GLsizei bufSize, GLuint *values); +typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVPROC) (GLenum map, GLsizei bufSize, GLushort *values); +typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEPROC) (GLsizei bufSize, GLubyte *pattern); +typedef void (APIENTRYP PFNGLGETNCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); +typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); +typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); +typedef void (APIENTRYP PFNGLGETNHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +typedef void (APIENTRYP PFNGLGETNMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +typedef void (APIENTRYP PFNGLTEXTUREBARRIERPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClipControl (GLenum origin, GLenum depth); +GLAPI void APIENTRY glCreateTransformFeedbacks (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glTransformFeedbackBufferBase (GLuint xfb, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackBufferRange (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glGetTransformFeedbackiv (GLuint xfb, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetTransformFeedbacki_v (GLuint xfb, GLenum pname, GLuint index, GLint *param); +GLAPI void APIENTRY glGetTransformFeedbacki64_v (GLuint xfb, GLenum pname, GLuint index, GLint64 *param); +GLAPI void APIENTRY glCreateBuffers (GLsizei n, GLuint *buffers); +GLAPI void APIENTRY glNamedBufferStorage (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); +GLAPI void APIENTRY glNamedBufferData (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); +GLAPI void APIENTRY glNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI void APIENTRY glCopyNamedBufferSubData (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI void APIENTRY glClearNamedBufferData (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearNamedBufferSubData (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +GLAPI void *APIENTRY glMapNamedBuffer (GLuint buffer, GLenum access); +GLAPI void *APIENTRY glMapNamedBufferRange (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI GLboolean APIENTRY glUnmapNamedBuffer (GLuint buffer); +GLAPI void APIENTRY glFlushMappedNamedBufferRange (GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glGetNamedBufferParameteriv (GLuint buffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetNamedBufferParameteri64v (GLuint buffer, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetNamedBufferPointerv (GLuint buffer, GLenum pname, void **params); +GLAPI void APIENTRY glGetNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); +GLAPI void APIENTRY glCreateFramebuffers (GLsizei n, GLuint *framebuffers); +GLAPI void APIENTRY glNamedFramebufferRenderbuffer (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glNamedFramebufferParameteri (GLuint framebuffer, GLenum pname, GLint param); +GLAPI void APIENTRY glNamedFramebufferTexture (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTextureLayer (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glNamedFramebufferDrawBuffer (GLuint framebuffer, GLenum buf); +GLAPI void APIENTRY glNamedFramebufferDrawBuffers (GLuint framebuffer, GLsizei n, const GLenum *bufs); +GLAPI void APIENTRY glNamedFramebufferReadBuffer (GLuint framebuffer, GLenum src); +GLAPI void APIENTRY glInvalidateNamedFramebufferData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments); +GLAPI void APIENTRY glInvalidateNamedFramebufferSubData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glClearNamedFramebufferiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value); +GLAPI void APIENTRY glClearNamedFramebufferuiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value); +GLAPI void APIENTRY glClearNamedFramebufferfv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value); +GLAPI void APIENTRY glClearNamedFramebufferfi (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI void APIENTRY glBlitNamedFramebuffer (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI GLenum APIENTRY glCheckNamedFramebufferStatus (GLuint framebuffer, GLenum target); +GLAPI void APIENTRY glGetNamedFramebufferParameteriv (GLuint framebuffer, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameteriv (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glCreateRenderbuffers (GLsizei n, GLuint *renderbuffers); +GLAPI void APIENTRY glNamedRenderbufferStorage (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisample (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetNamedRenderbufferParameteriv (GLuint renderbuffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glCreateTextures (GLenum target, GLsizei n, GLuint *textures); +GLAPI void APIENTRY glTextureBuffer (GLuint texture, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glTextureBufferRange (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTextureStorage1D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTextureStorage2D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTextureStorage3D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glTextureStorage2DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureStorage3DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCompressedTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCopyTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glCopyTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTextureParameterf (GLuint texture, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTextureParameterfv (GLuint texture, GLenum pname, const GLfloat *param); +GLAPI void APIENTRY glTextureParameteri (GLuint texture, GLenum pname, GLint param); +GLAPI void APIENTRY glTextureParameterIiv (GLuint texture, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTextureParameterIuiv (GLuint texture, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glTextureParameteriv (GLuint texture, GLenum pname, const GLint *param); +GLAPI void APIENTRY glGenerateTextureMipmap (GLuint texture); +GLAPI void APIENTRY glBindTextureUnit (GLuint unit, GLuint texture); +GLAPI void APIENTRY glGetTextureImage (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +GLAPI void APIENTRY glGetCompressedTextureImage (GLuint texture, GLint level, GLsizei bufSize, void *pixels); +GLAPI void APIENTRY glGetTextureLevelParameterfv (GLuint texture, GLint level, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTextureLevelParameteriv (GLuint texture, GLint level, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTextureParameterfv (GLuint texture, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTextureParameterIiv (GLuint texture, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTextureParameterIuiv (GLuint texture, GLenum pname, GLuint *params); +GLAPI void APIENTRY glGetTextureParameteriv (GLuint texture, GLenum pname, GLint *params); +GLAPI void APIENTRY glCreateVertexArrays (GLsizei n, GLuint *arrays); +GLAPI void APIENTRY glDisableVertexArrayAttrib (GLuint vaobj, GLuint index); +GLAPI void APIENTRY glEnableVertexArrayAttrib (GLuint vaobj, GLuint index); +GLAPI void APIENTRY glVertexArrayElementBuffer (GLuint vaobj, GLuint buffer); +GLAPI void APIENTRY glVertexArrayVertexBuffer (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexArrayVertexBuffers (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +GLAPI void APIENTRY glVertexArrayAttribBinding (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexArrayAttribFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayAttribIFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayAttribLFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayBindingDivisor (GLuint vaobj, GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glGetVertexArrayiv (GLuint vaobj, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetVertexArrayIndexediv (GLuint vaobj, GLuint index, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetVertexArrayIndexed64iv (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param); +GLAPI void APIENTRY glCreateSamplers (GLsizei n, GLuint *samplers); +GLAPI void APIENTRY glCreateProgramPipelines (GLsizei n, GLuint *pipelines); +GLAPI void APIENTRY glCreateQueries (GLenum target, GLsizei n, GLuint *ids); +GLAPI void APIENTRY glGetQueryBufferObjecti64v (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +GLAPI void APIENTRY glGetQueryBufferObjectiv (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +GLAPI void APIENTRY glGetQueryBufferObjectui64v (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +GLAPI void APIENTRY glGetQueryBufferObjectuiv (GLuint id, GLuint buffer, GLenum pname, GLintptr offset); +GLAPI void APIENTRY glMemoryBarrierByRegion (GLbitfield barriers); +GLAPI void APIENTRY glGetTextureSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +GLAPI void APIENTRY glGetCompressedTextureSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels); +GLAPI GLenum APIENTRY glGetGraphicsResetStatus (void); +GLAPI void APIENTRY glGetnCompressedTexImage (GLenum target, GLint lod, GLsizei bufSize, void *pixels); +GLAPI void APIENTRY glGetnTexImage (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +GLAPI void APIENTRY glGetnUniformdv (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +GLAPI void APIENTRY glGetnUniformfv (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +GLAPI void APIENTRY glGetnUniformiv (GLuint program, GLint location, GLsizei bufSize, GLint *params); +GLAPI void APIENTRY glGetnUniformuiv (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +GLAPI void APIENTRY glReadnPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +GLAPI void APIENTRY glGetnMapdv (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); +GLAPI void APIENTRY glGetnMapfv (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); +GLAPI void APIENTRY glGetnMapiv (GLenum target, GLenum query, GLsizei bufSize, GLint *v); +GLAPI void APIENTRY glGetnPixelMapfv (GLenum map, GLsizei bufSize, GLfloat *values); +GLAPI void APIENTRY glGetnPixelMapuiv (GLenum map, GLsizei bufSize, GLuint *values); +GLAPI void APIENTRY glGetnPixelMapusv (GLenum map, GLsizei bufSize, GLushort *values); +GLAPI void APIENTRY glGetnPolygonStipple (GLsizei bufSize, GLubyte *pattern); +GLAPI void APIENTRY glGetnColorTable (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); +GLAPI void APIENTRY glGetnConvolutionFilter (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); +GLAPI void APIENTRY glGetnSeparableFilter (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); +GLAPI void APIENTRY glGetnHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +GLAPI void APIENTRY glGetnMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +GLAPI void APIENTRY glTextureBarrier (void); +#endif +#endif /* GL_VERSION_4_5 */ + +#ifndef GL_ARB_ES2_compatibility +#define GL_ARB_ES2_compatibility 1 +#endif /* GL_ARB_ES2_compatibility */ + +#ifndef GL_ARB_ES3_1_compatibility +#define GL_ARB_ES3_1_compatibility 1 +#endif /* GL_ARB_ES3_1_compatibility */ + +#ifndef GL_ARB_ES3_2_compatibility +#define GL_ARB_ES3_2_compatibility 1 +#define GL_PRIMITIVE_BOUNDING_BOX_ARB 0x92BE +#define GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381 +#define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382 +typedef void (APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXARBPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPrimitiveBoundingBoxARB (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); +#endif +#endif /* GL_ARB_ES3_2_compatibility */ + +#ifndef GL_ARB_ES3_compatibility +#define GL_ARB_ES3_compatibility 1 +#endif /* GL_ARB_ES3_compatibility */ + +#ifndef GL_ARB_arrays_of_arrays +#define GL_ARB_arrays_of_arrays 1 +#endif /* GL_ARB_arrays_of_arrays */ + +#ifndef GL_ARB_base_instance +#define GL_ARB_base_instance 1 +#endif /* GL_ARB_base_instance */ + +#ifndef GL_ARB_bindless_texture +#define GL_ARB_bindless_texture 1 +typedef uint64_t GLuint64EXT; +#define GL_UNSIGNED_INT64_ARB 0x140F +typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC) (GLuint texture); +typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle); +typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint64 APIENTRY glGetTextureHandleARB (GLuint texture); +GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleARB (GLuint texture, GLuint sampler); +GLAPI void APIENTRY glMakeTextureHandleResidentARB (GLuint64 handle); +GLAPI void APIENTRY glMakeTextureHandleNonResidentARB (GLuint64 handle); +GLAPI GLuint64 APIENTRY glGetImageHandleARB (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +GLAPI void APIENTRY glMakeImageHandleResidentARB (GLuint64 handle, GLenum access); +GLAPI void APIENTRY glMakeImageHandleNonResidentARB (GLuint64 handle); +GLAPI void APIENTRY glUniformHandleui64ARB (GLint location, GLuint64 value); +GLAPI void APIENTRY glUniformHandleui64vARB (GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glProgramUniformHandleui64ARB (GLuint program, GLint location, GLuint64 value); +GLAPI void APIENTRY glProgramUniformHandleui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +GLAPI GLboolean APIENTRY glIsTextureHandleResidentARB (GLuint64 handle); +GLAPI GLboolean APIENTRY glIsImageHandleResidentARB (GLuint64 handle); +GLAPI void APIENTRY glVertexAttribL1ui64ARB (GLuint index, GLuint64EXT x); +GLAPI void APIENTRY glVertexAttribL1ui64vARB (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glGetVertexAttribLui64vARB (GLuint index, GLenum pname, GLuint64EXT *params); +#endif +#endif /* GL_ARB_bindless_texture */ + +#ifndef GL_ARB_blend_func_extended +#define GL_ARB_blend_func_extended 1 +#endif /* GL_ARB_blend_func_extended */ + +#ifndef GL_ARB_buffer_storage +#define GL_ARB_buffer_storage 1 +#endif /* GL_ARB_buffer_storage */ + +#ifndef GL_ARB_cl_event +#define GL_ARB_cl_event 1 +struct _cl_context; +struct _cl_event; +#define GL_SYNC_CL_EVENT_ARB 0x8240 +#define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 +typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); +#endif +#endif /* GL_ARB_cl_event */ + +#ifndef GL_ARB_clear_buffer_object +#define GL_ARB_clear_buffer_object 1 +#endif /* GL_ARB_clear_buffer_object */ + +#ifndef GL_ARB_clear_texture +#define GL_ARB_clear_texture 1 +#endif /* GL_ARB_clear_texture */ + +#ifndef GL_ARB_clip_control +#define GL_ARB_clip_control 1 +#endif /* GL_ARB_clip_control */ + +#ifndef GL_ARB_color_buffer_float +#define GL_ARB_color_buffer_float 1 +#define GL_RGBA_FLOAT_MODE_ARB 0x8820 +#define GL_CLAMP_VERTEX_COLOR_ARB 0x891A +#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B +#define GL_CLAMP_READ_COLOR_ARB 0x891C +#define GL_FIXED_ONLY_ARB 0x891D +typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp); +#endif +#endif /* GL_ARB_color_buffer_float */ + +#ifndef GL_ARB_compatibility +#define GL_ARB_compatibility 1 +#endif /* GL_ARB_compatibility */ + +#ifndef GL_ARB_compressed_texture_pixel_storage +#define GL_ARB_compressed_texture_pixel_storage 1 +#endif /* GL_ARB_compressed_texture_pixel_storage */ + +#ifndef GL_ARB_compute_shader +#define GL_ARB_compute_shader 1 +#endif /* GL_ARB_compute_shader */ + +#ifndef GL_ARB_compute_variable_group_size +#define GL_ARB_compute_variable_group_size 1 +#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344 +#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB +#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345 +#define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); +#endif +#endif /* GL_ARB_compute_variable_group_size */ + +#ifndef GL_ARB_conditional_render_inverted +#define GL_ARB_conditional_render_inverted 1 +#endif /* GL_ARB_conditional_render_inverted */ + +#ifndef GL_ARB_conservative_depth +#define GL_ARB_conservative_depth 1 +#endif /* GL_ARB_conservative_depth */ + +#ifndef GL_ARB_copy_buffer +#define GL_ARB_copy_buffer 1 +#endif /* GL_ARB_copy_buffer */ + +#ifndef GL_ARB_copy_image +#define GL_ARB_copy_image 1 +#endif /* GL_ARB_copy_image */ + +#ifndef GL_ARB_cull_distance +#define GL_ARB_cull_distance 1 +#endif /* GL_ARB_cull_distance */ + +#ifndef GL_ARB_debug_output +#define GL_ARB_debug_output 1 +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 +#define GL_DEBUG_SOURCE_API_ARB 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A +#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B +#define GL_DEBUG_TYPE_ERROR_ARB 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E +#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 +#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 +#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +#endif +#endif /* GL_ARB_debug_output */ + +#ifndef GL_ARB_depth_buffer_float +#define GL_ARB_depth_buffer_float 1 +#endif /* GL_ARB_depth_buffer_float */ + +#ifndef GL_ARB_depth_clamp +#define GL_ARB_depth_clamp 1 +#endif /* GL_ARB_depth_clamp */ + +#ifndef GL_ARB_depth_texture +#define GL_ARB_depth_texture 1 +#define GL_DEPTH_COMPONENT16_ARB 0x81A5 +#define GL_DEPTH_COMPONENT24_ARB 0x81A6 +#define GL_DEPTH_COMPONENT32_ARB 0x81A7 +#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A +#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B +#endif /* GL_ARB_depth_texture */ + +#ifndef GL_ARB_derivative_control +#define GL_ARB_derivative_control 1 +#endif /* GL_ARB_derivative_control */ + +#ifndef GL_ARB_direct_state_access +#define GL_ARB_direct_state_access 1 +#endif /* GL_ARB_direct_state_access */ + +#ifndef GL_ARB_draw_buffers +#define GL_ARB_draw_buffers 1 +#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 +#define GL_DRAW_BUFFER0_ARB 0x8825 +#define GL_DRAW_BUFFER1_ARB 0x8826 +#define GL_DRAW_BUFFER2_ARB 0x8827 +#define GL_DRAW_BUFFER3_ARB 0x8828 +#define GL_DRAW_BUFFER4_ARB 0x8829 +#define GL_DRAW_BUFFER5_ARB 0x882A +#define GL_DRAW_BUFFER6_ARB 0x882B +#define GL_DRAW_BUFFER7_ARB 0x882C +#define GL_DRAW_BUFFER8_ARB 0x882D +#define GL_DRAW_BUFFER9_ARB 0x882E +#define GL_DRAW_BUFFER10_ARB 0x882F +#define GL_DRAW_BUFFER11_ARB 0x8830 +#define GL_DRAW_BUFFER12_ARB 0x8831 +#define GL_DRAW_BUFFER13_ARB 0x8832 +#define GL_DRAW_BUFFER14_ARB 0x8833 +#define GL_DRAW_BUFFER15_ARB 0x8834 +typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawBuffersARB (GLsizei n, const GLenum *bufs); +#endif +#endif /* GL_ARB_draw_buffers */ + +#ifndef GL_ARB_draw_buffers_blend +#define GL_ARB_draw_buffers_blend 1 +typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#endif +#endif /* GL_ARB_draw_buffers_blend */ + +#ifndef GL_ARB_draw_elements_base_vertex +#define GL_ARB_draw_elements_base_vertex 1 +#endif /* GL_ARB_draw_elements_base_vertex */ + +#ifndef GL_ARB_draw_indirect +#define GL_ARB_draw_indirect 1 +#endif /* GL_ARB_draw_indirect */ + +#ifndef GL_ARB_draw_instanced +#define GL_ARB_draw_instanced 1 +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount); +GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +#endif +#endif /* GL_ARB_draw_instanced */ + +#ifndef GL_ARB_enhanced_layouts +#define GL_ARB_enhanced_layouts 1 +#endif /* GL_ARB_enhanced_layouts */ + +#ifndef GL_ARB_explicit_attrib_location +#define GL_ARB_explicit_attrib_location 1 +#endif /* GL_ARB_explicit_attrib_location */ + +#ifndef GL_ARB_explicit_uniform_location +#define GL_ARB_explicit_uniform_location 1 +#endif /* GL_ARB_explicit_uniform_location */ + +#ifndef GL_ARB_fragment_coord_conventions +#define GL_ARB_fragment_coord_conventions 1 +#endif /* GL_ARB_fragment_coord_conventions */ + +#ifndef GL_ARB_fragment_layer_viewport +#define GL_ARB_fragment_layer_viewport 1 +#endif /* GL_ARB_fragment_layer_viewport */ + +#ifndef GL_ARB_fragment_program +#define GL_ARB_fragment_program 1 +#define GL_FRAGMENT_PROGRAM_ARB 0x8804 +#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +#define GL_PROGRAM_LENGTH_ARB 0x8627 +#define GL_PROGRAM_FORMAT_ARB 0x8876 +#define GL_PROGRAM_BINDING_ARB 0x8677 +#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 +#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 +#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 +#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 +#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 +#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 +#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 +#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 +#define GL_PROGRAM_PARAMETERS_ARB 0x88A8 +#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 +#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA +#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB +#define GL_PROGRAM_ATTRIBS_ARB 0x88AC +#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD +#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE +#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF +#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 +#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 +#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 +#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 +#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 +#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 +#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 +#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 +#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A +#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B +#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C +#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D +#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E +#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F +#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 +#define GL_PROGRAM_STRING_ARB 0x8628 +#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B +#define GL_CURRENT_MATRIX_ARB 0x8641 +#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 +#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 +#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F +#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E +#define GL_MAX_TEXTURE_COORDS_ARB 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 +#define GL_PROGRAM_ERROR_STRING_ARB 0x8874 +#define GL_MATRIX0_ARB 0x88C0 +#define GL_MATRIX1_ARB 0x88C1 +#define GL_MATRIX2_ARB 0x88C2 +#define GL_MATRIX3_ARB 0x88C3 +#define GL_MATRIX4_ARB 0x88C4 +#define GL_MATRIX5_ARB 0x88C5 +#define GL_MATRIX6_ARB 0x88C6 +#define GL_MATRIX7_ARB 0x88C7 +#define GL_MATRIX8_ARB 0x88C8 +#define GL_MATRIX9_ARB 0x88C9 +#define GL_MATRIX10_ARB 0x88CA +#define GL_MATRIX11_ARB 0x88CB +#define GL_MATRIX12_ARB 0x88CC +#define GL_MATRIX13_ARB 0x88CD +#define GL_MATRIX14_ARB 0x88CE +#define GL_MATRIX15_ARB 0x88CF +#define GL_MATRIX16_ARB 0x88D0 +#define GL_MATRIX17_ARB 0x88D1 +#define GL_MATRIX18_ARB 0x88D2 +#define GL_MATRIX19_ARB 0x88D3 +#define GL_MATRIX20_ARB 0x88D4 +#define GL_MATRIX21_ARB 0x88D5 +#define GL_MATRIX22_ARB 0x88D6 +#define GL_MATRIX23_ARB 0x88D7 +#define GL_MATRIX24_ARB 0x88D8 +#define GL_MATRIX25_ARB 0x88D9 +#define GL_MATRIX26_ARB 0x88DA +#define GL_MATRIX27_ARB 0x88DB +#define GL_MATRIX28_ARB 0x88DC +#define GL_MATRIX29_ARB 0x88DD +#define GL_MATRIX30_ARB 0x88DE +#define GL_MATRIX31_ARB 0x88DF +typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string); +typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); +typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const void *string); +GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program); +GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs); +GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs); +GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); +GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); +GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); +GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); +GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, void *string); +GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program); +#endif +#endif /* GL_ARB_fragment_program */ + +#ifndef GL_ARB_fragment_program_shadow +#define GL_ARB_fragment_program_shadow 1 +#endif /* GL_ARB_fragment_program_shadow */ + +#ifndef GL_ARB_fragment_shader +#define GL_ARB_fragment_shader 1 +#define GL_FRAGMENT_SHADER_ARB 0x8B30 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B +#endif /* GL_ARB_fragment_shader */ + +#ifndef GL_ARB_fragment_shader_interlock +#define GL_ARB_fragment_shader_interlock 1 +#endif /* GL_ARB_fragment_shader_interlock */ + +#ifndef GL_ARB_framebuffer_no_attachments +#define GL_ARB_framebuffer_no_attachments 1 +#endif /* GL_ARB_framebuffer_no_attachments */ + +#ifndef GL_ARB_framebuffer_object +#define GL_ARB_framebuffer_object 1 +#endif /* GL_ARB_framebuffer_object */ + +#ifndef GL_ARB_framebuffer_sRGB +#define GL_ARB_framebuffer_sRGB 1 +#endif /* GL_ARB_framebuffer_sRGB */ + +#ifndef GL_ARB_geometry_shader4 +#define GL_ARB_geometry_shader4 1 +#define GL_LINES_ADJACENCY_ARB 0x000A +#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B +#define GL_TRIANGLES_ADJACENCY_ARB 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D +#define GL_PROGRAM_POINT_SIZE_ARB 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 +#define GL_GEOMETRY_SHADER_ARB 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA +#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB +#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC +#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD +#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value); +GLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#endif +#endif /* GL_ARB_geometry_shader4 */ + +#ifndef GL_ARB_get_program_binary +#define GL_ARB_get_program_binary 1 +#endif /* GL_ARB_get_program_binary */ + +#ifndef GL_ARB_get_texture_sub_image +#define GL_ARB_get_texture_sub_image 1 +#endif /* GL_ARB_get_texture_sub_image */ + +#ifndef GL_ARB_gpu_shader5 +#define GL_ARB_gpu_shader5 1 +#endif /* GL_ARB_gpu_shader5 */ + +#ifndef GL_ARB_gpu_shader_fp64 +#define GL_ARB_gpu_shader_fp64 1 +#endif /* GL_ARB_gpu_shader_fp64 */ + +#ifndef GL_ARB_gpu_shader_int64 +#define GL_ARB_gpu_shader_int64 1 +#define GL_INT64_ARB 0x140E +#define GL_INT64_VEC2_ARB 0x8FE9 +#define GL_INT64_VEC3_ARB 0x8FEA +#define GL_INT64_VEC4_ARB 0x8FEB +#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5 +#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6 +#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7 +typedef void (APIENTRYP PFNGLUNIFORM1I64ARBPROC) (GLint location, GLint64 x); +typedef void (APIENTRYP PFNGLUNIFORM2I64ARBPROC) (GLint location, GLint64 x, GLint64 y); +typedef void (APIENTRYP PFNGLUNIFORM3I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z); +typedef void (APIENTRYP PFNGLUNIFORM4I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); +typedef void (APIENTRYP PFNGLUNIFORM1I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); +typedef void (APIENTRYP PFNGLUNIFORM2I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); +typedef void (APIENTRYP PFNGLUNIFORM3I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); +typedef void (APIENTRYP PFNGLUNIFORM4I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value); +typedef void (APIENTRYP PFNGLUNIFORM1UI64ARBPROC) (GLint location, GLuint64 x); +typedef void (APIENTRYP PFNGLUNIFORM2UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y); +typedef void (APIENTRYP PFNGLUNIFORM3UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z); +typedef void (APIENTRYP PFNGLUNIFORM4UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); +typedef void (APIENTRYP PFNGLUNIFORM1UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLUNIFORM2UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLUNIFORM3UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLUNIFORM4UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLGETUNIFORMI64VARBPROC) (GLuint program, GLint location, GLint64 *params); +typedef void (APIENTRYP PFNGLGETUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLuint64 *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint64 *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64ARBPROC) (GLuint program, GLint location, GLint64 x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64ARBPROC) (GLuint program, GLint location, GLuint64 x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniform1i64ARB (GLint location, GLint64 x); +GLAPI void APIENTRY glUniform2i64ARB (GLint location, GLint64 x, GLint64 y); +GLAPI void APIENTRY glUniform3i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z); +GLAPI void APIENTRY glUniform4i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); +GLAPI void APIENTRY glUniform1i64vARB (GLint location, GLsizei count, const GLint64 *value); +GLAPI void APIENTRY glUniform2i64vARB (GLint location, GLsizei count, const GLint64 *value); +GLAPI void APIENTRY glUniform3i64vARB (GLint location, GLsizei count, const GLint64 *value); +GLAPI void APIENTRY glUniform4i64vARB (GLint location, GLsizei count, const GLint64 *value); +GLAPI void APIENTRY glUniform1ui64ARB (GLint location, GLuint64 x); +GLAPI void APIENTRY glUniform2ui64ARB (GLint location, GLuint64 x, GLuint64 y); +GLAPI void APIENTRY glUniform3ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z); +GLAPI void APIENTRY glUniform4ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); +GLAPI void APIENTRY glUniform1ui64vARB (GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glUniform2ui64vARB (GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glUniform3ui64vARB (GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glUniform4ui64vARB (GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glGetUniformi64vARB (GLuint program, GLint location, GLint64 *params); +GLAPI void APIENTRY glGetUniformui64vARB (GLuint program, GLint location, GLuint64 *params); +GLAPI void APIENTRY glGetnUniformi64vARB (GLuint program, GLint location, GLsizei bufSize, GLint64 *params); +GLAPI void APIENTRY glGetnUniformui64vARB (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params); +GLAPI void APIENTRY glProgramUniform1i64ARB (GLuint program, GLint location, GLint64 x); +GLAPI void APIENTRY glProgramUniform2i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y); +GLAPI void APIENTRY glProgramUniform3i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z); +GLAPI void APIENTRY glProgramUniform4i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w); +GLAPI void APIENTRY glProgramUniform1i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); +GLAPI void APIENTRY glProgramUniform2i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); +GLAPI void APIENTRY glProgramUniform3i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); +GLAPI void APIENTRY glProgramUniform4i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value); +GLAPI void APIENTRY glProgramUniform1ui64ARB (GLuint program, GLint location, GLuint64 x); +GLAPI void APIENTRY glProgramUniform2ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y); +GLAPI void APIENTRY glProgramUniform3ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z); +GLAPI void APIENTRY glProgramUniform4ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w); +GLAPI void APIENTRY glProgramUniform1ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glProgramUniform2ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glProgramUniform3ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glProgramUniform4ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value); +#endif +#endif /* GL_ARB_gpu_shader_int64 */ + +#ifndef GL_ARB_half_float_pixel +#define GL_ARB_half_float_pixel 1 +typedef unsigned short GLhalfARB; +#define GL_HALF_FLOAT_ARB 0x140B +#endif /* GL_ARB_half_float_pixel */ + +#ifndef GL_ARB_half_float_vertex +#define GL_ARB_half_float_vertex 1 +#endif /* GL_ARB_half_float_vertex */ + +#ifndef GL_ARB_imaging +#define GL_ARB_imaging 1 +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_EQUATION 0x8009 +#define GL_CONVOLUTION_1D 0x8010 +#define GL_CONVOLUTION_2D 0x8011 +#define GL_SEPARABLE_2D 0x8012 +#define GL_CONVOLUTION_BORDER_MODE 0x8013 +#define GL_CONVOLUTION_FILTER_SCALE 0x8014 +#define GL_CONVOLUTION_FILTER_BIAS 0x8015 +#define GL_REDUCE 0x8016 +#define GL_CONVOLUTION_FORMAT 0x8017 +#define GL_CONVOLUTION_WIDTH 0x8018 +#define GL_CONVOLUTION_HEIGHT 0x8019 +#define GL_MAX_CONVOLUTION_WIDTH 0x801A +#define GL_MAX_CONVOLUTION_HEIGHT 0x801B +#define GL_POST_CONVOLUTION_RED_SCALE 0x801C +#define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D +#define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E +#define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F +#define GL_POST_CONVOLUTION_RED_BIAS 0x8020 +#define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 +#define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 +#define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 +#define GL_HISTOGRAM 0x8024 +#define GL_PROXY_HISTOGRAM 0x8025 +#define GL_HISTOGRAM_WIDTH 0x8026 +#define GL_HISTOGRAM_FORMAT 0x8027 +#define GL_HISTOGRAM_RED_SIZE 0x8028 +#define GL_HISTOGRAM_GREEN_SIZE 0x8029 +#define GL_HISTOGRAM_BLUE_SIZE 0x802A +#define GL_HISTOGRAM_ALPHA_SIZE 0x802B +#define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C +#define GL_HISTOGRAM_SINK 0x802D +#define GL_MINMAX 0x802E +#define GL_MINMAX_FORMAT 0x802F +#define GL_MINMAX_SINK 0x8030 +#define GL_TABLE_TOO_LARGE 0x8031 +#define GL_COLOR_MATRIX 0x80B1 +#define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 +#define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 +#define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 +#define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 +#define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 +#define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 +#define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 +#define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 +#define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA +#define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB +#define GL_COLOR_TABLE 0x80D0 +#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 +#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 +#define GL_PROXY_COLOR_TABLE 0x80D3 +#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 +#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 +#define GL_COLOR_TABLE_SCALE 0x80D6 +#define GL_COLOR_TABLE_BIAS 0x80D7 +#define GL_COLOR_TABLE_FORMAT 0x80D8 +#define GL_COLOR_TABLE_WIDTH 0x80D9 +#define GL_COLOR_TABLE_RED_SIZE 0x80DA +#define GL_COLOR_TABLE_GREEN_SIZE 0x80DB +#define GL_COLOR_TABLE_BLUE_SIZE 0x80DC +#define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD +#define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE +#define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF +#define GL_CONSTANT_BORDER 0x8151 +#define GL_REPLICATE_BORDER 0x8153 +#define GL_CONVOLUTION_BORDER_COLOR 0x8154 +typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); +typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); +GLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, void *table); +GLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); +GLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params); +GLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params); +GLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, void *image); +GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); +GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +GLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glMinmax (GLenum target, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glResetHistogram (GLenum target); +GLAPI void APIENTRY glResetMinmax (GLenum target); +#endif +#endif /* GL_ARB_imaging */ + +#ifndef GL_ARB_indirect_parameters +#define GL_ARB_indirect_parameters 1 +#define GL_PARAMETER_BUFFER_ARB 0x80EE +#define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectCountARB (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +#endif +#endif /* GL_ARB_indirect_parameters */ + +#ifndef GL_ARB_instanced_arrays +#define GL_ARB_instanced_arrays 1 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE +typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); +#endif +#endif /* GL_ARB_instanced_arrays */ + +#ifndef GL_ARB_internalformat_query +#define GL_ARB_internalformat_query 1 +#endif /* GL_ARB_internalformat_query */ + +#ifndef GL_ARB_internalformat_query2 +#define GL_ARB_internalformat_query2 1 +#define GL_SRGB_DECODE_ARB 0x8299 +#endif /* GL_ARB_internalformat_query2 */ + +#ifndef GL_ARB_invalidate_subdata +#define GL_ARB_invalidate_subdata 1 +#endif /* GL_ARB_invalidate_subdata */ + +#ifndef GL_ARB_map_buffer_alignment +#define GL_ARB_map_buffer_alignment 1 +#endif /* GL_ARB_map_buffer_alignment */ + +#ifndef GL_ARB_map_buffer_range +#define GL_ARB_map_buffer_range 1 +#endif /* GL_ARB_map_buffer_range */ + +#ifndef GL_ARB_matrix_palette +#define GL_ARB_matrix_palette 1 +#define GL_MATRIX_PALETTE_ARB 0x8840 +#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 +#define GL_MAX_PALETTE_MATRICES_ARB 0x8842 +#define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 +#define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 +#define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 +#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 +#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 +#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 +#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 +typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); +typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index); +GLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices); +GLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices); +GLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices); +GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer); +#endif +#endif /* GL_ARB_matrix_palette */ + +#ifndef GL_ARB_multi_bind +#define GL_ARB_multi_bind 1 +#endif /* GL_ARB_multi_bind */ + +#ifndef GL_ARB_multi_draw_indirect +#define GL_ARB_multi_draw_indirect 1 +#endif /* GL_ARB_multi_draw_indirect */ + +#ifndef GL_ARB_multisample +#define GL_ARB_multisample 1 +#define GL_MULTISAMPLE_ARB 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F +#define GL_SAMPLE_COVERAGE_ARB 0x80A0 +#define GL_SAMPLE_BUFFERS_ARB 0x80A8 +#define GL_SAMPLES_ARB 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB +#define GL_MULTISAMPLE_BIT_ARB 0x20000000 +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleCoverageARB (GLfloat value, GLboolean invert); +#endif +#endif /* GL_ARB_multisample */ + +#ifndef GL_ARB_multitexture +#define GL_ARB_multitexture 1 +#define GL_TEXTURE0_ARB 0x84C0 +#define GL_TEXTURE1_ARB 0x84C1 +#define GL_TEXTURE2_ARB 0x84C2 +#define GL_TEXTURE3_ARB 0x84C3 +#define GL_TEXTURE4_ARB 0x84C4 +#define GL_TEXTURE5_ARB 0x84C5 +#define GL_TEXTURE6_ARB 0x84C6 +#define GL_TEXTURE7_ARB 0x84C7 +#define GL_TEXTURE8_ARB 0x84C8 +#define GL_TEXTURE9_ARB 0x84C9 +#define GL_TEXTURE10_ARB 0x84CA +#define GL_TEXTURE11_ARB 0x84CB +#define GL_TEXTURE12_ARB 0x84CC +#define GL_TEXTURE13_ARB 0x84CD +#define GL_TEXTURE14_ARB 0x84CE +#define GL_TEXTURE15_ARB 0x84CF +#define GL_TEXTURE16_ARB 0x84D0 +#define GL_TEXTURE17_ARB 0x84D1 +#define GL_TEXTURE18_ARB 0x84D2 +#define GL_TEXTURE19_ARB 0x84D3 +#define GL_TEXTURE20_ARB 0x84D4 +#define GL_TEXTURE21_ARB 0x84D5 +#define GL_TEXTURE22_ARB 0x84D6 +#define GL_TEXTURE23_ARB 0x84D7 +#define GL_TEXTURE24_ARB 0x84D8 +#define GL_TEXTURE25_ARB 0x84D9 +#define GL_TEXTURE26_ARB 0x84DA +#define GL_TEXTURE27_ARB 0x84DB +#define GL_TEXTURE28_ARB 0x84DC +#define GL_TEXTURE29_ARB 0x84DD +#define GL_TEXTURE30_ARB 0x84DE +#define GL_TEXTURE31_ARB 0x84DF +#define GL_ACTIVE_TEXTURE_ARB 0x84E0 +#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 +#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 +typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveTextureARB (GLenum texture); +GLAPI void APIENTRY glClientActiveTextureARB (GLenum texture); +GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum target, GLdouble s); +GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum target, GLfloat s); +GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum target, GLint s); +GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum target, GLshort s); +GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t); +GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t); +GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum target, GLint s, GLint t); +GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t); +GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r); +GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r); +GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r); +GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r); +GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q); +GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum target, const GLshort *v); +#endif +#endif /* GL_ARB_multitexture */ + +#ifndef GL_ARB_occlusion_query +#define GL_ARB_occlusion_query 1 +#define GL_QUERY_COUNTER_BITS_ARB 0x8864 +#define GL_CURRENT_QUERY_ARB 0x8865 +#define GL_QUERY_RESULT_ARB 0x8866 +#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 +#define GL_SAMPLES_PASSED_ARB 0x8914 +typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenQueriesARB (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glDeleteQueriesARB (GLsizei n, const GLuint *ids); +GLAPI GLboolean APIENTRY glIsQueryARB (GLuint id); +GLAPI void APIENTRY glBeginQueryARB (GLenum target, GLuint id); +GLAPI void APIENTRY glEndQueryARB (GLenum target); +GLAPI void APIENTRY glGetQueryivARB (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params); +#endif +#endif /* GL_ARB_occlusion_query */ + +#ifndef GL_ARB_occlusion_query2 +#define GL_ARB_occlusion_query2 1 +#endif /* GL_ARB_occlusion_query2 */ + +#ifndef GL_ARB_parallel_shader_compile +#define GL_ARB_parallel_shader_compile 1 +#define GL_MAX_SHADER_COMPILER_THREADS_ARB 0x91B0 +#define GL_COMPLETION_STATUS_ARB 0x91B1 +typedef void (APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSARBPROC) (GLuint count); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMaxShaderCompilerThreadsARB (GLuint count); +#endif +#endif /* GL_ARB_parallel_shader_compile */ + +#ifndef GL_ARB_pipeline_statistics_query +#define GL_ARB_pipeline_statistics_query 1 +#define GL_VERTICES_SUBMITTED_ARB 0x82EE +#define GL_PRIMITIVES_SUBMITTED_ARB 0x82EF +#define GL_VERTEX_SHADER_INVOCATIONS_ARB 0x82F0 +#define GL_TESS_CONTROL_SHADER_PATCHES_ARB 0x82F1 +#define GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB 0x82F2 +#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB 0x82F3 +#define GL_FRAGMENT_SHADER_INVOCATIONS_ARB 0x82F4 +#define GL_COMPUTE_SHADER_INVOCATIONS_ARB 0x82F5 +#define GL_CLIPPING_INPUT_PRIMITIVES_ARB 0x82F6 +#define GL_CLIPPING_OUTPUT_PRIMITIVES_ARB 0x82F7 +#endif /* GL_ARB_pipeline_statistics_query */ + +#ifndef GL_ARB_pixel_buffer_object +#define GL_ARB_pixel_buffer_object 1 +#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB +#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF +#endif /* GL_ARB_pixel_buffer_object */ + +#ifndef GL_ARB_point_parameters +#define GL_ARB_point_parameters 1 +#define GL_POINT_SIZE_MIN_ARB 0x8126 +#define GL_POINT_SIZE_MAX_ARB 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 +#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 +typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfARB (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params); +#endif +#endif /* GL_ARB_point_parameters */ + +#ifndef GL_ARB_point_sprite +#define GL_ARB_point_sprite 1 +#define GL_POINT_SPRITE_ARB 0x8861 +#define GL_COORD_REPLACE_ARB 0x8862 +#endif /* GL_ARB_point_sprite */ + +#ifndef GL_ARB_post_depth_coverage +#define GL_ARB_post_depth_coverage 1 +#endif /* GL_ARB_post_depth_coverage */ + +#ifndef GL_ARB_program_interface_query +#define GL_ARB_program_interface_query 1 +#endif /* GL_ARB_program_interface_query */ + +#ifndef GL_ARB_provoking_vertex +#define GL_ARB_provoking_vertex 1 +#endif /* GL_ARB_provoking_vertex */ + +#ifndef GL_ARB_query_buffer_object +#define GL_ARB_query_buffer_object 1 +#endif /* GL_ARB_query_buffer_object */ + +#ifndef GL_ARB_robust_buffer_access_behavior +#define GL_ARB_robust_buffer_access_behavior 1 +#endif /* GL_ARB_robust_buffer_access_behavior */ + +#ifndef GL_ARB_robustness +#define GL_ARB_robustness 1 +#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 +#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 +typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); +typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); +typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img); +typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); +typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); +typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); +typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values); +typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values); +typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values); +typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern); +typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); +typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); +typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); +typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); +GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); +GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, void *img); +GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); +GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +GLAPI void APIENTRY glGetnMapdvARB (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); +GLAPI void APIENTRY glGetnMapfvARB (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); +GLAPI void APIENTRY glGetnMapivARB (GLenum target, GLenum query, GLsizei bufSize, GLint *v); +GLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *values); +GLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values); +GLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values); +GLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern); +GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); +GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); +GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); +GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +#endif +#endif /* GL_ARB_robustness */ + +#ifndef GL_ARB_robustness_isolation +#define GL_ARB_robustness_isolation 1 +#endif /* GL_ARB_robustness_isolation */ + +#ifndef GL_ARB_sample_locations +#define GL_ARB_sample_locations 1 +#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB 0x933D +#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E +#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F +#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340 +#define GL_SAMPLE_LOCATION_ARB 0x8E50 +#define GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341 +#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342 +#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343 +typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLEVALUATEDEPTHVALUESARBPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFramebufferSampleLocationsfvARB (GLenum target, GLuint start, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glNamedFramebufferSampleLocationsfvARB (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glEvaluateDepthValuesARB (void); +#endif +#endif /* GL_ARB_sample_locations */ + +#ifndef GL_ARB_sample_shading +#define GL_ARB_sample_shading 1 +#define GL_SAMPLE_SHADING_ARB 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 +typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLfloat value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value); +#endif +#endif /* GL_ARB_sample_shading */ + +#ifndef GL_ARB_sampler_objects +#define GL_ARB_sampler_objects 1 +#endif /* GL_ARB_sampler_objects */ + +#ifndef GL_ARB_seamless_cube_map +#define GL_ARB_seamless_cube_map 1 +#endif /* GL_ARB_seamless_cube_map */ + +#ifndef GL_ARB_seamless_cubemap_per_texture +#define GL_ARB_seamless_cubemap_per_texture 1 +#endif /* GL_ARB_seamless_cubemap_per_texture */ + +#ifndef GL_ARB_separate_shader_objects +#define GL_ARB_separate_shader_objects 1 +#endif /* GL_ARB_separate_shader_objects */ + +#ifndef GL_ARB_shader_atomic_counter_ops +#define GL_ARB_shader_atomic_counter_ops 1 +#endif /* GL_ARB_shader_atomic_counter_ops */ + +#ifndef GL_ARB_shader_atomic_counters +#define GL_ARB_shader_atomic_counters 1 +#endif /* GL_ARB_shader_atomic_counters */ + +#ifndef GL_ARB_shader_ballot +#define GL_ARB_shader_ballot 1 +#endif /* GL_ARB_shader_ballot */ + +#ifndef GL_ARB_shader_bit_encoding +#define GL_ARB_shader_bit_encoding 1 +#endif /* GL_ARB_shader_bit_encoding */ + +#ifndef GL_ARB_shader_clock +#define GL_ARB_shader_clock 1 +#endif /* GL_ARB_shader_clock */ + +#ifndef GL_ARB_shader_draw_parameters +#define GL_ARB_shader_draw_parameters 1 +#endif /* GL_ARB_shader_draw_parameters */ + +#ifndef GL_ARB_shader_group_vote +#define GL_ARB_shader_group_vote 1 +#endif /* GL_ARB_shader_group_vote */ + +#ifndef GL_ARB_shader_image_load_store +#define GL_ARB_shader_image_load_store 1 +#endif /* GL_ARB_shader_image_load_store */ + +#ifndef GL_ARB_shader_image_size +#define GL_ARB_shader_image_size 1 +#endif /* GL_ARB_shader_image_size */ + +#ifndef GL_ARB_shader_objects +#define GL_ARB_shader_objects 1 +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef char GLcharARB; +#define GL_PROGRAM_OBJECT_ARB 0x8B40 +#define GL_SHADER_OBJECT_ARB 0x8B48 +#define GL_OBJECT_TYPE_ARB 0x8B4E +#define GL_OBJECT_SUBTYPE_ARB 0x8B4F +#define GL_FLOAT_VEC2_ARB 0x8B50 +#define GL_FLOAT_VEC3_ARB 0x8B51 +#define GL_FLOAT_VEC4_ARB 0x8B52 +#define GL_INT_VEC2_ARB 0x8B53 +#define GL_INT_VEC3_ARB 0x8B54 +#define GL_INT_VEC4_ARB 0x8B55 +#define GL_BOOL_ARB 0x8B56 +#define GL_BOOL_VEC2_ARB 0x8B57 +#define GL_BOOL_VEC3_ARB 0x8B58 +#define GL_BOOL_VEC4_ARB 0x8B59 +#define GL_FLOAT_MAT2_ARB 0x8B5A +#define GL_FLOAT_MAT3_ARB 0x8B5B +#define GL_FLOAT_MAT4_ARB 0x8B5C +#define GL_SAMPLER_1D_ARB 0x8B5D +#define GL_SAMPLER_2D_ARB 0x8B5E +#define GL_SAMPLER_3D_ARB 0x8B5F +#define GL_SAMPLER_CUBE_ARB 0x8B60 +#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 +#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 +#define GL_SAMPLER_2D_RECT_ARB 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 +#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 +#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 +#define GL_OBJECT_LINK_STATUS_ARB 0x8B82 +#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 +#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 +#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 +#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 +#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 +#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 +typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); +typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); +typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); +typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); +typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length); +typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); +typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); +typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); +typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); +typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); +typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); +typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); +typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj); +GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname); +GLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj); +GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum shaderType); +GLAPI void APIENTRY glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length); +GLAPI void APIENTRY glCompileShaderARB (GLhandleARB shaderObj); +GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); +GLAPI void APIENTRY glAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj); +GLAPI void APIENTRY glLinkProgramARB (GLhandleARB programObj); +GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB programObj); +GLAPI void APIENTRY glValidateProgramARB (GLhandleARB programObj); +GLAPI void APIENTRY glUniform1fARB (GLint location, GLfloat v0); +GLAPI void APIENTRY glUniform2fARB (GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glUniform1iARB (GLint location, GLint v0); +GLAPI void APIENTRY glUniform2iARB (GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glUniform1fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform2fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform3fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform4fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform1ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform2ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform3ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform4ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); +GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); +GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name); +GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params); +GLAPI void APIENTRY glGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params); +GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); +#endif +#endif /* GL_ARB_shader_objects */ + +#ifndef GL_ARB_shader_precision +#define GL_ARB_shader_precision 1 +#endif /* GL_ARB_shader_precision */ + +#ifndef GL_ARB_shader_stencil_export +#define GL_ARB_shader_stencil_export 1 +#endif /* GL_ARB_shader_stencil_export */ + +#ifndef GL_ARB_shader_storage_buffer_object +#define GL_ARB_shader_storage_buffer_object 1 +#endif /* GL_ARB_shader_storage_buffer_object */ + +#ifndef GL_ARB_shader_subroutine +#define GL_ARB_shader_subroutine 1 +#endif /* GL_ARB_shader_subroutine */ + +#ifndef GL_ARB_shader_texture_image_samples +#define GL_ARB_shader_texture_image_samples 1 +#endif /* GL_ARB_shader_texture_image_samples */ + +#ifndef GL_ARB_shader_texture_lod +#define GL_ARB_shader_texture_lod 1 +#endif /* GL_ARB_shader_texture_lod */ + +#ifndef GL_ARB_shader_viewport_layer_array +#define GL_ARB_shader_viewport_layer_array 1 +#endif /* GL_ARB_shader_viewport_layer_array */ + +#ifndef GL_ARB_shading_language_100 +#define GL_ARB_shading_language_100 1 +#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C +#endif /* GL_ARB_shading_language_100 */ + +#ifndef GL_ARB_shading_language_420pack +#define GL_ARB_shading_language_420pack 1 +#endif /* GL_ARB_shading_language_420pack */ + +#ifndef GL_ARB_shading_language_include +#define GL_ARB_shading_language_include 1 +#define GL_SHADER_INCLUDE_ARB 0x8DAE +#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 +#define GL_NAMED_STRING_TYPE_ARB 0x8DEA +typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); +typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); +typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); +typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); +typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); +typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); +GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name); +GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); +GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name); +GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); +GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +#endif +#endif /* GL_ARB_shading_language_include */ + +#ifndef GL_ARB_shading_language_packing +#define GL_ARB_shading_language_packing 1 +#endif /* GL_ARB_shading_language_packing */ + +#ifndef GL_ARB_shadow +#define GL_ARB_shadow 1 +#define GL_TEXTURE_COMPARE_MODE_ARB 0x884C +#define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D +#define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E +#endif /* GL_ARB_shadow */ + +#ifndef GL_ARB_shadow_ambient +#define GL_ARB_shadow_ambient 1 +#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF +#endif /* GL_ARB_shadow_ambient */ + +#ifndef GL_ARB_sparse_buffer +#define GL_ARB_sparse_buffer 1 +#define GL_SPARSE_STORAGE_BIT_ARB 0x0400 +#define GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8 +typedef void (APIENTRYP PFNGLBUFFERPAGECOMMITMENTARBPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit); +typedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); +typedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTARBPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferPageCommitmentARB (GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit); +GLAPI void APIENTRY glNamedBufferPageCommitmentEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); +GLAPI void APIENTRY glNamedBufferPageCommitmentARB (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit); +#endif +#endif /* GL_ARB_sparse_buffer */ + +#ifndef GL_ARB_sparse_texture +#define GL_ARB_sparse_texture 1 +#define GL_TEXTURE_SPARSE_ARB 0x91A6 +#define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB 0x91A7 +#define GL_NUM_SPARSE_LEVELS_ARB 0x91AA +#define GL_NUM_VIRTUAL_PAGE_SIZES_ARB 0x91A8 +#define GL_VIRTUAL_PAGE_SIZE_X_ARB 0x9195 +#define GL_VIRTUAL_PAGE_SIZE_Y_ARB 0x9196 +#define GL_VIRTUAL_PAGE_SIZE_Z_ARB 0x9197 +#define GL_MAX_SPARSE_TEXTURE_SIZE_ARB 0x9198 +#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB 0x9199 +#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB 0x919A +#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9 +typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); +#endif +#endif /* GL_ARB_sparse_texture */ + +#ifndef GL_ARB_sparse_texture2 +#define GL_ARB_sparse_texture2 1 +#endif /* GL_ARB_sparse_texture2 */ + +#ifndef GL_ARB_sparse_texture_clamp +#define GL_ARB_sparse_texture_clamp 1 +#endif /* GL_ARB_sparse_texture_clamp */ + +#ifndef GL_ARB_stencil_texturing +#define GL_ARB_stencil_texturing 1 +#endif /* GL_ARB_stencil_texturing */ + +#ifndef GL_ARB_sync +#define GL_ARB_sync 1 +#endif /* GL_ARB_sync */ + +#ifndef GL_ARB_tessellation_shader +#define GL_ARB_tessellation_shader 1 +#endif /* GL_ARB_tessellation_shader */ + +#ifndef GL_ARB_texture_barrier +#define GL_ARB_texture_barrier 1 +#endif /* GL_ARB_texture_barrier */ + +#ifndef GL_ARB_texture_border_clamp +#define GL_ARB_texture_border_clamp 1 +#define GL_CLAMP_TO_BORDER_ARB 0x812D +#endif /* GL_ARB_texture_border_clamp */ + +#ifndef GL_ARB_texture_buffer_object +#define GL_ARB_texture_buffer_object 1 +#define GL_TEXTURE_BUFFER_ARB 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D +#define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E +typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer); +#endif +#endif /* GL_ARB_texture_buffer_object */ + +#ifndef GL_ARB_texture_buffer_object_rgb32 +#define GL_ARB_texture_buffer_object_rgb32 1 +#endif /* GL_ARB_texture_buffer_object_rgb32 */ + +#ifndef GL_ARB_texture_buffer_range +#define GL_ARB_texture_buffer_range 1 +#endif /* GL_ARB_texture_buffer_range */ + +#ifndef GL_ARB_texture_compression +#define GL_ARB_texture_compression 1 +#define GL_COMPRESSED_ALPHA_ARB 0x84E9 +#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB +#define GL_COMPRESSED_INTENSITY_ARB 0x84EC +#define GL_COMPRESSED_RGB_ARB 0x84ED +#define GL_COMPRESSED_RGBA_ARB 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 +#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, void *img); +#endif +#endif /* GL_ARB_texture_compression */ + +#ifndef GL_ARB_texture_compression_bptc +#define GL_ARB_texture_compression_bptc 1 +#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F +#endif /* GL_ARB_texture_compression_bptc */ + +#ifndef GL_ARB_texture_compression_rgtc +#define GL_ARB_texture_compression_rgtc 1 +#endif /* GL_ARB_texture_compression_rgtc */ + +#ifndef GL_ARB_texture_cube_map +#define GL_ARB_texture_cube_map 1 +#define GL_NORMAL_MAP_ARB 0x8511 +#define GL_REFLECTION_MAP_ARB 0x8512 +#define GL_TEXTURE_CUBE_MAP_ARB 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C +#endif /* GL_ARB_texture_cube_map */ + +#ifndef GL_ARB_texture_cube_map_array +#define GL_ARB_texture_cube_map_array 1 +#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F +#endif /* GL_ARB_texture_cube_map_array */ + +#ifndef GL_ARB_texture_env_add +#define GL_ARB_texture_env_add 1 +#endif /* GL_ARB_texture_env_add */ + +#ifndef GL_ARB_texture_env_combine +#define GL_ARB_texture_env_combine 1 +#define GL_COMBINE_ARB 0x8570 +#define GL_COMBINE_RGB_ARB 0x8571 +#define GL_COMBINE_ALPHA_ARB 0x8572 +#define GL_SOURCE0_RGB_ARB 0x8580 +#define GL_SOURCE1_RGB_ARB 0x8581 +#define GL_SOURCE2_RGB_ARB 0x8582 +#define GL_SOURCE0_ALPHA_ARB 0x8588 +#define GL_SOURCE1_ALPHA_ARB 0x8589 +#define GL_SOURCE2_ALPHA_ARB 0x858A +#define GL_OPERAND0_RGB_ARB 0x8590 +#define GL_OPERAND1_RGB_ARB 0x8591 +#define GL_OPERAND2_RGB_ARB 0x8592 +#define GL_OPERAND0_ALPHA_ARB 0x8598 +#define GL_OPERAND1_ALPHA_ARB 0x8599 +#define GL_OPERAND2_ALPHA_ARB 0x859A +#define GL_RGB_SCALE_ARB 0x8573 +#define GL_ADD_SIGNED_ARB 0x8574 +#define GL_INTERPOLATE_ARB 0x8575 +#define GL_SUBTRACT_ARB 0x84E7 +#define GL_CONSTANT_ARB 0x8576 +#define GL_PRIMARY_COLOR_ARB 0x8577 +#define GL_PREVIOUS_ARB 0x8578 +#endif /* GL_ARB_texture_env_combine */ + +#ifndef GL_ARB_texture_env_crossbar +#define GL_ARB_texture_env_crossbar 1 +#endif /* GL_ARB_texture_env_crossbar */ + +#ifndef GL_ARB_texture_env_dot3 +#define GL_ARB_texture_env_dot3 1 +#define GL_DOT3_RGB_ARB 0x86AE +#define GL_DOT3_RGBA_ARB 0x86AF +#endif /* GL_ARB_texture_env_dot3 */ + +#ifndef GL_ARB_texture_filter_minmax +#define GL_ARB_texture_filter_minmax 1 +#define GL_TEXTURE_REDUCTION_MODE_ARB 0x9366 +#define GL_WEIGHTED_AVERAGE_ARB 0x9367 +#endif /* GL_ARB_texture_filter_minmax */ + +#ifndef GL_ARB_texture_float +#define GL_ARB_texture_float 1 +#define GL_TEXTURE_RED_TYPE_ARB 0x8C10 +#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 +#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 +#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 +#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 +#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 +#define GL_RGBA32F_ARB 0x8814 +#define GL_RGB32F_ARB 0x8815 +#define GL_ALPHA32F_ARB 0x8816 +#define GL_INTENSITY32F_ARB 0x8817 +#define GL_LUMINANCE32F_ARB 0x8818 +#define GL_LUMINANCE_ALPHA32F_ARB 0x8819 +#define GL_RGBA16F_ARB 0x881A +#define GL_RGB16F_ARB 0x881B +#define GL_ALPHA16F_ARB 0x881C +#define GL_INTENSITY16F_ARB 0x881D +#define GL_LUMINANCE16F_ARB 0x881E +#define GL_LUMINANCE_ALPHA16F_ARB 0x881F +#endif /* GL_ARB_texture_float */ + +#ifndef GL_ARB_texture_gather +#define GL_ARB_texture_gather 1 +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F +#define GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB 0x8F9F +#endif /* GL_ARB_texture_gather */ + +#ifndef GL_ARB_texture_mirror_clamp_to_edge +#define GL_ARB_texture_mirror_clamp_to_edge 1 +#endif /* GL_ARB_texture_mirror_clamp_to_edge */ + +#ifndef GL_ARB_texture_mirrored_repeat +#define GL_ARB_texture_mirrored_repeat 1 +#define GL_MIRRORED_REPEAT_ARB 0x8370 +#endif /* GL_ARB_texture_mirrored_repeat */ + +#ifndef GL_ARB_texture_multisample +#define GL_ARB_texture_multisample 1 +#endif /* GL_ARB_texture_multisample */ + +#ifndef GL_ARB_texture_non_power_of_two +#define GL_ARB_texture_non_power_of_two 1 +#endif /* GL_ARB_texture_non_power_of_two */ + +#ifndef GL_ARB_texture_query_levels +#define GL_ARB_texture_query_levels 1 +#endif /* GL_ARB_texture_query_levels */ + +#ifndef GL_ARB_texture_query_lod +#define GL_ARB_texture_query_lod 1 +#endif /* GL_ARB_texture_query_lod */ + +#ifndef GL_ARB_texture_rectangle +#define GL_ARB_texture_rectangle 1 +#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 +#endif /* GL_ARB_texture_rectangle */ + +#ifndef GL_ARB_texture_rg +#define GL_ARB_texture_rg 1 +#endif /* GL_ARB_texture_rg */ + +#ifndef GL_ARB_texture_rgb10_a2ui +#define GL_ARB_texture_rgb10_a2ui 1 +#endif /* GL_ARB_texture_rgb10_a2ui */ + +#ifndef GL_ARB_texture_stencil8 +#define GL_ARB_texture_stencil8 1 +#endif /* GL_ARB_texture_stencil8 */ + +#ifndef GL_ARB_texture_storage +#define GL_ARB_texture_storage 1 +#endif /* GL_ARB_texture_storage */ + +#ifndef GL_ARB_texture_storage_multisample +#define GL_ARB_texture_storage_multisample 1 +#endif /* GL_ARB_texture_storage_multisample */ + +#ifndef GL_ARB_texture_swizzle +#define GL_ARB_texture_swizzle 1 +#endif /* GL_ARB_texture_swizzle */ + +#ifndef GL_ARB_texture_view +#define GL_ARB_texture_view 1 +#endif /* GL_ARB_texture_view */ + +#ifndef GL_ARB_timer_query +#define GL_ARB_timer_query 1 +#endif /* GL_ARB_timer_query */ + +#ifndef GL_ARB_transform_feedback2 +#define GL_ARB_transform_feedback2 1 +#endif /* GL_ARB_transform_feedback2 */ + +#ifndef GL_ARB_transform_feedback3 +#define GL_ARB_transform_feedback3 1 +#endif /* GL_ARB_transform_feedback3 */ + +#ifndef GL_ARB_transform_feedback_instanced +#define GL_ARB_transform_feedback_instanced 1 +#endif /* GL_ARB_transform_feedback_instanced */ + +#ifndef GL_ARB_transform_feedback_overflow_query +#define GL_ARB_transform_feedback_overflow_query 1 +#define GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB 0x82EC +#define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB 0x82ED +#endif /* GL_ARB_transform_feedback_overflow_query */ + +#ifndef GL_ARB_transpose_matrix +#define GL_ARB_transpose_matrix 1 +#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *m); +GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *m); +GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *m); +GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m); +#endif +#endif /* GL_ARB_transpose_matrix */ + +#ifndef GL_ARB_uniform_buffer_object +#define GL_ARB_uniform_buffer_object 1 +#endif /* GL_ARB_uniform_buffer_object */ + +#ifndef GL_ARB_vertex_array_bgra +#define GL_ARB_vertex_array_bgra 1 +#endif /* GL_ARB_vertex_array_bgra */ + +#ifndef GL_ARB_vertex_array_object +#define GL_ARB_vertex_array_object 1 +#endif /* GL_ARB_vertex_array_object */ + +#ifndef GL_ARB_vertex_attrib_64bit +#define GL_ARB_vertex_attrib_64bit 1 +#endif /* GL_ARB_vertex_attrib_64bit */ + +#ifndef GL_ARB_vertex_attrib_binding +#define GL_ARB_vertex_attrib_binding 1 +#endif /* GL_ARB_vertex_attrib_binding */ + +#ifndef GL_ARB_vertex_blend +#define GL_ARB_vertex_blend 1 +#define GL_MAX_VERTEX_UNITS_ARB 0x86A4 +#define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 +#define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 +#define GL_VERTEX_BLEND_ARB 0x86A7 +#define GL_CURRENT_WEIGHT_ARB 0x86A8 +#define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 +#define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA +#define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB +#define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC +#define GL_WEIGHT_ARRAY_ARB 0x86AD +#define GL_MODELVIEW0_ARB 0x1700 +#define GL_MODELVIEW1_ARB 0x850A +#define GL_MODELVIEW2_ARB 0x8722 +#define GL_MODELVIEW3_ARB 0x8723 +#define GL_MODELVIEW4_ARB 0x8724 +#define GL_MODELVIEW5_ARB 0x8725 +#define GL_MODELVIEW6_ARB 0x8726 +#define GL_MODELVIEW7_ARB 0x8727 +#define GL_MODELVIEW8_ARB 0x8728 +#define GL_MODELVIEW9_ARB 0x8729 +#define GL_MODELVIEW10_ARB 0x872A +#define GL_MODELVIEW11_ARB 0x872B +#define GL_MODELVIEW12_ARB 0x872C +#define GL_MODELVIEW13_ARB 0x872D +#define GL_MODELVIEW14_ARB 0x872E +#define GL_MODELVIEW15_ARB 0x872F +#define GL_MODELVIEW16_ARB 0x8730 +#define GL_MODELVIEW17_ARB 0x8731 +#define GL_MODELVIEW18_ARB 0x8732 +#define GL_MODELVIEW19_ARB 0x8733 +#define GL_MODELVIEW20_ARB 0x8734 +#define GL_MODELVIEW21_ARB 0x8735 +#define GL_MODELVIEW22_ARB 0x8736 +#define GL_MODELVIEW23_ARB 0x8737 +#define GL_MODELVIEW24_ARB 0x8738 +#define GL_MODELVIEW25_ARB 0x8739 +#define GL_MODELVIEW26_ARB 0x873A +#define GL_MODELVIEW27_ARB 0x873B +#define GL_MODELVIEW28_ARB 0x873C +#define GL_MODELVIEW29_ARB 0x873D +#define GL_MODELVIEW30_ARB 0x873E +#define GL_MODELVIEW31_ARB 0x873F +typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights); +typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights); +typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights); +typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); +typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); +typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); +typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); +typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); +typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights); +GLAPI void APIENTRY glWeightsvARB (GLint size, const GLshort *weights); +GLAPI void APIENTRY glWeightivARB (GLint size, const GLint *weights); +GLAPI void APIENTRY glWeightfvARB (GLint size, const GLfloat *weights); +GLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights); +GLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights); +GLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights); +GLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights); +GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glVertexBlendARB (GLint count); +#endif +#endif /* GL_ARB_vertex_blend */ + +#ifndef GL_ARB_vertex_buffer_object +#define GL_ARB_vertex_buffer_object 1 +typedef ptrdiff_t GLsizeiptrARB; +typedef ptrdiff_t GLintptrARB; +#define GL_BUFFER_SIZE_ARB 0x8764 +#define GL_BUFFER_USAGE_ARB 0x8765 +#define GL_ARRAY_BUFFER_ARB 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 +#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 +#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F +#define GL_READ_ONLY_ARB 0x88B8 +#define GL_WRITE_ONLY_ARB 0x88B9 +#define GL_READ_WRITE_ARB 0x88BA +#define GL_BUFFER_ACCESS_ARB 0x88BB +#define GL_BUFFER_MAPPED_ARB 0x88BC +#define GL_BUFFER_MAP_POINTER_ARB 0x88BD +#define GL_STREAM_DRAW_ARB 0x88E0 +#define GL_STREAM_READ_ARB 0x88E1 +#define GL_STREAM_COPY_ARB 0x88E2 +#define GL_STATIC_DRAW_ARB 0x88E4 +#define GL_STATIC_READ_ARB 0x88E5 +#define GL_STATIC_COPY_ARB 0x88E6 +#define GL_DYNAMIC_DRAW_ARB 0x88E8 +#define GL_DYNAMIC_READ_ARB 0x88E9 +#define GL_DYNAMIC_COPY_ARB 0x88EA +typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); +typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); +typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); +typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data); +typedef void *(APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer); +GLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers); +GLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers); +GLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer); +GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage); +GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data); +GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data); +GLAPI void *APIENTRY glMapBufferARB (GLenum target, GLenum access); +GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target); +GLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, void **params); +#endif +#endif /* GL_ARB_vertex_buffer_object */ + +#ifndef GL_ARB_vertex_program +#define GL_ARB_vertex_program 1 +#define GL_COLOR_SUM_ARB 0x8458 +#define GL_VERTEX_PROGRAM_ARB 0x8620 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 +#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A +#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 +#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 +#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 +#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib1fARB (GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib1sARB (GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib2sARB (GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index); +GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index); +GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, void **pointer); +#endif +#endif /* GL_ARB_vertex_program */ + +#ifndef GL_ARB_vertex_shader +#define GL_ARB_vertex_shader 1 +#define GL_VERTEX_SHADER_ARB 0x8B31 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A +#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D +#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 +#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name); +GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name); +#endif +#endif /* GL_ARB_vertex_shader */ + +#ifndef GL_ARB_vertex_type_10f_11f_11f_rev +#define GL_ARB_vertex_type_10f_11f_11f_rev 1 +#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */ + +#ifndef GL_ARB_vertex_type_2_10_10_10_rev +#define GL_ARB_vertex_type_2_10_10_10_rev 1 +#endif /* GL_ARB_vertex_type_2_10_10_10_rev */ + +#ifndef GL_ARB_viewport_array +#define GL_ARB_viewport_array 1 +#endif /* GL_ARB_viewport_array */ + +#ifndef GL_ARB_window_pos +#define GL_ARB_window_pos 1 +typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWindowPos2dARB (GLdouble x, GLdouble y); +GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *v); +GLAPI void APIENTRY glWindowPos2fARB (GLfloat x, GLfloat y); +GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *v); +GLAPI void APIENTRY glWindowPos2iARB (GLint x, GLint y); +GLAPI void APIENTRY glWindowPos2ivARB (const GLint *v); +GLAPI void APIENTRY glWindowPos2sARB (GLshort x, GLshort y); +GLAPI void APIENTRY glWindowPos2svARB (const GLshort *v); +GLAPI void APIENTRY glWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *v); +GLAPI void APIENTRY glWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *v); +GLAPI void APIENTRY glWindowPos3iARB (GLint x, GLint y, GLint z); +GLAPI void APIENTRY glWindowPos3ivARB (const GLint *v); +GLAPI void APIENTRY glWindowPos3sARB (GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v); +#endif +#endif /* GL_ARB_window_pos */ + +#ifndef GL_KHR_blend_equation_advanced +#define GL_KHR_blend_equation_advanced 1 +#define GL_MULTIPLY_KHR 0x9294 +#define GL_SCREEN_KHR 0x9295 +#define GL_OVERLAY_KHR 0x9296 +#define GL_DARKEN_KHR 0x9297 +#define GL_LIGHTEN_KHR 0x9298 +#define GL_COLORDODGE_KHR 0x9299 +#define GL_COLORBURN_KHR 0x929A +#define GL_HARDLIGHT_KHR 0x929B +#define GL_SOFTLIGHT_KHR 0x929C +#define GL_DIFFERENCE_KHR 0x929E +#define GL_EXCLUSION_KHR 0x92A0 +#define GL_HSL_HUE_KHR 0x92AD +#define GL_HSL_SATURATION_KHR 0x92AE +#define GL_HSL_COLOR_KHR 0x92AF +#define GL_HSL_LUMINOSITY_KHR 0x92B0 +typedef void (APIENTRYP PFNGLBLENDBARRIERKHRPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendBarrierKHR (void); +#endif +#endif /* GL_KHR_blend_equation_advanced */ + +#ifndef GL_KHR_blend_equation_advanced_coherent +#define GL_KHR_blend_equation_advanced_coherent 1 +#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 +#endif /* GL_KHR_blend_equation_advanced_coherent */ + +#ifndef GL_KHR_context_flush_control +#define GL_KHR_context_flush_control 1 +#endif /* GL_KHR_context_flush_control */ + +#ifndef GL_KHR_debug +#define GL_KHR_debug 1 +#endif /* GL_KHR_debug */ + +#ifndef GL_KHR_no_error +#define GL_KHR_no_error 1 +#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008 +#endif /* GL_KHR_no_error */ + +#ifndef GL_KHR_robust_buffer_access_behavior +#define GL_KHR_robust_buffer_access_behavior 1 +#endif /* GL_KHR_robust_buffer_access_behavior */ + +#ifndef GL_KHR_robustness +#define GL_KHR_robustness 1 +#define GL_CONTEXT_ROBUST_ACCESS 0x90F3 +#endif /* GL_KHR_robustness */ + +#ifndef GL_KHR_texture_compression_astc_hdr +#define GL_KHR_texture_compression_astc_hdr 1 +#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB +#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC +#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#endif /* GL_KHR_texture_compression_astc_hdr */ + +#ifndef GL_KHR_texture_compression_astc_ldr +#define GL_KHR_texture_compression_astc_ldr 1 +#endif /* GL_KHR_texture_compression_astc_ldr */ + +#ifndef GL_KHR_texture_compression_astc_sliced_3d +#define GL_KHR_texture_compression_astc_sliced_3d 1 +#endif /* GL_KHR_texture_compression_astc_sliced_3d */ + +#ifndef GL_OES_byte_coordinates +#define GL_OES_byte_coordinates 1 +typedef void (APIENTRYP PFNGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD1BOESPROC) (GLbyte s); +typedef void (APIENTRYP PFNGLTEXCOORD1BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t); +typedef void (APIENTRYP PFNGLTEXCOORD2BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r); +typedef void (APIENTRYP PFNGLTEXCOORD3BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q); +typedef void (APIENTRYP PFNGLTEXCOORD4BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLVERTEX2BOESPROC) (GLbyte x, GLbyte y); +typedef void (APIENTRYP PFNGLVERTEX2BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLVERTEX3BOESPROC) (GLbyte x, GLbyte y, GLbyte z); +typedef void (APIENTRYP PFNGLVERTEX3BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z, GLbyte w); +typedef void (APIENTRYP PFNGLVERTEX4BVOESPROC) (const GLbyte *coords); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiTexCoord1bOES (GLenum texture, GLbyte s); +GLAPI void APIENTRY glMultiTexCoord1bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glMultiTexCoord2bOES (GLenum texture, GLbyte s, GLbyte t); +GLAPI void APIENTRY glMultiTexCoord2bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glMultiTexCoord3bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r); +GLAPI void APIENTRY glMultiTexCoord3bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glMultiTexCoord4bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q); +GLAPI void APIENTRY glMultiTexCoord4bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glTexCoord1bOES (GLbyte s); +GLAPI void APIENTRY glTexCoord1bvOES (const GLbyte *coords); +GLAPI void APIENTRY glTexCoord2bOES (GLbyte s, GLbyte t); +GLAPI void APIENTRY glTexCoord2bvOES (const GLbyte *coords); +GLAPI void APIENTRY glTexCoord3bOES (GLbyte s, GLbyte t, GLbyte r); +GLAPI void APIENTRY glTexCoord3bvOES (const GLbyte *coords); +GLAPI void APIENTRY glTexCoord4bOES (GLbyte s, GLbyte t, GLbyte r, GLbyte q); +GLAPI void APIENTRY glTexCoord4bvOES (const GLbyte *coords); +GLAPI void APIENTRY glVertex2bOES (GLbyte x, GLbyte y); +GLAPI void APIENTRY glVertex2bvOES (const GLbyte *coords); +GLAPI void APIENTRY glVertex3bOES (GLbyte x, GLbyte y, GLbyte z); +GLAPI void APIENTRY glVertex3bvOES (const GLbyte *coords); +GLAPI void APIENTRY glVertex4bOES (GLbyte x, GLbyte y, GLbyte z, GLbyte w); +GLAPI void APIENTRY glVertex4bvOES (const GLbyte *coords); +#endif +#endif /* GL_OES_byte_coordinates */ + +#ifndef GL_OES_compressed_paletted_texture +#define GL_OES_compressed_paletted_texture 1 +#define GL_PALETTE4_RGB8_OES 0x8B90 +#define GL_PALETTE4_RGBA8_OES 0x8B91 +#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 +#define GL_PALETTE4_RGBA4_OES 0x8B93 +#define GL_PALETTE4_RGB5_A1_OES 0x8B94 +#define GL_PALETTE8_RGB8_OES 0x8B95 +#define GL_PALETTE8_RGBA8_OES 0x8B96 +#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 +#define GL_PALETTE8_RGBA4_OES 0x8B98 +#define GL_PALETTE8_RGB5_A1_OES 0x8B99 +#endif /* GL_OES_compressed_paletted_texture */ + +#ifndef GL_OES_fixed_point +#define GL_OES_fixed_point 1 +typedef GLint GLfixed; +#define GL_FIXED_OES 0x140C +typedef void (APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref); +typedef void (APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLfixed depth); +typedef void (APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation); +typedef void (APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f); +typedef void (APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *param); +typedef void (APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +typedef void (APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation); +typedef void (APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param); +typedef void (APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width); +typedef void (APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param); +typedef void (APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q); +typedef void (APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz); +typedef void (APIENTRYP PFNGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +typedef void (APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size); +typedef void (APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units); +typedef void (APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLACCUMXOESPROC) (GLenum op, GLfixed value); +typedef void (APIENTRYP PFNGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap); +typedef void (APIENTRYP PFNGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue); +typedef void (APIENTRYP PFNGLCOLOR3XVOESPROC) (const GLfixed *components); +typedef void (APIENTRYP PFNGLCOLOR4XVOESPROC) (const GLfixed *components); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLEVALCOORD1XOESPROC) (GLfixed u); +typedef void (APIENTRYP PFNGLEVALCOORD1XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v); +typedef void (APIENTRYP PFNGLEVALCOORD2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v); +typedef void (APIENTRYP PFNGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values); +typedef void (APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLINDEXXOESPROC) (GLfixed component); +typedef void (APIENTRYP PFNGLINDEXXVOESPROC) (const GLfixed *component); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points); +typedef void (APIENTRYP PFNGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points); +typedef void (APIENTRYP PFNGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2); +typedef void (APIENTRYP PFNGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLNORMAL3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLPASSTHROUGHXOESPROC) (GLfixed token); +typedef void (APIENTRYP PFNGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values); +typedef void (APIENTRYP PFNGLPIXELSTOREXPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor); +typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities); +typedef void (APIENTRYP PFNGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y); +typedef void (APIENTRYP PFNGLRASTERPOS2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLRASTERPOS3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w); +typedef void (APIENTRYP PFNGLRASTERPOS4XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2); +typedef void (APIENTRYP PFNGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2); +typedef void (APIENTRYP PFNGLTEXCOORD1XOESPROC) (GLfixed s); +typedef void (APIENTRYP PFNGLTEXCOORD1XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t); +typedef void (APIENTRYP PFNGLTEXCOORD2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r); +typedef void (APIENTRYP PFNGLTEXCOORD3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q); +typedef void (APIENTRYP PFNGLTEXCOORD4XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLVERTEX2XOESPROC) (GLfixed x); +typedef void (APIENTRYP PFNGLVERTEX2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLVERTEX3XOESPROC) (GLfixed x, GLfixed y); +typedef void (APIENTRYP PFNGLVERTEX3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLVERTEX4XVOESPROC) (const GLfixed *coords); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glAlphaFuncxOES (GLenum func, GLfixed ref); +GLAPI void APIENTRY glClearColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glClearDepthxOES (GLfixed depth); +GLAPI void APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation); +GLAPI void APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glDepthRangexOES (GLfixed n, GLfixed f); +GLAPI void APIENTRY glFogxOES (GLenum pname, GLfixed param); +GLAPI void APIENTRY glFogxvOES (GLenum pname, const GLfixed *param); +GLAPI void APIENTRY glFrustumxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +GLAPI void APIENTRY glGetClipPlanexOES (GLenum plane, GLfixed *equation); +GLAPI void APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetTexEnvxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glLightModelxOES (GLenum pname, GLfixed param); +GLAPI void APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *param); +GLAPI void APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param); +GLAPI void APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glLineWidthxOES (GLfixed width); +GLAPI void APIENTRY glLoadMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param); +GLAPI void APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *param); +GLAPI void APIENTRY glMultMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMultiTexCoord4xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q); +GLAPI void APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz); +GLAPI void APIENTRY glOrthoxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +GLAPI void APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glPointSizexOES (GLfixed size); +GLAPI void APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units); +GLAPI void APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param); +GLAPI void APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param); +GLAPI void APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glAccumxOES (GLenum op, GLfixed value); +GLAPI void APIENTRY glBitmapxOES (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap); +GLAPI void APIENTRY glBlendColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glClearAccumxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glColor3xOES (GLfixed red, GLfixed green, GLfixed blue); +GLAPI void APIENTRY glColor3xvOES (const GLfixed *components); +GLAPI void APIENTRY glColor4xvOES (const GLfixed *components); +GLAPI void APIENTRY glConvolutionParameterxOES (GLenum target, GLenum pname, GLfixed param); +GLAPI void APIENTRY glConvolutionParameterxvOES (GLenum target, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glEvalCoord1xOES (GLfixed u); +GLAPI void APIENTRY glEvalCoord1xvOES (const GLfixed *coords); +GLAPI void APIENTRY glEvalCoord2xOES (GLfixed u, GLfixed v); +GLAPI void APIENTRY glEvalCoord2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glFeedbackBufferxOES (GLsizei n, GLenum type, const GLfixed *buffer); +GLAPI void APIENTRY glGetConvolutionParameterxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetHistogramParameterxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetLightxOES (GLenum light, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetMapxvOES (GLenum target, GLenum query, GLfixed *v); +GLAPI void APIENTRY glGetMaterialxOES (GLenum face, GLenum pname, GLfixed param); +GLAPI void APIENTRY glGetPixelMapxv (GLenum map, GLint size, GLfixed *values); +GLAPI void APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetTexLevelParameterxvOES (GLenum target, GLint level, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glIndexxOES (GLfixed component); +GLAPI void APIENTRY glIndexxvOES (const GLfixed *component); +GLAPI void APIENTRY glLoadTransposeMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMap1xOES (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points); +GLAPI void APIENTRY glMap2xOES (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points); +GLAPI void APIENTRY glMapGrid1xOES (GLint n, GLfixed u1, GLfixed u2); +GLAPI void APIENTRY glMapGrid2xOES (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2); +GLAPI void APIENTRY glMultTransposeMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMultiTexCoord1xOES (GLenum texture, GLfixed s); +GLAPI void APIENTRY glMultiTexCoord1xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glMultiTexCoord2xOES (GLenum texture, GLfixed s, GLfixed t); +GLAPI void APIENTRY glMultiTexCoord2xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glMultiTexCoord3xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r); +GLAPI void APIENTRY glMultiTexCoord3xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glMultiTexCoord4xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glNormal3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glPassThroughxOES (GLfixed token); +GLAPI void APIENTRY glPixelMapx (GLenum map, GLint size, const GLfixed *values); +GLAPI void APIENTRY glPixelStorex (GLenum pname, GLfixed param); +GLAPI void APIENTRY glPixelTransferxOES (GLenum pname, GLfixed param); +GLAPI void APIENTRY glPixelZoomxOES (GLfixed xfactor, GLfixed yfactor); +GLAPI void APIENTRY glPrioritizeTexturesxOES (GLsizei n, const GLuint *textures, const GLfixed *priorities); +GLAPI void APIENTRY glRasterPos2xOES (GLfixed x, GLfixed y); +GLAPI void APIENTRY glRasterPos2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glRasterPos3xOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glRasterPos3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glRasterPos4xOES (GLfixed x, GLfixed y, GLfixed z, GLfixed w); +GLAPI void APIENTRY glRasterPos4xvOES (const GLfixed *coords); +GLAPI void APIENTRY glRectxOES (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2); +GLAPI void APIENTRY glRectxvOES (const GLfixed *v1, const GLfixed *v2); +GLAPI void APIENTRY glTexCoord1xOES (GLfixed s); +GLAPI void APIENTRY glTexCoord1xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexCoord2xOES (GLfixed s, GLfixed t); +GLAPI void APIENTRY glTexCoord2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexCoord3xOES (GLfixed s, GLfixed t, GLfixed r); +GLAPI void APIENTRY glTexCoord3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexCoord4xOES (GLfixed s, GLfixed t, GLfixed r, GLfixed q); +GLAPI void APIENTRY glTexCoord4xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param); +GLAPI void APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glVertex2xOES (GLfixed x); +GLAPI void APIENTRY glVertex2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glVertex3xOES (GLfixed x, GLfixed y); +GLAPI void APIENTRY glVertex3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glVertex4xOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glVertex4xvOES (const GLfixed *coords); +#endif +#endif /* GL_OES_fixed_point */ + +#ifndef GL_OES_query_matrix +#define GL_OES_query_matrix 1 +typedef GLbitfield (APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLbitfield APIENTRY glQueryMatrixxOES (GLfixed *mantissa, GLint *exponent); +#endif +#endif /* GL_OES_query_matrix */ + +#ifndef GL_OES_read_format +#define GL_OES_read_format 1 +#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B +#endif /* GL_OES_read_format */ + +#ifndef GL_OES_single_precision +#define GL_OES_single_precision 1 +typedef void (APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth); +typedef void (APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation); +typedef void (APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f); +typedef void (APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +typedef void (APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation); +typedef void (APIENTRYP PFNGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClearDepthfOES (GLclampf depth); +GLAPI void APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation); +GLAPI void APIENTRY glDepthRangefOES (GLclampf n, GLclampf f); +GLAPI void APIENTRY glFrustumfOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +GLAPI void APIENTRY glGetClipPlanefOES (GLenum plane, GLfloat *equation); +GLAPI void APIENTRY glOrthofOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +#endif +#endif /* GL_OES_single_precision */ + +#ifndef GL_3DFX_multisample +#define GL_3DFX_multisample 1 +#define GL_MULTISAMPLE_3DFX 0x86B2 +#define GL_SAMPLE_BUFFERS_3DFX 0x86B3 +#define GL_SAMPLES_3DFX 0x86B4 +#define GL_MULTISAMPLE_BIT_3DFX 0x20000000 +#endif /* GL_3DFX_multisample */ + +#ifndef GL_3DFX_tbuffer +#define GL_3DFX_tbuffer 1 +typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTbufferMask3DFX (GLuint mask); +#endif +#endif /* GL_3DFX_tbuffer */ + +#ifndef GL_3DFX_texture_compression_FXT1 +#define GL_3DFX_texture_compression_FXT1 1 +#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 +#define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 +#endif /* GL_3DFX_texture_compression_FXT1 */ + +#ifndef GL_AMD_blend_minmax_factor +#define GL_AMD_blend_minmax_factor 1 +#define GL_FACTOR_MIN_AMD 0x901C +#define GL_FACTOR_MAX_AMD 0x901D +#endif /* GL_AMD_blend_minmax_factor */ + +#ifndef GL_AMD_conservative_depth +#define GL_AMD_conservative_depth 1 +#endif /* GL_AMD_conservative_depth */ + +#ifndef GL_AMD_debug_output +#define GL_AMD_debug_output 1 +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +#define GL_MAX_DEBUG_MESSAGE_LENGTH_AMD 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_AMD 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147 +#define GL_DEBUG_SEVERITY_LOW_AMD 0x9148 +#define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149 +#define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A +#define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B +#define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C +#define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D +#define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E +#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F +#define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150 +typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); +#endif +#endif /* GL_AMD_debug_output */ + +#ifndef GL_AMD_depth_clamp_separate +#define GL_AMD_depth_clamp_separate 1 +#define GL_DEPTH_CLAMP_NEAR_AMD 0x901E +#define GL_DEPTH_CLAMP_FAR_AMD 0x901F +#endif /* GL_AMD_depth_clamp_separate */ + +#ifndef GL_AMD_draw_buffers_blend +#define GL_AMD_draw_buffers_blend 1 +typedef void (APIENTRYP PFNGLBLENDFUNCINDEXEDAMDPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (APIENTRYP PFNGLBLENDEQUATIONINDEXEDAMDPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncIndexedAMD (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparateIndexedAMD (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GLAPI void APIENTRY glBlendEquationIndexedAMD (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +#endif +#endif /* GL_AMD_draw_buffers_blend */ + +#ifndef GL_AMD_gcn_shader +#define GL_AMD_gcn_shader 1 +#endif /* GL_AMD_gcn_shader */ + +#ifndef GL_AMD_gpu_shader_int64 +#define GL_AMD_gpu_shader_int64 1 +typedef int64_t GLint64EXT; +#define GL_INT64_NV 0x140E +#define GL_UNSIGNED_INT64_NV 0x140F +#define GL_INT8_NV 0x8FE0 +#define GL_INT8_VEC2_NV 0x8FE1 +#define GL_INT8_VEC3_NV 0x8FE2 +#define GL_INT8_VEC4_NV 0x8FE3 +#define GL_INT16_NV 0x8FE4 +#define GL_INT16_VEC2_NV 0x8FE5 +#define GL_INT16_VEC3_NV 0x8FE6 +#define GL_INT16_VEC4_NV 0x8FE7 +#define GL_INT64_VEC2_NV 0x8FE9 +#define GL_INT64_VEC3_NV 0x8FEA +#define GL_INT64_VEC4_NV 0x8FEB +#define GL_UNSIGNED_INT8_NV 0x8FEC +#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED +#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE +#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF +#define GL_UNSIGNED_INT16_NV 0x8FF0 +#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 +#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 +#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 +#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 +#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 +#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 +#define GL_FLOAT16_NV 0x8FF8 +#define GL_FLOAT16_VEC2_NV 0x8FF9 +#define GL_FLOAT16_VEC3_NV 0x8FFA +#define GL_FLOAT16_VEC4_NV 0x8FFB +typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); +typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); +typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); +typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); +typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); +GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); +GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); +GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params); +GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); +GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); +GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#endif +#endif /* GL_AMD_gpu_shader_int64 */ + +#ifndef GL_AMD_interleaved_elements +#define GL_AMD_interleaved_elements 1 +#define GL_VERTEX_ELEMENT_SWIZZLE_AMD 0x91A4 +#define GL_VERTEX_ID_SWIZZLE_AMD 0x91A5 +typedef void (APIENTRYP PFNGLVERTEXATTRIBPARAMETERIAMDPROC) (GLuint index, GLenum pname, GLint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribParameteriAMD (GLuint index, GLenum pname, GLint param); +#endif +#endif /* GL_AMD_interleaved_elements */ + +#ifndef GL_AMD_multi_draw_indirect +#define GL_AMD_multi_draw_indirect 1 +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride); +#endif +#endif /* GL_AMD_multi_draw_indirect */ + +#ifndef GL_AMD_name_gen_delete +#define GL_AMD_name_gen_delete 1 +#define GL_DATA_BUFFER_AMD 0x9151 +#define GL_PERFORMANCE_MONITOR_AMD 0x9152 +#define GL_QUERY_OBJECT_AMD 0x9153 +#define GL_VERTEX_ARRAY_OBJECT_AMD 0x9154 +#define GL_SAMPLER_OBJECT_AMD 0x9155 +typedef void (APIENTRYP PFNGLGENNAMESAMDPROC) (GLenum identifier, GLuint num, GLuint *names); +typedef void (APIENTRYP PFNGLDELETENAMESAMDPROC) (GLenum identifier, GLuint num, const GLuint *names); +typedef GLboolean (APIENTRYP PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenNamesAMD (GLenum identifier, GLuint num, GLuint *names); +GLAPI void APIENTRY glDeleteNamesAMD (GLenum identifier, GLuint num, const GLuint *names); +GLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name); +#endif +#endif /* GL_AMD_name_gen_delete */ + +#ifndef GL_AMD_occlusion_query_event +#define GL_AMD_occlusion_query_event 1 +#define GL_OCCLUSION_QUERY_EVENT_MASK_AMD 0x874F +#define GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD 0x00000001 +#define GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD 0x00000002 +#define GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD 0x00000004 +#define GL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD 0x00000008 +#define GL_QUERY_ALL_EVENT_BITS_AMD 0xFFFFFFFF +typedef void (APIENTRYP PFNGLQUERYOBJECTPARAMETERUIAMDPROC) (GLenum target, GLuint id, GLenum pname, GLuint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glQueryObjectParameteruiAMD (GLenum target, GLuint id, GLenum pname, GLuint param); +#endif +#endif /* GL_AMD_occlusion_query_event */ + +#ifndef GL_AMD_performance_monitor +#define GL_AMD_performance_monitor 1 +#define GL_COUNTER_TYPE_AMD 0x8BC0 +#define GL_COUNTER_RANGE_AMD 0x8BC1 +#define GL_UNSIGNED_INT64_AMD 0x8BC2 +#define GL_PERCENTAGE_AMD 0x8BC3 +#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 +#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 +#define GL_PERFMON_RESULT_AMD 0x8BC6 +typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); +typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data); +typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); +typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); +typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); +typedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); +typedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); +GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); +GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); +GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); +GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data); +GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); +GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); +GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); +GLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor); +GLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor); +GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +#endif +#endif /* GL_AMD_performance_monitor */ + +#ifndef GL_AMD_pinned_memory +#define GL_AMD_pinned_memory 1 +#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160 +#endif /* GL_AMD_pinned_memory */ + +#ifndef GL_AMD_query_buffer_object +#define GL_AMD_query_buffer_object 1 +#define GL_QUERY_BUFFER_AMD 0x9192 +#define GL_QUERY_BUFFER_BINDING_AMD 0x9193 +#define GL_QUERY_RESULT_NO_WAIT_AMD 0x9194 +#endif /* GL_AMD_query_buffer_object */ + +#ifndef GL_AMD_sample_positions +#define GL_AMD_sample_positions 1 +#define GL_SUBSAMPLE_DISTANCE_AMD 0x883F +typedef void (APIENTRYP PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint index, const GLfloat *val); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLfloat *val); +#endif +#endif /* GL_AMD_sample_positions */ + +#ifndef GL_AMD_seamless_cubemap_per_texture +#define GL_AMD_seamless_cubemap_per_texture 1 +#endif /* GL_AMD_seamless_cubemap_per_texture */ + +#ifndef GL_AMD_shader_atomic_counter_ops +#define GL_AMD_shader_atomic_counter_ops 1 +#endif /* GL_AMD_shader_atomic_counter_ops */ + +#ifndef GL_AMD_shader_stencil_export +#define GL_AMD_shader_stencil_export 1 +#endif /* GL_AMD_shader_stencil_export */ + +#ifndef GL_AMD_shader_trinary_minmax +#define GL_AMD_shader_trinary_minmax 1 +#endif /* GL_AMD_shader_trinary_minmax */ + +#ifndef GL_AMD_sparse_texture +#define GL_AMD_sparse_texture 1 +#define GL_VIRTUAL_PAGE_SIZE_X_AMD 0x9195 +#define GL_VIRTUAL_PAGE_SIZE_Y_AMD 0x9196 +#define GL_VIRTUAL_PAGE_SIZE_Z_AMD 0x9197 +#define GL_MAX_SPARSE_TEXTURE_SIZE_AMD 0x9198 +#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD 0x9199 +#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS 0x919A +#define GL_MIN_SPARSE_LEVEL_AMD 0x919B +#define GL_MIN_LOD_WARNING_AMD 0x919C +#define GL_TEXTURE_STORAGE_SPARSE_BIT_AMD 0x00000001 +typedef void (APIENTRYP PFNGLTEXSTORAGESPARSEAMDPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +typedef void (APIENTRYP PFNGLTEXTURESTORAGESPARSEAMDPROC) (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexStorageSparseAMD (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +GLAPI void APIENTRY glTextureStorageSparseAMD (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +#endif +#endif /* GL_AMD_sparse_texture */ + +#ifndef GL_AMD_stencil_operation_extended +#define GL_AMD_stencil_operation_extended 1 +#define GL_SET_AMD 0x874A +#define GL_REPLACE_VALUE_AMD 0x874B +#define GL_STENCIL_OP_VALUE_AMD 0x874C +#define GL_STENCIL_BACK_OP_VALUE_AMD 0x874D +typedef void (APIENTRYP PFNGLSTENCILOPVALUEAMDPROC) (GLenum face, GLuint value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStencilOpValueAMD (GLenum face, GLuint value); +#endif +#endif /* GL_AMD_stencil_operation_extended */ + +#ifndef GL_AMD_texture_texture4 +#define GL_AMD_texture_texture4 1 +#endif /* GL_AMD_texture_texture4 */ + +#ifndef GL_AMD_transform_feedback3_lines_triangles +#define GL_AMD_transform_feedback3_lines_triangles 1 +#endif /* GL_AMD_transform_feedback3_lines_triangles */ + +#ifndef GL_AMD_transform_feedback4 +#define GL_AMD_transform_feedback4 1 +#define GL_STREAM_RASTERIZATION_AMD 0x91A0 +#endif /* GL_AMD_transform_feedback4 */ + +#ifndef GL_AMD_vertex_shader_layer +#define GL_AMD_vertex_shader_layer 1 +#endif /* GL_AMD_vertex_shader_layer */ + +#ifndef GL_AMD_vertex_shader_tessellator +#define GL_AMD_vertex_shader_tessellator 1 +#define GL_SAMPLER_BUFFER_AMD 0x9001 +#define GL_INT_SAMPLER_BUFFER_AMD 0x9002 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003 +#define GL_TESSELLATION_MODE_AMD 0x9004 +#define GL_TESSELLATION_FACTOR_AMD 0x9005 +#define GL_DISCRETE_AMD 0x9006 +#define GL_CONTINUOUS_AMD 0x9007 +typedef void (APIENTRYP PFNGLTESSELLATIONFACTORAMDPROC) (GLfloat factor); +typedef void (APIENTRYP PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTessellationFactorAMD (GLfloat factor); +GLAPI void APIENTRY glTessellationModeAMD (GLenum mode); +#endif +#endif /* GL_AMD_vertex_shader_tessellator */ + +#ifndef GL_AMD_vertex_shader_viewport_index +#define GL_AMD_vertex_shader_viewport_index 1 +#endif /* GL_AMD_vertex_shader_viewport_index */ + +#ifndef GL_APPLE_aux_depth_stencil +#define GL_APPLE_aux_depth_stencil 1 +#define GL_AUX_DEPTH_STENCIL_APPLE 0x8A14 +#endif /* GL_APPLE_aux_depth_stencil */ + +#ifndef GL_APPLE_client_storage +#define GL_APPLE_client_storage 1 +#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 +#endif /* GL_APPLE_client_storage */ + +#ifndef GL_APPLE_element_array +#define GL_APPLE_element_array 1 +#define GL_ELEMENT_ARRAY_APPLE 0x8A0C +#define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8A0D +#define GL_ELEMENT_ARRAY_POINTER_APPLE 0x8A0E +typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const void *pointer); +typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const void *pointer); +GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count); +GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); +GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); +#endif +#endif /* GL_APPLE_element_array */ + +#ifndef GL_APPLE_fence +#define GL_APPLE_fence 1 +#define GL_DRAW_PIXELS_APPLE 0x8A0A +#define GL_FENCE_APPLE 0x8A0B +typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences); +typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences); +typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name); +typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenFencesAPPLE (GLsizei n, GLuint *fences); +GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei n, const GLuint *fences); +GLAPI void APIENTRY glSetFenceAPPLE (GLuint fence); +GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint fence); +GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint fence); +GLAPI void APIENTRY glFinishFenceAPPLE (GLuint fence); +GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum object, GLuint name); +GLAPI void APIENTRY glFinishObjectAPPLE (GLenum object, GLint name); +#endif +#endif /* GL_APPLE_fence */ + +#ifndef GL_APPLE_float_pixels +#define GL_APPLE_float_pixels 1 +#define GL_HALF_APPLE 0x140B +#define GL_RGBA_FLOAT32_APPLE 0x8814 +#define GL_RGB_FLOAT32_APPLE 0x8815 +#define GL_ALPHA_FLOAT32_APPLE 0x8816 +#define GL_INTENSITY_FLOAT32_APPLE 0x8817 +#define GL_LUMINANCE_FLOAT32_APPLE 0x8818 +#define GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819 +#define GL_RGBA_FLOAT16_APPLE 0x881A +#define GL_RGB_FLOAT16_APPLE 0x881B +#define GL_ALPHA_FLOAT16_APPLE 0x881C +#define GL_INTENSITY_FLOAT16_APPLE 0x881D +#define GL_LUMINANCE_FLOAT16_APPLE 0x881E +#define GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F +#define GL_COLOR_FLOAT_APPLE 0x8A0F +#endif /* GL_APPLE_float_pixels */ + +#ifndef GL_APPLE_flush_buffer_range +#define GL_APPLE_flush_buffer_range 1 +#define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 +#define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 +typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum target, GLintptr offset, GLsizeiptr size); +#endif +#endif /* GL_APPLE_flush_buffer_range */ + +#ifndef GL_APPLE_object_purgeable +#define GL_APPLE_object_purgeable 1 +#define GL_BUFFER_OBJECT_APPLE 0x85B3 +#define GL_RELEASED_APPLE 0x8A19 +#define GL_VOLATILE_APPLE 0x8A1A +#define GL_RETAINED_APPLE 0x8A1B +#define GL_UNDEFINED_APPLE 0x8A1C +#define GL_PURGEABLE_APPLE 0x8A1D +typedef GLenum (APIENTRYP PFNGLOBJECTPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); +typedef GLenum (APIENTRYP PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVAPPLEPROC) (GLenum objectType, GLuint name, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLenum APIENTRY glObjectPurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); +GLAPI GLenum APIENTRY glObjectUnpurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); +GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, GLenum pname, GLint *params); +#endif +#endif /* GL_APPLE_object_purgeable */ + +#ifndef GL_APPLE_rgb_422 +#define GL_APPLE_rgb_422 1 +#define GL_RGB_422_APPLE 0x8A1F +#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA +#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB +#define GL_RGB_RAW_422_APPLE 0x8A51 +#endif /* GL_APPLE_rgb_422 */ + +#ifndef GL_APPLE_row_bytes +#define GL_APPLE_row_bytes 1 +#define GL_PACK_ROW_BYTES_APPLE 0x8A15 +#define GL_UNPACK_ROW_BYTES_APPLE 0x8A16 +#endif /* GL_APPLE_row_bytes */ + +#ifndef GL_APPLE_specular_vector +#define GL_APPLE_specular_vector 1 +#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 +#endif /* GL_APPLE_specular_vector */ + +#ifndef GL_APPLE_texture_range +#define GL_APPLE_texture_range 1 +#define GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7 +#define GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8 +#define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC +#define GL_STORAGE_PRIVATE_APPLE 0x85BD +#define GL_STORAGE_CACHED_APPLE 0x85BE +#define GL_STORAGE_SHARED_APPLE 0x85BF +typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const void *pointer); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, void **params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const void *pointer); +GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, void **params); +#endif +#endif /* GL_APPLE_texture_range */ + +#ifndef GL_APPLE_transform_hint +#define GL_APPLE_transform_hint 1 +#define GL_TRANSFORM_HINT_APPLE 0x85B1 +#endif /* GL_APPLE_transform_hint */ + +#ifndef GL_APPLE_vertex_array_object +#define GL_APPLE_vertex_array_object 1 +#define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array); +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint array); +GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays); +GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei n, GLuint *arrays); +GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array); +#endif +#endif /* GL_APPLE_vertex_array_object */ + +#ifndef GL_APPLE_vertex_array_range +#define GL_APPLE_vertex_array_range 1 +#define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D +#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E +#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F +#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 +#define GL_STORAGE_CLIENT_APPLE 0x85B4 +typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer); +typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer); +typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, void *pointer); +GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, void *pointer); +GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param); +#endif +#endif /* GL_APPLE_vertex_array_range */ + +#ifndef GL_APPLE_vertex_program_evaluators +#define GL_APPLE_vertex_program_evaluators 1 +#define GL_VERTEX_ATTRIB_MAP1_APPLE 0x8A00 +#define GL_VERTEX_ATTRIB_MAP2_APPLE 0x8A01 +#define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE 0x8A02 +#define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03 +#define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04 +#define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05 +#define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE 0x8A06 +#define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07 +#define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08 +#define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09 +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); +typedef GLboolean (APIENTRYP PFNGLISVERTEXATTRIBENABLEDAPPLEPROC) (GLuint index, GLenum pname); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glEnableVertexAttribAPPLE (GLuint index, GLenum pname); +GLAPI void APIENTRY glDisableVertexAttribAPPLE (GLuint index, GLenum pname); +GLAPI GLboolean APIENTRY glIsVertexAttribEnabledAPPLE (GLuint index, GLenum pname); +GLAPI void APIENTRY glMapVertexAttrib1dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +GLAPI void APIENTRY glMapVertexAttrib1fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +GLAPI void APIENTRY glMapVertexAttrib2dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +GLAPI void APIENTRY glMapVertexAttrib2fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +#endif +#endif /* GL_APPLE_vertex_program_evaluators */ + +#ifndef GL_APPLE_ycbcr_422 +#define GL_APPLE_ycbcr_422 1 +#define GL_YCBCR_422_APPLE 0x85B9 +#endif /* GL_APPLE_ycbcr_422 */ + +#ifndef GL_ATI_draw_buffers +#define GL_ATI_draw_buffers 1 +#define GL_MAX_DRAW_BUFFERS_ATI 0x8824 +#define GL_DRAW_BUFFER0_ATI 0x8825 +#define GL_DRAW_BUFFER1_ATI 0x8826 +#define GL_DRAW_BUFFER2_ATI 0x8827 +#define GL_DRAW_BUFFER3_ATI 0x8828 +#define GL_DRAW_BUFFER4_ATI 0x8829 +#define GL_DRAW_BUFFER5_ATI 0x882A +#define GL_DRAW_BUFFER6_ATI 0x882B +#define GL_DRAW_BUFFER7_ATI 0x882C +#define GL_DRAW_BUFFER8_ATI 0x882D +#define GL_DRAW_BUFFER9_ATI 0x882E +#define GL_DRAW_BUFFER10_ATI 0x882F +#define GL_DRAW_BUFFER11_ATI 0x8830 +#define GL_DRAW_BUFFER12_ATI 0x8831 +#define GL_DRAW_BUFFER13_ATI 0x8832 +#define GL_DRAW_BUFFER14_ATI 0x8833 +#define GL_DRAW_BUFFER15_ATI 0x8834 +typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs); +#endif +#endif /* GL_ATI_draw_buffers */ + +#ifndef GL_ATI_element_array +#define GL_ATI_element_array 1 +#define GL_ELEMENT_ARRAY_ATI 0x8768 +#define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 +#define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A +typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const void *pointer); +typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glElementPointerATI (GLenum type, const void *pointer); +GLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count); +GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count); +#endif +#endif /* GL_ATI_element_array */ + +#ifndef GL_ATI_envmap_bumpmap +#define GL_ATI_envmap_bumpmap 1 +#define GL_BUMP_ROT_MATRIX_ATI 0x8775 +#define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 +#define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 +#define GL_BUMP_TEX_UNITS_ATI 0x8778 +#define GL_DUDV_ATI 0x8779 +#define GL_DU8DV8_ATI 0x877A +#define GL_BUMP_ENVMAP_ATI 0x877B +#define GL_BUMP_TARGET_ATI 0x877C +typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param); +typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexBumpParameterivATI (GLenum pname, const GLint *param); +GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum pname, const GLfloat *param); +GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum pname, GLint *param); +GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum pname, GLfloat *param); +#endif +#endif /* GL_ATI_envmap_bumpmap */ + +#ifndef GL_ATI_fragment_shader +#define GL_ATI_fragment_shader 1 +#define GL_FRAGMENT_SHADER_ATI 0x8920 +#define GL_REG_0_ATI 0x8921 +#define GL_REG_1_ATI 0x8922 +#define GL_REG_2_ATI 0x8923 +#define GL_REG_3_ATI 0x8924 +#define GL_REG_4_ATI 0x8925 +#define GL_REG_5_ATI 0x8926 +#define GL_REG_6_ATI 0x8927 +#define GL_REG_7_ATI 0x8928 +#define GL_REG_8_ATI 0x8929 +#define GL_REG_9_ATI 0x892A +#define GL_REG_10_ATI 0x892B +#define GL_REG_11_ATI 0x892C +#define GL_REG_12_ATI 0x892D +#define GL_REG_13_ATI 0x892E +#define GL_REG_14_ATI 0x892F +#define GL_REG_15_ATI 0x8930 +#define GL_REG_16_ATI 0x8931 +#define GL_REG_17_ATI 0x8932 +#define GL_REG_18_ATI 0x8933 +#define GL_REG_19_ATI 0x8934 +#define GL_REG_20_ATI 0x8935 +#define GL_REG_21_ATI 0x8936 +#define GL_REG_22_ATI 0x8937 +#define GL_REG_23_ATI 0x8938 +#define GL_REG_24_ATI 0x8939 +#define GL_REG_25_ATI 0x893A +#define GL_REG_26_ATI 0x893B +#define GL_REG_27_ATI 0x893C +#define GL_REG_28_ATI 0x893D +#define GL_REG_29_ATI 0x893E +#define GL_REG_30_ATI 0x893F +#define GL_REG_31_ATI 0x8940 +#define GL_CON_0_ATI 0x8941 +#define GL_CON_1_ATI 0x8942 +#define GL_CON_2_ATI 0x8943 +#define GL_CON_3_ATI 0x8944 +#define GL_CON_4_ATI 0x8945 +#define GL_CON_5_ATI 0x8946 +#define GL_CON_6_ATI 0x8947 +#define GL_CON_7_ATI 0x8948 +#define GL_CON_8_ATI 0x8949 +#define GL_CON_9_ATI 0x894A +#define GL_CON_10_ATI 0x894B +#define GL_CON_11_ATI 0x894C +#define GL_CON_12_ATI 0x894D +#define GL_CON_13_ATI 0x894E +#define GL_CON_14_ATI 0x894F +#define GL_CON_15_ATI 0x8950 +#define GL_CON_16_ATI 0x8951 +#define GL_CON_17_ATI 0x8952 +#define GL_CON_18_ATI 0x8953 +#define GL_CON_19_ATI 0x8954 +#define GL_CON_20_ATI 0x8955 +#define GL_CON_21_ATI 0x8956 +#define GL_CON_22_ATI 0x8957 +#define GL_CON_23_ATI 0x8958 +#define GL_CON_24_ATI 0x8959 +#define GL_CON_25_ATI 0x895A +#define GL_CON_26_ATI 0x895B +#define GL_CON_27_ATI 0x895C +#define GL_CON_28_ATI 0x895D +#define GL_CON_29_ATI 0x895E +#define GL_CON_30_ATI 0x895F +#define GL_CON_31_ATI 0x8960 +#define GL_MOV_ATI 0x8961 +#define GL_ADD_ATI 0x8963 +#define GL_MUL_ATI 0x8964 +#define GL_SUB_ATI 0x8965 +#define GL_DOT3_ATI 0x8966 +#define GL_DOT4_ATI 0x8967 +#define GL_MAD_ATI 0x8968 +#define GL_LERP_ATI 0x8969 +#define GL_CND_ATI 0x896A +#define GL_CND0_ATI 0x896B +#define GL_DOT2_ADD_ATI 0x896C +#define GL_SECONDARY_INTERPOLATOR_ATI 0x896D +#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E +#define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F +#define GL_NUM_PASSES_ATI 0x8970 +#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 +#define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 +#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 +#define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 +#define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 +#define GL_SWIZZLE_STR_ATI 0x8976 +#define GL_SWIZZLE_STQ_ATI 0x8977 +#define GL_SWIZZLE_STR_DR_ATI 0x8978 +#define GL_SWIZZLE_STQ_DQ_ATI 0x8979 +#define GL_SWIZZLE_STRQ_ATI 0x897A +#define GL_SWIZZLE_STRQ_DQ_ATI 0x897B +#define GL_RED_BIT_ATI 0x00000001 +#define GL_GREEN_BIT_ATI 0x00000002 +#define GL_BLUE_BIT_ATI 0x00000004 +#define GL_2X_BIT_ATI 0x00000001 +#define GL_4X_BIT_ATI 0x00000002 +#define GL_8X_BIT_ATI 0x00000004 +#define GL_HALF_BIT_ATI 0x00000008 +#define GL_QUARTER_BIT_ATI 0x00000010 +#define GL_EIGHTH_BIT_ATI 0x00000020 +#define GL_SATURATE_BIT_ATI 0x00000040 +#define GL_COMP_BIT_ATI 0x00000002 +#define GL_NEGATE_BIT_ATI 0x00000004 +#define GL_BIAS_BIT_ATI 0x00000008 +typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range); +typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id); +typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void); +typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void); +typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle); +typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint range); +GLAPI void APIENTRY glBindFragmentShaderATI (GLuint id); +GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint id); +GLAPI void APIENTRY glBeginFragmentShaderATI (void); +GLAPI void APIENTRY glEndFragmentShaderATI (void); +GLAPI void APIENTRY glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle); +GLAPI void APIENTRY glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle); +GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value); +#endif +#endif /* GL_ATI_fragment_shader */ + +#ifndef GL_ATI_map_object_buffer +#define GL_ATI_map_object_buffer 1 +typedef void *(APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void *APIENTRY glMapObjectBufferATI (GLuint buffer); +GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint buffer); +#endif +#endif /* GL_ATI_map_object_buffer */ + +#ifndef GL_ATI_meminfo +#define GL_ATI_meminfo 1 +#define GL_VBO_FREE_MEMORY_ATI 0x87FB +#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC +#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD +#endif /* GL_ATI_meminfo */ + +#ifndef GL_ATI_pixel_format_float +#define GL_ATI_pixel_format_float 1 +#define GL_RGBA_FLOAT_MODE_ATI 0x8820 +#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 +#endif /* GL_ATI_pixel_format_float */ + +#ifndef GL_ATI_pn_triangles +#define GL_ATI_pn_triangles 1 +#define GL_PN_TRIANGLES_ATI 0x87F0 +#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 +#define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 +#define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 +#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 +#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 +#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 +#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 +#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 +typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPNTrianglesiATI (GLenum pname, GLint param); +GLAPI void APIENTRY glPNTrianglesfATI (GLenum pname, GLfloat param); +#endif +#endif /* GL_ATI_pn_triangles */ + +#ifndef GL_ATI_separate_stencil +#define GL_ATI_separate_stencil 1 +#define GL_STENCIL_BACK_FUNC_ATI 0x8800 +#define GL_STENCIL_BACK_FAIL_ATI 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); +#endif +#endif /* GL_ATI_separate_stencil */ + +#ifndef GL_ATI_text_fragment_shader +#define GL_ATI_text_fragment_shader 1 +#define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 +#endif /* GL_ATI_text_fragment_shader */ + +#ifndef GL_ATI_texture_env_combine3 +#define GL_ATI_texture_env_combine3 1 +#define GL_MODULATE_ADD_ATI 0x8744 +#define GL_MODULATE_SIGNED_ADD_ATI 0x8745 +#define GL_MODULATE_SUBTRACT_ATI 0x8746 +#endif /* GL_ATI_texture_env_combine3 */ + +#ifndef GL_ATI_texture_float +#define GL_ATI_texture_float 1 +#define GL_RGBA_FLOAT32_ATI 0x8814 +#define GL_RGB_FLOAT32_ATI 0x8815 +#define GL_ALPHA_FLOAT32_ATI 0x8816 +#define GL_INTENSITY_FLOAT32_ATI 0x8817 +#define GL_LUMINANCE_FLOAT32_ATI 0x8818 +#define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 +#define GL_RGBA_FLOAT16_ATI 0x881A +#define GL_RGB_FLOAT16_ATI 0x881B +#define GL_ALPHA_FLOAT16_ATI 0x881C +#define GL_INTENSITY_FLOAT16_ATI 0x881D +#define GL_LUMINANCE_FLOAT16_ATI 0x881E +#define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F +#endif /* GL_ATI_texture_float */ + +#ifndef GL_ATI_texture_mirror_once +#define GL_ATI_texture_mirror_once 1 +#define GL_MIRROR_CLAMP_ATI 0x8742 +#define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 +#endif /* GL_ATI_texture_mirror_once */ + +#ifndef GL_ATI_vertex_array_object +#define GL_ATI_vertex_array_object 1 +#define GL_STATIC_ATI 0x8760 +#define GL_DYNAMIC_ATI 0x8761 +#define GL_PRESERVE_ATI 0x8762 +#define GL_DISCARD_ATI 0x8763 +#define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 +#define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 +#define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 +#define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 +typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const void *pointer, GLenum usage); +typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve); +typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const void *pointer, GLenum usage); +GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer); +GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve); +GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer); +GLAPI void APIENTRY glArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params); +GLAPI void APIENTRY glVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params); +#endif +#endif /* GL_ATI_vertex_array_object */ + +#ifndef GL_ATI_vertex_attrib_array_object +#define GL_ATI_vertex_attrib_array_object 1 +typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); +GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params); +#endif +#endif /* GL_ATI_vertex_attrib_array_object */ + +#ifndef GL_ATI_vertex_streams +#define GL_ATI_vertex_streams 1 +#define GL_MAX_VERTEX_STREAMS_ATI 0x876B +#define GL_VERTEX_STREAM0_ATI 0x876C +#define GL_VERTEX_STREAM1_ATI 0x876D +#define GL_VERTEX_STREAM2_ATI 0x876E +#define GL_VERTEX_STREAM3_ATI 0x876F +#define GL_VERTEX_STREAM4_ATI 0x8770 +#define GL_VERTEX_STREAM5_ATI 0x8771 +#define GL_VERTEX_STREAM6_ATI 0x8772 +#define GL_VERTEX_STREAM7_ATI 0x8773 +#define GL_VERTEX_SOURCE_ATI 0x8774 +typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream); +typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexStream1sATI (GLenum stream, GLshort x); +GLAPI void APIENTRY glVertexStream1svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream1iATI (GLenum stream, GLint x); +GLAPI void APIENTRY glVertexStream1ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream1fATI (GLenum stream, GLfloat x); +GLAPI void APIENTRY glVertexStream1fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream1dATI (GLenum stream, GLdouble x); +GLAPI void APIENTRY glVertexStream1dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glVertexStream2sATI (GLenum stream, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexStream2svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream2iATI (GLenum stream, GLint x, GLint y); +GLAPI void APIENTRY glVertexStream2ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexStream2fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexStream2dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexStream3svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexStream3ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexStream3fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexStream3dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexStream4svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexStream4ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexStream4fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexStream4dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); +GLAPI void APIENTRY glNormalStream3bvATI (GLenum stream, const GLbyte *coords); +GLAPI void APIENTRY glNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz); +GLAPI void APIENTRY glNormalStream3svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz); +GLAPI void APIENTRY glNormalStream3ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); +GLAPI void APIENTRY glNormalStream3fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); +GLAPI void APIENTRY glNormalStream3dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum stream); +GLAPI void APIENTRY glVertexBlendEnviATI (GLenum pname, GLint param); +GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum pname, GLfloat param); +#endif +#endif /* GL_ATI_vertex_streams */ + +#ifndef GL_EXT_422_pixels +#define GL_EXT_422_pixels 1 +#define GL_422_EXT 0x80CC +#define GL_422_REV_EXT 0x80CD +#define GL_422_AVERAGE_EXT 0x80CE +#define GL_422_REV_AVERAGE_EXT 0x80CF +#endif /* GL_EXT_422_pixels */ + +#ifndef GL_EXT_abgr +#define GL_EXT_abgr 1 +#define GL_ABGR_EXT 0x8000 +#endif /* GL_EXT_abgr */ + +#ifndef GL_EXT_bgra +#define GL_EXT_bgra 1 +#define GL_BGR_EXT 0x80E0 +#define GL_BGRA_EXT 0x80E1 +#endif /* GL_EXT_bgra */ + +#ifndef GL_EXT_bindable_uniform +#define GL_EXT_bindable_uniform 1 +#define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 +#define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 +#define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 +#define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED +#define GL_UNIFORM_BUFFER_EXT 0x8DEE +#define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF +typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer); +typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location); +typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniformBufferEXT (GLuint program, GLint location, GLuint buffer); +GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint program, GLint location); +GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint program, GLint location); +#endif +#endif /* GL_EXT_bindable_uniform */ + +#ifndef GL_EXT_blend_color +#define GL_EXT_blend_color 1 +#define GL_CONSTANT_COLOR_EXT 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 +#define GL_CONSTANT_ALPHA_EXT 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 +#define GL_BLEND_COLOR_EXT 0x8005 +typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendColorEXT (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +#endif +#endif /* GL_EXT_blend_color */ + +#ifndef GL_EXT_blend_equation_separate +#define GL_EXT_blend_equation_separate 1 +#define GL_BLEND_EQUATION_RGB_EXT 0x8009 +#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha); +#endif +#endif /* GL_EXT_blend_equation_separate */ + +#ifndef GL_EXT_blend_func_separate +#define GL_EXT_blend_func_separate 1 +#define GL_BLEND_DST_RGB_EXT 0x80C8 +#define GL_BLEND_SRC_RGB_EXT 0x80C9 +#define GL_BLEND_DST_ALPHA_EXT 0x80CA +#define GL_BLEND_SRC_ALPHA_EXT 0x80CB +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#endif +#endif /* GL_EXT_blend_func_separate */ + +#ifndef GL_EXT_blend_logic_op +#define GL_EXT_blend_logic_op 1 +#endif /* GL_EXT_blend_logic_op */ + +#ifndef GL_EXT_blend_minmax +#define GL_EXT_blend_minmax 1 +#define GL_MIN_EXT 0x8007 +#define GL_MAX_EXT 0x8008 +#define GL_FUNC_ADD_EXT 0x8006 +#define GL_BLEND_EQUATION_EXT 0x8009 +typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationEXT (GLenum mode); +#endif +#endif /* GL_EXT_blend_minmax */ + +#ifndef GL_EXT_blend_subtract +#define GL_EXT_blend_subtract 1 +#define GL_FUNC_SUBTRACT_EXT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B +#endif /* GL_EXT_blend_subtract */ + +#ifndef GL_EXT_clip_volume_hint +#define GL_EXT_clip_volume_hint 1 +#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 +#endif /* GL_EXT_clip_volume_hint */ + +#ifndef GL_EXT_cmyka +#define GL_EXT_cmyka 1 +#define GL_CMYK_EXT 0x800C +#define GL_CMYKA_EXT 0x800D +#define GL_PACK_CMYK_HINT_EXT 0x800E +#define GL_UNPACK_CMYK_HINT_EXT 0x800F +#endif /* GL_EXT_cmyka */ + +#ifndef GL_EXT_color_subtable +#define GL_EXT_color_subtable 1 +typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +#endif +#endif /* GL_EXT_color_subtable */ + +#ifndef GL_EXT_compiled_vertex_array +#define GL_EXT_compiled_vertex_array 1 +#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 +#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 +typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count); +GLAPI void APIENTRY glUnlockArraysEXT (void); +#endif +#endif /* GL_EXT_compiled_vertex_array */ + +#ifndef GL_EXT_convolution +#define GL_EXT_convolution 1 +#define GL_CONVOLUTION_1D_EXT 0x8010 +#define GL_CONVOLUTION_2D_EXT 0x8011 +#define GL_SEPARABLE_2D_EXT 0x8012 +#define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 +#define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 +#define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 +#define GL_REDUCE_EXT 0x8016 +#define GL_CONVOLUTION_FORMAT_EXT 0x8017 +#define GL_CONVOLUTION_WIDTH_EXT 0x8018 +#define GL_CONVOLUTION_HEIGHT_EXT 0x8019 +#define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A +#define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B +#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C +#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D +#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E +#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F +#define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 +#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 +#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 +#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *image); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); +GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params); +GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params); +GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, void *image); +GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); +#endif +#endif /* GL_EXT_convolution */ + +#ifndef GL_EXT_coordinate_frame +#define GL_EXT_coordinate_frame 1 +#define GL_TANGENT_ARRAY_EXT 0x8439 +#define GL_BINORMAL_ARRAY_EXT 0x843A +#define GL_CURRENT_TANGENT_EXT 0x843B +#define GL_CURRENT_BINORMAL_EXT 0x843C +#define GL_TANGENT_ARRAY_TYPE_EXT 0x843E +#define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F +#define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 +#define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 +#define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 +#define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 +#define GL_MAP1_TANGENT_EXT 0x8444 +#define GL_MAP2_TANGENT_EXT 0x8445 +#define GL_MAP1_BINORMAL_EXT 0x8446 +#define GL_MAP2_BINORMAL_EXT 0x8447 +typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz); +typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz); +typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz); +typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz); +typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz); +typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz); +typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz); +typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz); +typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); +typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); +typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz); +GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v); +GLAPI void APIENTRY glTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz); +GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *v); +GLAPI void APIENTRY glTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz); +GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *v); +GLAPI void APIENTRY glTangent3iEXT (GLint tx, GLint ty, GLint tz); +GLAPI void APIENTRY glTangent3ivEXT (const GLint *v); +GLAPI void APIENTRY glTangent3sEXT (GLshort tx, GLshort ty, GLshort tz); +GLAPI void APIENTRY glTangent3svEXT (const GLshort *v); +GLAPI void APIENTRY glBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz); +GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *v); +GLAPI void APIENTRY glBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz); +GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *v); +GLAPI void APIENTRY glBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz); +GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *v); +GLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz); +GLAPI void APIENTRY glBinormal3ivEXT (const GLint *v); +GLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz); +GLAPI void APIENTRY glBinormal3svEXT (const GLshort *v); +GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const void *pointer); +#endif +#endif /* GL_EXT_coordinate_frame */ + +#ifndef GL_EXT_copy_texture +#define GL_EXT_copy_texture 1 +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif +#endif /* GL_EXT_copy_texture */ + +#ifndef GL_EXT_cull_vertex +#define GL_EXT_cull_vertex 1 +#define GL_CULL_VERTEX_EXT 0x81AA +#define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB +#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC +typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCullParameterdvEXT (GLenum pname, GLdouble *params); +GLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params); +#endif +#endif /* GL_EXT_cull_vertex */ + +#ifndef GL_EXT_debug_label +#define GL_EXT_debug_label 1 +#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F +#define GL_PROGRAM_OBJECT_EXT 0x8B40 +#define GL_SHADER_OBJECT_EXT 0x8B48 +#define GL_BUFFER_OBJECT_EXT 0x9151 +#define GL_QUERY_OBJECT_EXT 0x9153 +#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 +typedef void (APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); +#endif +#endif /* GL_EXT_debug_label */ + +#ifndef GL_EXT_debug_marker +#define GL_EXT_debug_marker 1 +typedef void (APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker); +typedef void (APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker); +typedef void (APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker); +GLAPI void APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker); +GLAPI void APIENTRY glPopGroupMarkerEXT (void); +#endif +#endif /* GL_EXT_debug_marker */ + +#ifndef GL_EXT_depth_bounds_test +#define GL_EXT_depth_bounds_test 1 +#define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 +#define GL_DEPTH_BOUNDS_EXT 0x8891 +typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDepthBoundsEXT (GLclampd zmin, GLclampd zmax); +#endif +#endif /* GL_EXT_depth_bounds_test */ + +#ifndef GL_EXT_direct_state_access +#define GL_EXT_direct_state_access 1 +#define GL_PROGRAM_MATRIX_EXT 0x8E2D +#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E +#define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F +typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); +typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); +typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data); +typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data); +typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, void **data); +typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); +typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, void *img); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, void *img); +typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); +typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, void **params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params); +typedef void (APIENTRYP PFNGLENABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, void *string); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target); +typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); +typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); +typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYINDEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYNORMALOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); +typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); +typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERVEXTPROC) (GLuint vaobj, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, void **param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param); +typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) (GLuint framebuffer, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC) (GLuint vaobj, GLuint index, GLuint divisor); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode); +GLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glMatrixPopEXT (GLenum mode); +GLAPI void APIENTRY glMatrixPushEXT (GLenum mode); +GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask); +GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask); +GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture); +GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); +GLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); +GLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); +GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params); +GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); +GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data); +GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data); +GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, void **data); +GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index); +GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index); +GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index); +GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data); +GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data); +GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, void *img); +GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, void *img); +GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); +GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI void *APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access); +GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer); +GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, void **params); +GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); +GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0); +GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0); +GLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0); +GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); +GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params); +GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); +GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params); +GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params); +GLAPI void APIENTRY glEnableClientStateiEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glDisableClientStateiEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glGetFloati_vEXT (GLenum pname, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetDoublei_vEXT (GLenum pname, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetPointeri_vEXT (GLenum pname, GLuint index, void **params); +GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); +GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params); +GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, void *string); +GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target); +GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target); +GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target); +GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode); +GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs); +GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode); +GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); +GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glVertexArrayVertexOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayEdgeFlagOffsetEXT (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayIndexOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayNormalOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayMultiTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayFogCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArraySecondaryColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayVertexAttribOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayVertexAttribIOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glEnableVertexArrayEXT (GLuint vaobj, GLenum array); +GLAPI void APIENTRY glDisableVertexArrayEXT (GLuint vaobj, GLenum array); +GLAPI void APIENTRY glEnableVertexArrayAttribEXT (GLuint vaobj, GLuint index); +GLAPI void APIENTRY glDisableVertexArrayAttribEXT (GLuint vaobj, GLuint index); +GLAPI void APIENTRY glGetVertexArrayIntegervEXT (GLuint vaobj, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetVertexArrayPointervEXT (GLuint vaobj, GLenum pname, void **param); +GLAPI void APIENTRY glGetVertexArrayIntegeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetVertexArrayPointeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, void **param); +GLAPI void *APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glNamedBufferStorageEXT (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); +GLAPI void APIENTRY glClearNamedBufferDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glNamedFramebufferParameteriEXT (GLuint framebuffer, GLenum pname, GLint param); +GLAPI void APIENTRY glGetNamedFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x); +GLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y); +GLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glTextureBufferRangeEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glTextureStorage2DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureStorage3DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glVertexArrayBindVertexBufferEXT (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexArrayVertexAttribFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribIFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT (GLuint vaobj, GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glTexturePageCommitmentEXT (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); +GLAPI void APIENTRY glVertexArrayVertexAttribDivisorEXT (GLuint vaobj, GLuint index, GLuint divisor); +#endif +#endif /* GL_EXT_direct_state_access */ + +#ifndef GL_EXT_draw_buffers2 +#define GL_EXT_draw_buffers2 1 +typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +#endif +#endif /* GL_EXT_draw_buffers2 */ + +#ifndef GL_EXT_draw_instanced +#define GL_EXT_draw_instanced 1 +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount); +GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +#endif +#endif /* GL_EXT_draw_instanced */ + +#ifndef GL_EXT_draw_range_elements +#define GL_EXT_draw_range_elements 1 +#define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 +#define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +#endif +#endif /* GL_EXT_draw_range_elements */ + +#ifndef GL_EXT_fog_coord +#define GL_EXT_fog_coord 1 +#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 +#define GL_FOG_COORDINATE_EXT 0x8451 +#define GL_FRAGMENT_DEPTH_EXT 0x8452 +#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 +#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 +typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); +typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); +typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); +typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFogCoordfEXT (GLfloat coord); +GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord); +GLAPI void APIENTRY glFogCoorddEXT (GLdouble coord); +GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord); +GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const void *pointer); +#endif +#endif /* GL_EXT_fog_coord */ + +#ifndef GL_EXT_framebuffer_blit +#define GL_EXT_framebuffer_blit 1 +#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 +#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 +#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#endif +#endif /* GL_EXT_framebuffer_blit */ + +#ifndef GL_EXT_framebuffer_multisample +#define GL_EXT_framebuffer_multisample 1 +#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#define GL_MAX_SAMPLES_EXT 0x8D57 +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +#endif +#endif /* GL_EXT_framebuffer_multisample */ + +#ifndef GL_EXT_framebuffer_multisample_blit_scaled +#define GL_EXT_framebuffer_multisample_blit_scaled 1 +#define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA +#define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB +#endif /* GL_EXT_framebuffer_multisample_blit_scaled */ + +#ifndef GL_EXT_framebuffer_object +#define GL_EXT_framebuffer_object 1 +#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 +#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 +#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF +#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 +#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 +#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 +#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 +#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 +#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 +#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 +#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 +#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 +#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 +#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA +#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB +#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC +#define GL_COLOR_ATTACHMENT13_EXT 0x8CED +#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE +#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF +#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 +#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 +#define GL_FRAMEBUFFER_EXT 0x8D40 +#define GL_RENDERBUFFER_EXT 0x8D41 +#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 +#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 +#define GL_STENCIL_INDEX1_EXT 0x8D46 +#define GL_STENCIL_INDEX4_EXT 0x8D47 +#define GL_STENCIL_INDEX8_EXT 0x8D48 +#define GL_STENCIL_INDEX16_EXT 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); +typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint renderbuffer); +GLAPI void APIENTRY glBindRenderbufferEXT (GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers); +GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers); +GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint framebuffer); +GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer); +GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers); +GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers); +GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum target); +GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glGenerateMipmapEXT (GLenum target); +#endif +#endif /* GL_EXT_framebuffer_object */ + +#ifndef GL_EXT_framebuffer_sRGB +#define GL_EXT_framebuffer_sRGB 1 +#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 +#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA +#endif /* GL_EXT_framebuffer_sRGB */ + +#ifndef GL_EXT_geometry_shader4 +#define GL_EXT_geometry_shader4 1 +#define GL_GEOMETRY_SHADER_EXT 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA +#define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB +#define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 +#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD +#define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE +#define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 +#define GL_LINES_ADJACENCY_EXT 0x000A +#define GL_LINE_STRIP_ADJACENCY_EXT 0x000B +#define GL_TRIANGLES_ADJACENCY_EXT 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 +#define GL_PROGRAM_POINT_SIZE_EXT 0x8642 +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value); +#endif +#endif /* GL_EXT_geometry_shader4 */ + +#ifndef GL_EXT_gpu_program_parameters +#define GL_EXT_gpu_program_parameters 1 +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +#endif +#endif /* GL_EXT_gpu_program_parameters */ + +#ifndef GL_EXT_gpu_shader4 +#define GL_EXT_gpu_shader4 1 +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD +#define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 +#define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 +#define GL_SAMPLER_BUFFER_EXT 0x8DC2 +#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 +#define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 +#define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 +#define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 +#define GL_INT_SAMPLER_1D_EXT 0x8DC9 +#define GL_INT_SAMPLER_2D_EXT 0x8DCA +#define GL_INT_SAMPLER_3D_EXT 0x8DCB +#define GL_INT_SAMPLER_CUBE_EXT 0x8DCC +#define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD +#define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF +#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 +#define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905 +typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params); +GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint program, const GLchar *name); +GLAPI void APIENTRY glUniform1uiEXT (GLint location, GLuint v0); +GLAPI void APIENTRY glUniform2uiEXT (GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glUniform3uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glUniform4uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value); +#endif +#endif /* GL_EXT_gpu_shader4 */ + +#ifndef GL_EXT_histogram +#define GL_EXT_histogram 1 +#define GL_HISTOGRAM_EXT 0x8024 +#define GL_PROXY_HISTOGRAM_EXT 0x8025 +#define GL_HISTOGRAM_WIDTH_EXT 0x8026 +#define GL_HISTOGRAM_FORMAT_EXT 0x8027 +#define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 +#define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 +#define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A +#define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B +#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C +#define GL_HISTOGRAM_SINK_EXT 0x802D +#define GL_MINMAX_EXT 0x802E +#define GL_MINMAX_FORMAT_EXT 0x802F +#define GL_MINMAX_SINK_EXT 0x8030 +#define GL_TABLE_TOO_LARGE_EXT 0x8031 +typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); +typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); +GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glResetHistogramEXT (GLenum target); +GLAPI void APIENTRY glResetMinmaxEXT (GLenum target); +#endif +#endif /* GL_EXT_histogram */ + +#ifndef GL_EXT_index_array_formats +#define GL_EXT_index_array_formats 1 +#define GL_IUI_V2F_EXT 0x81AD +#define GL_IUI_V3F_EXT 0x81AE +#define GL_IUI_N3F_V2F_EXT 0x81AF +#define GL_IUI_N3F_V3F_EXT 0x81B0 +#define GL_T2F_IUI_V2F_EXT 0x81B1 +#define GL_T2F_IUI_V3F_EXT 0x81B2 +#define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 +#define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 +#endif /* GL_EXT_index_array_formats */ + +#ifndef GL_EXT_index_func +#define GL_EXT_index_func 1 +#define GL_INDEX_TEST_EXT 0x81B5 +#define GL_INDEX_TEST_FUNC_EXT 0x81B6 +#define GL_INDEX_TEST_REF_EXT 0x81B7 +typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIndexFuncEXT (GLenum func, GLclampf ref); +#endif +#endif /* GL_EXT_index_func */ + +#ifndef GL_EXT_index_material +#define GL_EXT_index_material 1 +#define GL_INDEX_MATERIAL_EXT 0x81B8 +#define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 +#define GL_INDEX_MATERIAL_FACE_EXT 0x81BA +typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIndexMaterialEXT (GLenum face, GLenum mode); +#endif +#endif /* GL_EXT_index_material */ + +#ifndef GL_EXT_index_texture +#define GL_EXT_index_texture 1 +#endif /* GL_EXT_index_texture */ + +#ifndef GL_EXT_light_texture +#define GL_EXT_light_texture 1 +#define GL_FRAGMENT_MATERIAL_EXT 0x8349 +#define GL_FRAGMENT_NORMAL_EXT 0x834A +#define GL_FRAGMENT_COLOR_EXT 0x834C +#define GL_ATTENUATION_EXT 0x834D +#define GL_SHADOW_ATTENUATION_EXT 0x834E +#define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F +#define GL_TEXTURE_LIGHT_EXT 0x8350 +#define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 +#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 +typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname); +typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glApplyTextureEXT (GLenum mode); +GLAPI void APIENTRY glTextureLightEXT (GLenum pname); +GLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode); +#endif +#endif /* GL_EXT_light_texture */ + +#ifndef GL_EXT_misc_attribute +#define GL_EXT_misc_attribute 1 +#endif /* GL_EXT_misc_attribute */ + +#ifndef GL_EXT_multi_draw_arrays +#define GL_EXT_multi_draw_arrays 1 +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); +#endif +#endif /* GL_EXT_multi_draw_arrays */ + +#ifndef GL_EXT_multisample +#define GL_EXT_multisample 1 +#define GL_MULTISAMPLE_EXT 0x809D +#define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F +#define GL_SAMPLE_MASK_EXT 0x80A0 +#define GL_1PASS_EXT 0x80A1 +#define GL_2PASS_0_EXT 0x80A2 +#define GL_2PASS_1_EXT 0x80A3 +#define GL_4PASS_0_EXT 0x80A4 +#define GL_4PASS_1_EXT 0x80A5 +#define GL_4PASS_2_EXT 0x80A6 +#define GL_4PASS_3_EXT 0x80A7 +#define GL_SAMPLE_BUFFERS_EXT 0x80A8 +#define GL_SAMPLES_EXT 0x80A9 +#define GL_SAMPLE_MASK_VALUE_EXT 0x80AA +#define GL_SAMPLE_MASK_INVERT_EXT 0x80AB +#define GL_SAMPLE_PATTERN_EXT 0x80AC +#define GL_MULTISAMPLE_BIT_EXT 0x20000000 +typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert); +typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleMaskEXT (GLclampf value, GLboolean invert); +GLAPI void APIENTRY glSamplePatternEXT (GLenum pattern); +#endif +#endif /* GL_EXT_multisample */ + +#ifndef GL_EXT_packed_depth_stencil +#define GL_EXT_packed_depth_stencil 1 +#define GL_DEPTH_STENCIL_EXT 0x84F9 +#define GL_UNSIGNED_INT_24_8_EXT 0x84FA +#define GL_DEPTH24_STENCIL8_EXT 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 +#endif /* GL_EXT_packed_depth_stencil */ + +#ifndef GL_EXT_packed_float +#define GL_EXT_packed_float 1 +#define GL_R11F_G11F_B10F_EXT 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B +#define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C +#endif /* GL_EXT_packed_float */ + +#ifndef GL_EXT_packed_pixels +#define GL_EXT_packed_pixels 1 +#define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 +#endif /* GL_EXT_packed_pixels */ + +#ifndef GL_EXT_paletted_texture +#define GL_EXT_paletted_texture 1 +#define GL_COLOR_INDEX1_EXT 0x80E2 +#define GL_COLOR_INDEX2_EXT 0x80E3 +#define GL_COLOR_INDEX4_EXT 0x80E4 +#define GL_COLOR_INDEX8_EXT 0x80E5 +#define GL_COLOR_INDEX12_EXT 0x80E6 +#define GL_COLOR_INDEX16_EXT 0x80E7 +#define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED +typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, void *data); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table); +GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, void *data); +GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +#endif +#endif /* GL_EXT_paletted_texture */ + +#ifndef GL_EXT_pixel_buffer_object +#define GL_EXT_pixel_buffer_object 1 +#define GL_PIXEL_PACK_BUFFER_EXT 0x88EB +#define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF +#endif /* GL_EXT_pixel_buffer_object */ + +#ifndef GL_EXT_pixel_transform +#define GL_EXT_pixel_transform 1 +#define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 +#define GL_PIXEL_MAG_FILTER_EXT 0x8331 +#define GL_PIXEL_MIN_FILTER_EXT 0x8332 +#define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 +#define GL_CUBIC_EXT 0x8334 +#define GL_AVERAGE_EXT 0x8335 +#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 +#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 +#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetPixelTransformParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetPixelTransformParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +#endif +#endif /* GL_EXT_pixel_transform */ + +#ifndef GL_EXT_pixel_transform_color_table +#define GL_EXT_pixel_transform_color_table 1 +#endif /* GL_EXT_pixel_transform_color_table */ + +#ifndef GL_EXT_point_parameters +#define GL_EXT_point_parameters 1 +#define GL_POINT_SIZE_MIN_EXT 0x8126 +#define GL_POINT_SIZE_MAX_EXT 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 +#define GL_DISTANCE_ATTENUATION_EXT 0x8129 +typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfEXT (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfvEXT (GLenum pname, const GLfloat *params); +#endif +#endif /* GL_EXT_point_parameters */ + +#ifndef GL_EXT_polygon_offset +#define GL_EXT_polygon_offset 1 +#define GL_POLYGON_OFFSET_EXT 0x8037 +#define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 +#define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 +typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat factor, GLfloat bias); +#endif +#endif /* GL_EXT_polygon_offset */ + +#ifndef GL_EXT_polygon_offset_clamp +#define GL_EXT_polygon_offset_clamp 1 +#define GL_POLYGON_OFFSET_CLAMP_EXT 0x8E1B +typedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPolygonOffsetClampEXT (GLfloat factor, GLfloat units, GLfloat clamp); +#endif +#endif /* GL_EXT_polygon_offset_clamp */ + +#ifndef GL_EXT_post_depth_coverage +#define GL_EXT_post_depth_coverage 1 +#endif /* GL_EXT_post_depth_coverage */ + +#ifndef GL_EXT_provoking_vertex +#define GL_EXT_provoking_vertex 1 +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D +#define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E +#define GL_PROVOKING_VERTEX_EXT 0x8E4F +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProvokingVertexEXT (GLenum mode); +#endif +#endif /* GL_EXT_provoking_vertex */ + +#ifndef GL_EXT_raster_multisample +#define GL_EXT_raster_multisample 1 +#define GL_RASTER_MULTISAMPLE_EXT 0x9327 +#define GL_RASTER_SAMPLES_EXT 0x9328 +#define GL_MAX_RASTER_SAMPLES_EXT 0x9329 +#define GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A +#define GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B +#define GL_EFFECTIVE_RASTER_SAMPLES_EXT 0x932C +typedef void (APIENTRYP PFNGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glRasterSamplesEXT (GLuint samples, GLboolean fixedsamplelocations); +#endif +#endif /* GL_EXT_raster_multisample */ + +#ifndef GL_EXT_rescale_normal +#define GL_EXT_rescale_normal 1 +#define GL_RESCALE_NORMAL_EXT 0x803A +#endif /* GL_EXT_rescale_normal */ + +#ifndef GL_EXT_secondary_color +#define GL_EXT_secondary_color 1 +#define GL_COLOR_SUM_EXT 0x8458 +#define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D +#define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue); +GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v); +GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue); +GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *v); +GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue); +GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *v); +GLAPI void APIENTRY glSecondaryColor3iEXT (GLint red, GLint green, GLint blue); +GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *v); +GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue); +GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *v); +GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue); +GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *v); +GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue); +GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v); +GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue); +GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v); +GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer); +#endif +#endif /* GL_EXT_secondary_color */ + +#ifndef GL_EXT_separate_shader_objects +#define GL_EXT_separate_shader_objects 1 +#define GL_ACTIVE_PROGRAM_EXT 0x8B8D +typedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program); +typedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program); +GLAPI void APIENTRY glActiveProgramEXT (GLuint program); +GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string); +#endif +#endif /* GL_EXT_separate_shader_objects */ + +#ifndef GL_EXT_separate_specular_color +#define GL_EXT_separate_specular_color 1 +#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 +#define GL_SINGLE_COLOR_EXT 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA +#endif /* GL_EXT_separate_specular_color */ + +#ifndef GL_EXT_shader_image_load_formatted +#define GL_EXT_shader_image_load_formatted 1 +#endif /* GL_EXT_shader_image_load_formatted */ + +#ifndef GL_EXT_shader_image_load_store +#define GL_EXT_shader_image_load_store 1 +#define GL_MAX_IMAGE_UNITS_EXT 0x8F38 +#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39 +#define GL_IMAGE_BINDING_NAME_EXT 0x8F3A +#define GL_IMAGE_BINDING_LEVEL_EXT 0x8F3B +#define GL_IMAGE_BINDING_LAYERED_EXT 0x8F3C +#define GL_IMAGE_BINDING_LAYER_EXT 0x8F3D +#define GL_IMAGE_BINDING_ACCESS_EXT 0x8F3E +#define GL_IMAGE_1D_EXT 0x904C +#define GL_IMAGE_2D_EXT 0x904D +#define GL_IMAGE_3D_EXT 0x904E +#define GL_IMAGE_2D_RECT_EXT 0x904F +#define GL_IMAGE_CUBE_EXT 0x9050 +#define GL_IMAGE_BUFFER_EXT 0x9051 +#define GL_IMAGE_1D_ARRAY_EXT 0x9052 +#define GL_IMAGE_2D_ARRAY_EXT 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE_EXT 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056 +#define GL_INT_IMAGE_1D_EXT 0x9057 +#define GL_INT_IMAGE_2D_EXT 0x9058 +#define GL_INT_IMAGE_3D_EXT 0x9059 +#define GL_INT_IMAGE_2D_RECT_EXT 0x905A +#define GL_INT_IMAGE_CUBE_EXT 0x905B +#define GL_INT_IMAGE_BUFFER_EXT 0x905C +#define GL_INT_IMAGE_1D_ARRAY_EXT 0x905D +#define GL_INT_IMAGE_2D_ARRAY_EXT 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE_EXT 0x9060 +#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061 +#define GL_UNSIGNED_INT_IMAGE_1D_EXT 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D_EXT 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D_EXT 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE_EXT 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C +#define GL_MAX_IMAGE_SAMPLES_EXT 0x906D +#define GL_IMAGE_BINDING_FORMAT_EXT 0x906E +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001 +#define GL_ELEMENT_ARRAY_BARRIER_BIT_EXT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT_EXT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT_EXT 0x00000008 +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020 +#define GL_COMMAND_BARRIER_BIT_EXT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT_EXT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT_EXT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT_EXT 0x00000400 +#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800 +#define GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000 +#define GL_ALL_BARRIER_BITS_EXT 0xFFFFFFFF +typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREEXTPROC) (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); +typedef void (APIENTRYP PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindImageTextureEXT (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); +GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers); +#endif +#endif /* GL_EXT_shader_image_load_store */ + +#ifndef GL_EXT_shader_integer_mix +#define GL_EXT_shader_integer_mix 1 +#endif /* GL_EXT_shader_integer_mix */ + +#ifndef GL_EXT_shadow_funcs +#define GL_EXT_shadow_funcs 1 +#endif /* GL_EXT_shadow_funcs */ + +#ifndef GL_EXT_shared_texture_palette +#define GL_EXT_shared_texture_palette 1 +#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB +#endif /* GL_EXT_shared_texture_palette */ + +#ifndef GL_EXT_sparse_texture2 +#define GL_EXT_sparse_texture2 1 +#endif /* GL_EXT_sparse_texture2 */ + +#ifndef GL_EXT_stencil_clear_tag +#define GL_EXT_stencil_clear_tag 1 +#define GL_STENCIL_TAG_BITS_EXT 0x88F2 +#define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 +typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStencilClearTagEXT (GLsizei stencilTagBits, GLuint stencilClearTag); +#endif +#endif /* GL_EXT_stencil_clear_tag */ + +#ifndef GL_EXT_stencil_two_side +#define GL_EXT_stencil_two_side 1 +#define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 +#define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 +typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face); +#endif +#endif /* GL_EXT_stencil_two_side */ + +#ifndef GL_EXT_stencil_wrap +#define GL_EXT_stencil_wrap 1 +#define GL_INCR_WRAP_EXT 0x8507 +#define GL_DECR_WRAP_EXT 0x8508 +#endif /* GL_EXT_stencil_wrap */ + +#ifndef GL_EXT_subtexture +#define GL_EXT_subtexture 1 +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +#endif +#endif /* GL_EXT_subtexture */ + +#ifndef GL_EXT_texture +#define GL_EXT_texture 1 +#define GL_ALPHA4_EXT 0x803B +#define GL_ALPHA8_EXT 0x803C +#define GL_ALPHA12_EXT 0x803D +#define GL_ALPHA16_EXT 0x803E +#define GL_LUMINANCE4_EXT 0x803F +#define GL_LUMINANCE8_EXT 0x8040 +#define GL_LUMINANCE12_EXT 0x8041 +#define GL_LUMINANCE16_EXT 0x8042 +#define GL_LUMINANCE4_ALPHA4_EXT 0x8043 +#define GL_LUMINANCE6_ALPHA2_EXT 0x8044 +#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 +#define GL_LUMINANCE12_ALPHA4_EXT 0x8046 +#define GL_LUMINANCE12_ALPHA12_EXT 0x8047 +#define GL_LUMINANCE16_ALPHA16_EXT 0x8048 +#define GL_INTENSITY_EXT 0x8049 +#define GL_INTENSITY4_EXT 0x804A +#define GL_INTENSITY8_EXT 0x804B +#define GL_INTENSITY12_EXT 0x804C +#define GL_INTENSITY16_EXT 0x804D +#define GL_RGB2_EXT 0x804E +#define GL_RGB4_EXT 0x804F +#define GL_RGB5_EXT 0x8050 +#define GL_RGB8_EXT 0x8051 +#define GL_RGB10_EXT 0x8052 +#define GL_RGB12_EXT 0x8053 +#define GL_RGB16_EXT 0x8054 +#define GL_RGBA2_EXT 0x8055 +#define GL_RGBA4_EXT 0x8056 +#define GL_RGB5_A1_EXT 0x8057 +#define GL_RGBA8_EXT 0x8058 +#define GL_RGB10_A2_EXT 0x8059 +#define GL_RGBA12_EXT 0x805A +#define GL_RGBA16_EXT 0x805B +#define GL_TEXTURE_RED_SIZE_EXT 0x805C +#define GL_TEXTURE_GREEN_SIZE_EXT 0x805D +#define GL_TEXTURE_BLUE_SIZE_EXT 0x805E +#define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F +#define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 +#define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 +#define GL_REPLACE_EXT 0x8062 +#define GL_PROXY_TEXTURE_1D_EXT 0x8063 +#define GL_PROXY_TEXTURE_2D_EXT 0x8064 +#define GL_TEXTURE_TOO_LARGE_EXT 0x8065 +#endif /* GL_EXT_texture */ + +#ifndef GL_EXT_texture3D +#define GL_EXT_texture3D 1 +#define GL_PACK_SKIP_IMAGES_EXT 0x806B +#define GL_PACK_IMAGE_HEIGHT_EXT 0x806C +#define GL_UNPACK_SKIP_IMAGES_EXT 0x806D +#define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E +#define GL_TEXTURE_3D_EXT 0x806F +#define GL_PROXY_TEXTURE_3D_EXT 0x8070 +#define GL_TEXTURE_DEPTH_EXT 0x8071 +#define GL_TEXTURE_WRAP_R_EXT 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 +typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +#endif +#endif /* GL_EXT_texture3D */ + +#ifndef GL_EXT_texture_array +#define GL_EXT_texture_array 1 +#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 +#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D +#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF +#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +#endif +#endif /* GL_EXT_texture_array */ + +#ifndef GL_EXT_texture_buffer_object +#define GL_EXT_texture_buffer_object 1 +#define GL_TEXTURE_BUFFER_EXT 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D +#define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E +typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer); +#endif +#endif /* GL_EXT_texture_buffer_object */ + +#ifndef GL_EXT_texture_compression_latc +#define GL_EXT_texture_compression_latc 1 +#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 +#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 +#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 +#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 +#endif /* GL_EXT_texture_compression_latc */ + +#ifndef GL_EXT_texture_compression_rgtc +#define GL_EXT_texture_compression_rgtc 1 +#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC +#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD +#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE +#endif /* GL_EXT_texture_compression_rgtc */ + +#ifndef GL_EXT_texture_compression_s3tc +#define GL_EXT_texture_compression_s3tc 1 +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif /* GL_EXT_texture_compression_s3tc */ + +#ifndef GL_EXT_texture_cube_map +#define GL_EXT_texture_cube_map 1 +#define GL_NORMAL_MAP_EXT 0x8511 +#define GL_REFLECTION_MAP_EXT 0x8512 +#define GL_TEXTURE_CUBE_MAP_EXT 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C +#endif /* GL_EXT_texture_cube_map */ + +#ifndef GL_EXT_texture_env_add +#define GL_EXT_texture_env_add 1 +#endif /* GL_EXT_texture_env_add */ + +#ifndef GL_EXT_texture_env_combine +#define GL_EXT_texture_env_combine 1 +#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_ADD_SIGNED_EXT 0x8574 +#define GL_INTERPOLATE_EXT 0x8575 +#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_SOURCE2_RGB_EXT 0x8582 +#define GL_SOURCE0_ALPHA_EXT 0x8588 +#define GL_SOURCE1_ALPHA_EXT 0x8589 +#define GL_SOURCE2_ALPHA_EXT 0x858A +#define GL_OPERAND0_RGB_EXT 0x8590 +#define GL_OPERAND1_RGB_EXT 0x8591 +#define GL_OPERAND2_RGB_EXT 0x8592 +#define GL_OPERAND0_ALPHA_EXT 0x8598 +#define GL_OPERAND1_ALPHA_EXT 0x8599 +#define GL_OPERAND2_ALPHA_EXT 0x859A +#endif /* GL_EXT_texture_env_combine */ + +#ifndef GL_EXT_texture_env_dot3 +#define GL_EXT_texture_env_dot3 1 +#define GL_DOT3_RGB_EXT 0x8740 +#define GL_DOT3_RGBA_EXT 0x8741 +#endif /* GL_EXT_texture_env_dot3 */ + +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_EXT_texture_filter_anisotropic 1 +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif /* GL_EXT_texture_filter_anisotropic */ + +#ifndef GL_EXT_texture_filter_minmax +#define GL_EXT_texture_filter_minmax 1 +#endif /* GL_EXT_texture_filter_minmax */ + +#ifndef GL_EXT_texture_integer +#define GL_EXT_texture_integer 1 +#define GL_RGBA32UI_EXT 0x8D70 +#define GL_RGB32UI_EXT 0x8D71 +#define GL_ALPHA32UI_EXT 0x8D72 +#define GL_INTENSITY32UI_EXT 0x8D73 +#define GL_LUMINANCE32UI_EXT 0x8D74 +#define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 +#define GL_RGBA16UI_EXT 0x8D76 +#define GL_RGB16UI_EXT 0x8D77 +#define GL_ALPHA16UI_EXT 0x8D78 +#define GL_INTENSITY16UI_EXT 0x8D79 +#define GL_LUMINANCE16UI_EXT 0x8D7A +#define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B +#define GL_RGBA8UI_EXT 0x8D7C +#define GL_RGB8UI_EXT 0x8D7D +#define GL_ALPHA8UI_EXT 0x8D7E +#define GL_INTENSITY8UI_EXT 0x8D7F +#define GL_LUMINANCE8UI_EXT 0x8D80 +#define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 +#define GL_RGBA32I_EXT 0x8D82 +#define GL_RGB32I_EXT 0x8D83 +#define GL_ALPHA32I_EXT 0x8D84 +#define GL_INTENSITY32I_EXT 0x8D85 +#define GL_LUMINANCE32I_EXT 0x8D86 +#define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 +#define GL_RGBA16I_EXT 0x8D88 +#define GL_RGB16I_EXT 0x8D89 +#define GL_ALPHA16I_EXT 0x8D8A +#define GL_INTENSITY16I_EXT 0x8D8B +#define GL_LUMINANCE16I_EXT 0x8D8C +#define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D +#define GL_RGBA8I_EXT 0x8D8E +#define GL_RGB8I_EXT 0x8D8F +#define GL_ALPHA8I_EXT 0x8D90 +#define GL_INTENSITY8I_EXT 0x8D91 +#define GL_LUMINANCE8I_EXT 0x8D92 +#define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 +#define GL_RED_INTEGER_EXT 0x8D94 +#define GL_GREEN_INTEGER_EXT 0x8D95 +#define GL_BLUE_INTEGER_EXT 0x8D96 +#define GL_ALPHA_INTEGER_EXT 0x8D97 +#define GL_RGB_INTEGER_EXT 0x8D98 +#define GL_RGBA_INTEGER_EXT 0x8D99 +#define GL_BGR_INTEGER_EXT 0x8D9A +#define GL_BGRA_INTEGER_EXT 0x8D9B +#define GL_LUMINANCE_INTEGER_EXT 0x8D9C +#define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D +#define GL_RGBA_INTEGER_MODE_EXT 0x8D9E +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha); +typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glClearColorIiEXT (GLint red, GLint green, GLint blue, GLint alpha); +GLAPI void APIENTRY glClearColorIuiEXT (GLuint red, GLuint green, GLuint blue, GLuint alpha); +#endif +#endif /* GL_EXT_texture_integer */ + +#ifndef GL_EXT_texture_lod_bias +#define GL_EXT_texture_lod_bias 1 +#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD +#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 +#define GL_TEXTURE_LOD_BIAS_EXT 0x8501 +#endif /* GL_EXT_texture_lod_bias */ + +#ifndef GL_EXT_texture_mirror_clamp +#define GL_EXT_texture_mirror_clamp 1 +#define GL_MIRROR_CLAMP_EXT 0x8742 +#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 +#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 +#endif /* GL_EXT_texture_mirror_clamp */ + +#ifndef GL_EXT_texture_object +#define GL_EXT_texture_object 1 +#define GL_TEXTURE_PRIORITY_EXT 0x8066 +#define GL_TEXTURE_RESIDENT_EXT 0x8067 +#define GL_TEXTURE_1D_BINDING_EXT 0x8068 +#define GL_TEXTURE_2D_BINDING_EXT 0x8069 +#define GL_TEXTURE_3D_BINDING_EXT 0x806A +typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); +typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures); +typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture); +typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences); +GLAPI void APIENTRY glBindTextureEXT (GLenum target, GLuint texture); +GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures); +GLAPI void APIENTRY glGenTexturesEXT (GLsizei n, GLuint *textures); +GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint texture); +GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities); +#endif +#endif /* GL_EXT_texture_object */ + +#ifndef GL_EXT_texture_perturb_normal +#define GL_EXT_texture_perturb_normal 1 +#define GL_PERTURB_EXT 0x85AE +#define GL_TEXTURE_NORMAL_EXT 0x85AF +typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureNormalEXT (GLenum mode); +#endif +#endif /* GL_EXT_texture_perturb_normal */ + +#ifndef GL_EXT_texture_sRGB +#define GL_EXT_texture_sRGB 1 +#define GL_SRGB_EXT 0x8C40 +#define GL_SRGB8_EXT 0x8C41 +#define GL_SRGB_ALPHA_EXT 0x8C42 +#define GL_SRGB8_ALPHA8_EXT 0x8C43 +#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 +#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 +#define GL_SLUMINANCE_EXT 0x8C46 +#define GL_SLUMINANCE8_EXT 0x8C47 +#define GL_COMPRESSED_SRGB_EXT 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 +#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#endif /* GL_EXT_texture_sRGB */ + +#ifndef GL_EXT_texture_sRGB_decode +#define GL_EXT_texture_sRGB_decode 1 +#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 +#define GL_DECODE_EXT 0x8A49 +#define GL_SKIP_DECODE_EXT 0x8A4A +#endif /* GL_EXT_texture_sRGB_decode */ + +#ifndef GL_EXT_texture_shared_exponent +#define GL_EXT_texture_shared_exponent 1 +#define GL_RGB9_E5_EXT 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E +#define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F +#endif /* GL_EXT_texture_shared_exponent */ + +#ifndef GL_EXT_texture_snorm +#define GL_EXT_texture_snorm 1 +#define GL_ALPHA_SNORM 0x9010 +#define GL_LUMINANCE_SNORM 0x9011 +#define GL_LUMINANCE_ALPHA_SNORM 0x9012 +#define GL_INTENSITY_SNORM 0x9013 +#define GL_ALPHA8_SNORM 0x9014 +#define GL_LUMINANCE8_SNORM 0x9015 +#define GL_LUMINANCE8_ALPHA8_SNORM 0x9016 +#define GL_INTENSITY8_SNORM 0x9017 +#define GL_ALPHA16_SNORM 0x9018 +#define GL_LUMINANCE16_SNORM 0x9019 +#define GL_LUMINANCE16_ALPHA16_SNORM 0x901A +#define GL_INTENSITY16_SNORM 0x901B +#define GL_RED_SNORM 0x8F90 +#define GL_RG_SNORM 0x8F91 +#define GL_RGB_SNORM 0x8F92 +#define GL_RGBA_SNORM 0x8F93 +#endif /* GL_EXT_texture_snorm */ + +#ifndef GL_EXT_texture_swizzle +#define GL_EXT_texture_swizzle 1 +#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 +#define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 +#define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 +#define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 +#endif /* GL_EXT_texture_swizzle */ + +#ifndef GL_EXT_timer_query +#define GL_EXT_timer_query 1 +#define GL_TIME_ELAPSED_EXT 0x88BF +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64 *params); +#endif +#endif /* GL_EXT_timer_query */ + +#ifndef GL_EXT_transform_feedback +#define GL_EXT_transform_feedback 1 +#define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F +#define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C +#define GL_SEPARATE_ATTRIBS_EXT 0x8C8D +#define GL_PRIMITIVES_GENERATED_EXT 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 +#define GL_RASTERIZER_DISCARD_EXT 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +typedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedbackEXT (void); +GLAPI void APIENTRY glBindBufferRangeEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferOffsetEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +GLAPI void APIENTRY glBindBufferBaseEXT (GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +#endif +#endif /* GL_EXT_transform_feedback */ + +#ifndef GL_EXT_vertex_array +#define GL_EXT_vertex_array 1 +#define GL_VERTEX_ARRAY_EXT 0x8074 +#define GL_NORMAL_ARRAY_EXT 0x8075 +#define GL_COLOR_ARRAY_EXT 0x8076 +#define GL_INDEX_ARRAY_EXT 0x8077 +#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 +#define GL_EDGE_FLAG_ARRAY_EXT 0x8079 +#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A +#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B +#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C +#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D +#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E +#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F +#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 +#define GL_COLOR_ARRAY_SIZE_EXT 0x8081 +#define GL_COLOR_ARRAY_TYPE_EXT 0x8082 +#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 +#define GL_COLOR_ARRAY_COUNT_EXT 0x8084 +#define GL_INDEX_ARRAY_TYPE_EXT 0x8085 +#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 +#define GL_INDEX_ARRAY_COUNT_EXT 0x8087 +#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A +#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B +#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C +#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D +#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E +#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F +#define GL_COLOR_ARRAY_POINTER_EXT 0x8090 +#define GL_INDEX_ARRAY_POINTER_EXT 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 +typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); +typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); +typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, void **params); +typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glArrayElementEXT (GLint i); +GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +GLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count); +GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer); +GLAPI void APIENTRY glGetPointervEXT (GLenum pname, void **params); +GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +#endif +#endif /* GL_EXT_vertex_array */ + +#ifndef GL_EXT_vertex_array_bgra +#define GL_EXT_vertex_array_bgra 1 +#endif /* GL_EXT_vertex_array_bgra */ + +#ifndef GL_EXT_vertex_attrib_64bit +#define GL_EXT_vertex_attrib_64bit 1 +#define GL_DOUBLE_VEC2_EXT 0x8FFC +#define GL_DOUBLE_VEC3_EXT 0x8FFD +#define GL_DOUBLE_VEC4_EXT 0x8FFE +#define GL_DOUBLE_MAT2_EXT 0x8F46 +#define GL_DOUBLE_MAT3_EXT 0x8F47 +#define GL_DOUBLE_MAT4_EXT 0x8F48 +#define GL_DOUBLE_MAT2x3_EXT 0x8F49 +#define GL_DOUBLE_MAT2x4_EXT 0x8F4A +#define GL_DOUBLE_MAT3x2_EXT 0x8F4B +#define GL_DOUBLE_MAT3x4_EXT 0x8F4C +#define GL_DOUBLE_MAT4x2_EXT 0x8F4D +#define GL_DOUBLE_MAT4x3_EXT 0x8F4E +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DEXTPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DEXTPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttribL2dEXT (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttribL3dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttribL4dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params); +#endif +#endif /* GL_EXT_vertex_attrib_64bit */ + +#ifndef GL_EXT_vertex_shader +#define GL_EXT_vertex_shader 1 +#define GL_VERTEX_SHADER_EXT 0x8780 +#define GL_VERTEX_SHADER_BINDING_EXT 0x8781 +#define GL_OP_INDEX_EXT 0x8782 +#define GL_OP_NEGATE_EXT 0x8783 +#define GL_OP_DOT3_EXT 0x8784 +#define GL_OP_DOT4_EXT 0x8785 +#define GL_OP_MUL_EXT 0x8786 +#define GL_OP_ADD_EXT 0x8787 +#define GL_OP_MADD_EXT 0x8788 +#define GL_OP_FRAC_EXT 0x8789 +#define GL_OP_MAX_EXT 0x878A +#define GL_OP_MIN_EXT 0x878B +#define GL_OP_SET_GE_EXT 0x878C +#define GL_OP_SET_LT_EXT 0x878D +#define GL_OP_CLAMP_EXT 0x878E +#define GL_OP_FLOOR_EXT 0x878F +#define GL_OP_ROUND_EXT 0x8790 +#define GL_OP_EXP_BASE_2_EXT 0x8791 +#define GL_OP_LOG_BASE_2_EXT 0x8792 +#define GL_OP_POWER_EXT 0x8793 +#define GL_OP_RECIP_EXT 0x8794 +#define GL_OP_RECIP_SQRT_EXT 0x8795 +#define GL_OP_SUB_EXT 0x8796 +#define GL_OP_CROSS_PRODUCT_EXT 0x8797 +#define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 +#define GL_OP_MOV_EXT 0x8799 +#define GL_OUTPUT_VERTEX_EXT 0x879A +#define GL_OUTPUT_COLOR0_EXT 0x879B +#define GL_OUTPUT_COLOR1_EXT 0x879C +#define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D +#define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E +#define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F +#define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 +#define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 +#define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 +#define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 +#define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 +#define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 +#define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 +#define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 +#define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 +#define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 +#define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA +#define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB +#define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC +#define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD +#define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE +#define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF +#define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 +#define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 +#define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 +#define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 +#define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 +#define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 +#define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 +#define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 +#define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 +#define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 +#define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA +#define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB +#define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC +#define GL_OUTPUT_FOG_EXT 0x87BD +#define GL_SCALAR_EXT 0x87BE +#define GL_VECTOR_EXT 0x87BF +#define GL_MATRIX_EXT 0x87C0 +#define GL_VARIANT_EXT 0x87C1 +#define GL_INVARIANT_EXT 0x87C2 +#define GL_LOCAL_CONSTANT_EXT 0x87C3 +#define GL_LOCAL_EXT 0x87C4 +#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 +#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 +#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 +#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 +#define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE +#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF +#define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 +#define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 +#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 +#define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 +#define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 +#define GL_X_EXT 0x87D5 +#define GL_Y_EXT 0x87D6 +#define GL_Z_EXT 0x87D7 +#define GL_W_EXT 0x87D8 +#define GL_NEGATIVE_X_EXT 0x87D9 +#define GL_NEGATIVE_Y_EXT 0x87DA +#define GL_NEGATIVE_Z_EXT 0x87DB +#define GL_NEGATIVE_W_EXT 0x87DC +#define GL_ZERO_EXT 0x87DD +#define GL_ONE_EXT 0x87DE +#define GL_NEGATIVE_ONE_EXT 0x87DF +#define GL_NORMALIZED_RANGE_EXT 0x87E0 +#define GL_FULL_RANGE_EXT 0x87E1 +#define GL_CURRENT_VERTEX_EXT 0x87E2 +#define GL_MVP_MATRIX_EXT 0x87E3 +#define GL_VARIANT_VALUE_EXT 0x87E4 +#define GL_VARIANT_DATATYPE_EXT 0x87E5 +#define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 +#define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 +#define GL_VARIANT_ARRAY_EXT 0x87E8 +#define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 +#define GL_INVARIANT_VALUE_EXT 0x87EA +#define GL_INVARIANT_DATATYPE_EXT 0x87EB +#define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC +#define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED +typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void); +typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void); +typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id); +typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range); +typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id); +typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1); +typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); +typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); +typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); +typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); +typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); +typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const void *addr); +typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const void *addr); +typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); +typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); +typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); +typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr); +typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr); +typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); +typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); +typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); +typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const void *addr); +typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); +typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); +typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value); +typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap); +typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, void **data); +typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginVertexShaderEXT (void); +GLAPI void APIENTRY glEndVertexShaderEXT (void); +GLAPI void APIENTRY glBindVertexShaderEXT (GLuint id); +GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint range); +GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint id); +GLAPI void APIENTRY glShaderOp1EXT (GLenum op, GLuint res, GLuint arg1); +GLAPI void APIENTRY glShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2); +GLAPI void APIENTRY glShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); +GLAPI void APIENTRY glSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +GLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +GLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num); +GLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num); +GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); +GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const void *addr); +GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const void *addr); +GLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr); +GLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr); +GLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr); +GLAPI void APIENTRY glVariantfvEXT (GLuint id, const GLfloat *addr); +GLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr); +GLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr); +GLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr); +GLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr); +GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const void *addr); +GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id); +GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id); +GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value); +GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum face, GLenum value); +GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value); +GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum unit, GLenum value); +GLAPI GLuint APIENTRY glBindParameterEXT (GLenum value); +GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap); +GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); +GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data); +GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); +GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, void **data); +GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); +GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data); +GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); +GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); +GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data); +GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data); +#endif +#endif /* GL_EXT_vertex_shader */ + +#ifndef GL_EXT_vertex_weighting +#define GL_EXT_vertex_weighting 1 +#define GL_MODELVIEW0_STACK_DEPTH_EXT 0x0BA3 +#define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 +#define GL_MODELVIEW0_MATRIX_EXT 0x0BA6 +#define GL_MODELVIEW1_MATRIX_EXT 0x8506 +#define GL_VERTEX_WEIGHTING_EXT 0x8509 +#define GL_MODELVIEW0_EXT 0x1700 +#define GL_MODELVIEW1_EXT 0x850A +#define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B +#define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C +#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D +#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E +#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F +#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 +typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight); +GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight); +GLAPI void APIENTRY glVertexWeightPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer); +#endif +#endif /* GL_EXT_vertex_weighting */ + +#ifndef GL_EXT_x11_sync_object +#define GL_EXT_x11_sync_object 1 +#define GL_SYNC_X11_FENCE_EXT 0x90E1 +typedef GLsync (APIENTRYP PFNGLIMPORTSYNCEXTPROC) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLsync APIENTRY glImportSyncEXT (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); +#endif +#endif /* GL_EXT_x11_sync_object */ + +#ifndef GL_GREMEDY_frame_terminator +#define GL_GREMEDY_frame_terminator 1 +typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFrameTerminatorGREMEDY (void); +#endif +#endif /* GL_GREMEDY_frame_terminator */ + +#ifndef GL_GREMEDY_string_marker +#define GL_GREMEDY_string_marker 1 +typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const void *string); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const void *string); +#endif +#endif /* GL_GREMEDY_string_marker */ + +#ifndef GL_HP_convolution_border_modes +#define GL_HP_convolution_border_modes 1 +#define GL_IGNORE_BORDER_HP 0x8150 +#define GL_CONSTANT_BORDER_HP 0x8151 +#define GL_REPLICATE_BORDER_HP 0x8153 +#define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 +#endif /* GL_HP_convolution_border_modes */ + +#ifndef GL_HP_image_transform +#define GL_HP_image_transform 1 +#define GL_IMAGE_SCALE_X_HP 0x8155 +#define GL_IMAGE_SCALE_Y_HP 0x8156 +#define GL_IMAGE_TRANSLATE_X_HP 0x8157 +#define GL_IMAGE_TRANSLATE_Y_HP 0x8158 +#define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 +#define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A +#define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B +#define GL_IMAGE_MAG_FILTER_HP 0x815C +#define GL_IMAGE_MIN_FILTER_HP 0x815D +#define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E +#define GL_CUBIC_HP 0x815F +#define GL_AVERAGE_HP 0x8160 +#define GL_IMAGE_TRANSFORM_2D_HP 0x8161 +#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 +#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glImageTransformParameteriHP (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params); +#endif +#endif /* GL_HP_image_transform */ + +#ifndef GL_HP_occlusion_test +#define GL_HP_occlusion_test 1 +#define GL_OCCLUSION_TEST_HP 0x8165 +#define GL_OCCLUSION_TEST_RESULT_HP 0x8166 +#endif /* GL_HP_occlusion_test */ + +#ifndef GL_HP_texture_lighting +#define GL_HP_texture_lighting 1 +#define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 +#define GL_TEXTURE_POST_SPECULAR_HP 0x8168 +#define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 +#endif /* GL_HP_texture_lighting */ + +#ifndef GL_IBM_cull_vertex +#define GL_IBM_cull_vertex 1 +#define GL_CULL_VERTEX_IBM 103050 +#endif /* GL_IBM_cull_vertex */ + +#ifndef GL_IBM_multimode_draw_arrays +#define GL_IBM_multimode_draw_arrays 1 +typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); +typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); +GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride); +#endif +#endif /* GL_IBM_multimode_draw_arrays */ + +#ifndef GL_IBM_rasterpos_clip +#define GL_IBM_rasterpos_clip 1 +#define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 +#endif /* GL_IBM_rasterpos_clip */ + +#ifndef GL_IBM_static_data +#define GL_IBM_static_data 1 +#define GL_ALL_STATIC_DATA_IBM 103060 +#define GL_STATIC_VERTEX_ARRAY_IBM 103061 +typedef void (APIENTRYP PFNGLFLUSHSTATICDATAIBMPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFlushStaticDataIBM (GLenum target); +#endif +#endif /* GL_IBM_static_data */ + +#ifndef GL_IBM_texture_mirrored_repeat +#define GL_IBM_texture_mirrored_repeat 1 +#define GL_MIRRORED_REPEAT_IBM 0x8370 +#endif /* GL_IBM_texture_mirrored_repeat */ + +#ifndef GL_IBM_vertex_array_lists +#define GL_IBM_vertex_array_lists 1 +#define GL_VERTEX_ARRAY_LIST_IBM 103070 +#define GL_NORMAL_ARRAY_LIST_IBM 103071 +#define GL_COLOR_ARRAY_LIST_IBM 103072 +#define GL_INDEX_ARRAY_LIST_IBM 103073 +#define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 +#define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 +#define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 +#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 +#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 +#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 +#define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 +#define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 +#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 +#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 +#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 +#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 +typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean **pointer, GLint ptrstride); +GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +#endif +#endif /* GL_IBM_vertex_array_lists */ + +#ifndef GL_INGR_blend_func_separate +#define GL_INGR_blend_func_separate 1 +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#endif +#endif /* GL_INGR_blend_func_separate */ + +#ifndef GL_INGR_color_clamp +#define GL_INGR_color_clamp 1 +#define GL_RED_MIN_CLAMP_INGR 0x8560 +#define GL_GREEN_MIN_CLAMP_INGR 0x8561 +#define GL_BLUE_MIN_CLAMP_INGR 0x8562 +#define GL_ALPHA_MIN_CLAMP_INGR 0x8563 +#define GL_RED_MAX_CLAMP_INGR 0x8564 +#define GL_GREEN_MAX_CLAMP_INGR 0x8565 +#define GL_BLUE_MAX_CLAMP_INGR 0x8566 +#define GL_ALPHA_MAX_CLAMP_INGR 0x8567 +#endif /* GL_INGR_color_clamp */ + +#ifndef GL_INGR_interlace_read +#define GL_INGR_interlace_read 1 +#define GL_INTERLACE_READ_INGR 0x8568 +#endif /* GL_INGR_interlace_read */ + +#ifndef GL_INTEL_fragment_shader_ordering +#define GL_INTEL_fragment_shader_ordering 1 +#endif /* GL_INTEL_fragment_shader_ordering */ + +#ifndef GL_INTEL_framebuffer_CMAA +#define GL_INTEL_framebuffer_CMAA 1 +typedef void (APIENTRYP PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glApplyFramebufferAttachmentCMAAINTEL (void); +#endif +#endif /* GL_INTEL_framebuffer_CMAA */ + +#ifndef GL_INTEL_map_texture +#define GL_INTEL_map_texture 1 +#define GL_TEXTURE_MEMORY_LAYOUT_INTEL 0x83FF +#define GL_LAYOUT_DEFAULT_INTEL 0 +#define GL_LAYOUT_LINEAR_INTEL 1 +#define GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2 +typedef void (APIENTRYP PFNGLSYNCTEXTUREINTELPROC) (GLuint texture); +typedef void (APIENTRYP PFNGLUNMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level); +typedef void *(APIENTRYP PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSyncTextureINTEL (GLuint texture); +GLAPI void APIENTRY glUnmapTexture2DINTEL (GLuint texture, GLint level); +GLAPI void *APIENTRY glMapTexture2DINTEL (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout); +#endif +#endif /* GL_INTEL_map_texture */ + +#ifndef GL_INTEL_parallel_arrays +#define GL_INTEL_parallel_arrays 1 +#define GL_PARALLEL_ARRAYS_INTEL 0x83F4 +#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 +#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 +#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 +#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 +typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); +typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const void **pointer); +typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const void **pointer); +GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const void **pointer); +GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const void **pointer); +GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const void **pointer); +#endif +#endif /* GL_INTEL_parallel_arrays */ + +#ifndef GL_INTEL_performance_query +#define GL_INTEL_performance_query 1 +#define GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x00000000 +#define GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x00000001 +#define GL_PERFQUERY_WAIT_INTEL 0x83FB +#define GL_PERFQUERY_FLUSH_INTEL 0x83FA +#define GL_PERFQUERY_DONOT_FLUSH_INTEL 0x83F9 +#define GL_PERFQUERY_COUNTER_EVENT_INTEL 0x94F0 +#define GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1 +#define GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2 +#define GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3 +#define GL_PERFQUERY_COUNTER_RAW_INTEL 0x94F4 +#define GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5 +#define GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8 +#define GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9 +#define GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL 0x94FA +#define GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL 0x94FB +#define GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL 0x94FC +#define GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL 0x94FD +#define GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE +#define GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF +#define GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500 +typedef void (APIENTRYP PFNGLBEGINPERFQUERYINTELPROC) (GLuint queryHandle); +typedef void (APIENTRYP PFNGLCREATEPERFQUERYINTELPROC) (GLuint queryId, GLuint *queryHandle); +typedef void (APIENTRYP PFNGLDELETEPERFQUERYINTELPROC) (GLuint queryHandle); +typedef void (APIENTRYP PFNGLENDPERFQUERYINTELPROC) (GLuint queryHandle); +typedef void (APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint *queryId); +typedef void (APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint *nextQueryId); +typedef void (APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); +typedef void (APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten); +typedef void (APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar *queryName, GLuint *queryId); +typedef void (APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginPerfQueryINTEL (GLuint queryHandle); +GLAPI void APIENTRY glCreatePerfQueryINTEL (GLuint queryId, GLuint *queryHandle); +GLAPI void APIENTRY glDeletePerfQueryINTEL (GLuint queryHandle); +GLAPI void APIENTRY glEndPerfQueryINTEL (GLuint queryHandle); +GLAPI void APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId); +GLAPI void APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId); +GLAPI void APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); +GLAPI void APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten); +GLAPI void APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId); +GLAPI void APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); +#endif +#endif /* GL_INTEL_performance_query */ + +#ifndef GL_MESAX_texture_stack +#define GL_MESAX_texture_stack 1 +#define GL_TEXTURE_1D_STACK_MESAX 0x8759 +#define GL_TEXTURE_2D_STACK_MESAX 0x875A +#define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B +#define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C +#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D +#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E +#endif /* GL_MESAX_texture_stack */ + +#ifndef GL_MESA_pack_invert +#define GL_MESA_pack_invert 1 +#define GL_PACK_INVERT_MESA 0x8758 +#endif /* GL_MESA_pack_invert */ + +#ifndef GL_MESA_resize_buffers +#define GL_MESA_resize_buffers 1 +typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glResizeBuffersMESA (void); +#endif +#endif /* GL_MESA_resize_buffers */ + +#ifndef GL_MESA_window_pos +#define GL_MESA_window_pos 1 +typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWindowPos2dMESA (GLdouble x, GLdouble y); +GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *v); +GLAPI void APIENTRY glWindowPos2fMESA (GLfloat x, GLfloat y); +GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *v); +GLAPI void APIENTRY glWindowPos2iMESA (GLint x, GLint y); +GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *v); +GLAPI void APIENTRY glWindowPos2sMESA (GLshort x, GLshort y); +GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *v); +GLAPI void APIENTRY glWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *v); +GLAPI void APIENTRY glWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *v); +GLAPI void APIENTRY glWindowPos3iMESA (GLint x, GLint y, GLint z); +GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *v); +GLAPI void APIENTRY glWindowPos3sMESA (GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *v); +GLAPI void APIENTRY glWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *v); +GLAPI void APIENTRY glWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *v); +GLAPI void APIENTRY glWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *v); +GLAPI void APIENTRY glWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *v); +#endif +#endif /* GL_MESA_window_pos */ + +#ifndef GL_MESA_ycbcr_texture +#define GL_MESA_ycbcr_texture 1 +#define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA +#define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB +#define GL_YCBCR_MESA 0x8757 +#endif /* GL_MESA_ycbcr_texture */ + +#ifndef GL_NVX_conditional_render +#define GL_NVX_conditional_render 1 +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVXPROC) (GLuint id); +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginConditionalRenderNVX (GLuint id); +GLAPI void APIENTRY glEndConditionalRenderNVX (void); +#endif +#endif /* GL_NVX_conditional_render */ + +#ifndef GL_NVX_gpu_memory_info +#define GL_NVX_gpu_memory_info 1 +#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047 +#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048 +#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 +#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A +#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B +#endif /* GL_NVX_gpu_memory_info */ + +#ifndef GL_NV_bindless_multi_draw_indirect +#define GL_NV_bindless_multi_draw_indirect 1 +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +#endif +#endif /* GL_NV_bindless_multi_draw_indirect */ + +#ifndef GL_NV_bindless_multi_draw_indirect_count +#define GL_NV_bindless_multi_draw_indirect_count 1 +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessCountNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); +GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessCountNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); +#endif +#endif /* GL_NV_bindless_multi_draw_indirect_count */ + +#ifndef GL_NV_bindless_texture +#define GL_NV_bindless_texture 1 +typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture); +typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLENVPROC) (GLuint texture, GLuint sampler); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC) (GLuint64 handle); +typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLENVPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle, GLenum access); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64NVPROC) (GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC) (GLuint program, GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); +typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint64 APIENTRY glGetTextureHandleNV (GLuint texture); +GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleNV (GLuint texture, GLuint sampler); +GLAPI void APIENTRY glMakeTextureHandleResidentNV (GLuint64 handle); +GLAPI void APIENTRY glMakeTextureHandleNonResidentNV (GLuint64 handle); +GLAPI GLuint64 APIENTRY glGetImageHandleNV (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +GLAPI void APIENTRY glMakeImageHandleResidentNV (GLuint64 handle, GLenum access); +GLAPI void APIENTRY glMakeImageHandleNonResidentNV (GLuint64 handle); +GLAPI void APIENTRY glUniformHandleui64NV (GLint location, GLuint64 value); +GLAPI void APIENTRY glUniformHandleui64vNV (GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glProgramUniformHandleui64NV (GLuint program, GLint location, GLuint64 value); +GLAPI void APIENTRY glProgramUniformHandleui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +GLAPI GLboolean APIENTRY glIsTextureHandleResidentNV (GLuint64 handle); +GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle); +#endif +#endif /* GL_NV_bindless_texture */ + +#ifndef GL_NV_blend_equation_advanced +#define GL_NV_blend_equation_advanced 1 +#define GL_BLEND_OVERLAP_NV 0x9281 +#define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 +#define GL_BLUE_NV 0x1905 +#define GL_COLORBURN_NV 0x929A +#define GL_COLORDODGE_NV 0x9299 +#define GL_CONJOINT_NV 0x9284 +#define GL_CONTRAST_NV 0x92A1 +#define GL_DARKEN_NV 0x9297 +#define GL_DIFFERENCE_NV 0x929E +#define GL_DISJOINT_NV 0x9283 +#define GL_DST_ATOP_NV 0x928F +#define GL_DST_IN_NV 0x928B +#define GL_DST_NV 0x9287 +#define GL_DST_OUT_NV 0x928D +#define GL_DST_OVER_NV 0x9289 +#define GL_EXCLUSION_NV 0x92A0 +#define GL_GREEN_NV 0x1904 +#define GL_HARDLIGHT_NV 0x929B +#define GL_HARDMIX_NV 0x92A9 +#define GL_HSL_COLOR_NV 0x92AF +#define GL_HSL_HUE_NV 0x92AD +#define GL_HSL_LUMINOSITY_NV 0x92B0 +#define GL_HSL_SATURATION_NV 0x92AE +#define GL_INVERT_OVG_NV 0x92B4 +#define GL_INVERT_RGB_NV 0x92A3 +#define GL_LIGHTEN_NV 0x9298 +#define GL_LINEARBURN_NV 0x92A5 +#define GL_LINEARDODGE_NV 0x92A4 +#define GL_LINEARLIGHT_NV 0x92A7 +#define GL_MINUS_CLAMPED_NV 0x92B3 +#define GL_MINUS_NV 0x929F +#define GL_MULTIPLY_NV 0x9294 +#define GL_OVERLAY_NV 0x9296 +#define GL_PINLIGHT_NV 0x92A8 +#define GL_PLUS_CLAMPED_ALPHA_NV 0x92B2 +#define GL_PLUS_CLAMPED_NV 0x92B1 +#define GL_PLUS_DARKER_NV 0x9292 +#define GL_PLUS_NV 0x9291 +#define GL_RED_NV 0x1903 +#define GL_SCREEN_NV 0x9295 +#define GL_SOFTLIGHT_NV 0x929C +#define GL_SRC_ATOP_NV 0x928E +#define GL_SRC_IN_NV 0x928A +#define GL_SRC_NV 0x9286 +#define GL_SRC_OUT_NV 0x928C +#define GL_SRC_OVER_NV 0x9288 +#define GL_UNCORRELATED_NV 0x9282 +#define GL_VIVIDLIGHT_NV 0x92A6 +#define GL_XOR_NV 0x1506 +typedef void (APIENTRYP PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLBLENDBARRIERNVPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendParameteriNV (GLenum pname, GLint value); +GLAPI void APIENTRY glBlendBarrierNV (void); +#endif +#endif /* GL_NV_blend_equation_advanced */ + +#ifndef GL_NV_blend_equation_advanced_coherent +#define GL_NV_blend_equation_advanced_coherent 1 +#define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 +#endif /* GL_NV_blend_equation_advanced_coherent */ + +#ifndef GL_NV_blend_square +#define GL_NV_blend_square 1 +#endif /* GL_NV_blend_square */ + +#ifndef GL_NV_command_list +#define GL_NV_command_list 1 +#define GL_TERMINATE_SEQUENCE_COMMAND_NV 0x0000 +#define GL_NOP_COMMAND_NV 0x0001 +#define GL_DRAW_ELEMENTS_COMMAND_NV 0x0002 +#define GL_DRAW_ARRAYS_COMMAND_NV 0x0003 +#define GL_DRAW_ELEMENTS_STRIP_COMMAND_NV 0x0004 +#define GL_DRAW_ARRAYS_STRIP_COMMAND_NV 0x0005 +#define GL_DRAW_ELEMENTS_INSTANCED_COMMAND_NV 0x0006 +#define GL_DRAW_ARRAYS_INSTANCED_COMMAND_NV 0x0007 +#define GL_ELEMENT_ADDRESS_COMMAND_NV 0x0008 +#define GL_ATTRIBUTE_ADDRESS_COMMAND_NV 0x0009 +#define GL_UNIFORM_ADDRESS_COMMAND_NV 0x000A +#define GL_BLEND_COLOR_COMMAND_NV 0x000B +#define GL_STENCIL_REF_COMMAND_NV 0x000C +#define GL_LINE_WIDTH_COMMAND_NV 0x000D +#define GL_POLYGON_OFFSET_COMMAND_NV 0x000E +#define GL_ALPHA_REF_COMMAND_NV 0x000F +#define GL_VIEWPORT_COMMAND_NV 0x0010 +#define GL_SCISSOR_COMMAND_NV 0x0011 +#define GL_FRONT_FACE_COMMAND_NV 0x0012 +typedef void (APIENTRYP PFNGLCREATESTATESNVPROC) (GLsizei n, GLuint *states); +typedef void (APIENTRYP PFNGLDELETESTATESNVPROC) (GLsizei n, const GLuint *states); +typedef GLboolean (APIENTRYP PFNGLISSTATENVPROC) (GLuint state); +typedef void (APIENTRYP PFNGLSTATECAPTURENVPROC) (GLuint state, GLenum mode); +typedef GLuint (APIENTRYP PFNGLGETCOMMANDHEADERNVPROC) (GLenum tokenID, GLuint size); +typedef GLushort (APIENTRYP PFNGLGETSTAGEINDEXNVPROC) (GLenum shadertype); +typedef void (APIENTRYP PFNGLDRAWCOMMANDSNVPROC) (GLenum primitiveMode, GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, GLuint count); +typedef void (APIENTRYP PFNGLDRAWCOMMANDSADDRESSNVPROC) (GLenum primitiveMode, const GLuint64 *indirects, const GLsizei *sizes, GLuint count); +typedef void (APIENTRYP PFNGLDRAWCOMMANDSSTATESNVPROC) (GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); +typedef void (APIENTRYP PFNGLDRAWCOMMANDSSTATESADDRESSNVPROC) (const GLuint64 *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); +typedef void (APIENTRYP PFNGLCREATECOMMANDLISTSNVPROC) (GLsizei n, GLuint *lists); +typedef void (APIENTRYP PFNGLDELETECOMMANDLISTSNVPROC) (GLsizei n, const GLuint *lists); +typedef GLboolean (APIENTRYP PFNGLISCOMMANDLISTNVPROC) (GLuint list); +typedef void (APIENTRYP PFNGLLISTDRAWCOMMANDSSTATESCLIENTNVPROC) (GLuint list, GLuint segment, const void **indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); +typedef void (APIENTRYP PFNGLCOMMANDLISTSEGMENTSNVPROC) (GLuint list, GLuint segments); +typedef void (APIENTRYP PFNGLCOMPILECOMMANDLISTNVPROC) (GLuint list); +typedef void (APIENTRYP PFNGLCALLCOMMANDLISTNVPROC) (GLuint list); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCreateStatesNV (GLsizei n, GLuint *states); +GLAPI void APIENTRY glDeleteStatesNV (GLsizei n, const GLuint *states); +GLAPI GLboolean APIENTRY glIsStateNV (GLuint state); +GLAPI void APIENTRY glStateCaptureNV (GLuint state, GLenum mode); +GLAPI GLuint APIENTRY glGetCommandHeaderNV (GLenum tokenID, GLuint size); +GLAPI GLushort APIENTRY glGetStageIndexNV (GLenum shadertype); +GLAPI void APIENTRY glDrawCommandsNV (GLenum primitiveMode, GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, GLuint count); +GLAPI void APIENTRY glDrawCommandsAddressNV (GLenum primitiveMode, const GLuint64 *indirects, const GLsizei *sizes, GLuint count); +GLAPI void APIENTRY glDrawCommandsStatesNV (GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); +GLAPI void APIENTRY glDrawCommandsStatesAddressNV (const GLuint64 *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); +GLAPI void APIENTRY glCreateCommandListsNV (GLsizei n, GLuint *lists); +GLAPI void APIENTRY glDeleteCommandListsNV (GLsizei n, const GLuint *lists); +GLAPI GLboolean APIENTRY glIsCommandListNV (GLuint list); +GLAPI void APIENTRY glListDrawCommandsStatesClientNV (GLuint list, GLuint segment, const void **indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count); +GLAPI void APIENTRY glCommandListSegmentsNV (GLuint list, GLuint segments); +GLAPI void APIENTRY glCompileCommandListNV (GLuint list); +GLAPI void APIENTRY glCallCommandListNV (GLuint list); +#endif +#endif /* GL_NV_command_list */ + +#ifndef GL_NV_compute_program5 +#define GL_NV_compute_program5 1 +#define GL_COMPUTE_PROGRAM_NV 0x90FB +#define GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV 0x90FC +#endif /* GL_NV_compute_program5 */ + +#ifndef GL_NV_conditional_render +#define GL_NV_conditional_render 1 +#define GL_QUERY_WAIT_NV 0x8E13 +#define GL_QUERY_NO_WAIT_NV 0x8E14 +#define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode); +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode); +GLAPI void APIENTRY glEndConditionalRenderNV (void); +#endif +#endif /* GL_NV_conditional_render */ + +#ifndef GL_NV_conservative_raster +#define GL_NV_conservative_raster 1 +#define GL_CONSERVATIVE_RASTERIZATION_NV 0x9346 +#define GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV 0x9347 +#define GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV 0x9348 +#define GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV 0x9349 +typedef void (APIENTRYP PFNGLSUBPIXELPRECISIONBIASNVPROC) (GLuint xbits, GLuint ybits); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSubpixelPrecisionBiasNV (GLuint xbits, GLuint ybits); +#endif +#endif /* GL_NV_conservative_raster */ + +#ifndef GL_NV_conservative_raster_dilate +#define GL_NV_conservative_raster_dilate 1 +#define GL_CONSERVATIVE_RASTER_DILATE_NV 0x9379 +#define GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV 0x937A +#define GL_CONSERVATIVE_RASTER_DILATE_GRANULARITY_NV 0x937B +typedef void (APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERFNVPROC) (GLenum pname, GLfloat value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glConservativeRasterParameterfNV (GLenum pname, GLfloat value); +#endif +#endif /* GL_NV_conservative_raster_dilate */ + +#ifndef GL_NV_copy_depth_to_color +#define GL_NV_copy_depth_to_color 1 +#define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E +#define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F +#endif /* GL_NV_copy_depth_to_color */ + +#ifndef GL_NV_copy_image +#define GL_NV_copy_image 1 +typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATANVPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCopyImageSubDataNV (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#endif +#endif /* GL_NV_copy_image */ + +#ifndef GL_NV_deep_texture3D +#define GL_NV_deep_texture3D 1 +#define GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV 0x90D0 +#define GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV 0x90D1 +#endif /* GL_NV_deep_texture3D */ + +#ifndef GL_NV_depth_buffer_float +#define GL_NV_depth_buffer_float 1 +#define GL_DEPTH_COMPONENT32F_NV 0x8DAB +#define GL_DEPTH32F_STENCIL8_NV 0x8DAC +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD +#define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF +typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar); +typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth); +typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glClearDepthdNV (GLdouble depth); +GLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax); +#endif +#endif /* GL_NV_depth_buffer_float */ + +#ifndef GL_NV_depth_clamp +#define GL_NV_depth_clamp 1 +#define GL_DEPTH_CLAMP_NV 0x864F +#endif /* GL_NV_depth_clamp */ + +#ifndef GL_NV_draw_texture +#define GL_NV_draw_texture 1 +typedef void (APIENTRYP PFNGLDRAWTEXTURENVPROC) (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawTextureNV (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); +#endif +#endif /* GL_NV_draw_texture */ + +#ifndef GL_NV_evaluators +#define GL_NV_evaluators 1 +#define GL_EVAL_2D_NV 0x86C0 +#define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 +#define GL_MAP_TESSELLATION_NV 0x86C2 +#define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 +#define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 +#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 +#define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 +#define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 +#define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 +#define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 +#define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA +#define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB +#define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC +#define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD +#define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE +#define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF +#define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 +#define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 +#define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 +#define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 +#define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 +#define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 +#define GL_MAX_MAP_TESSELLATION_NV 0x86D6 +#define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 +typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points); +typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points); +typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points); +GLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points); +GLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glEvalMapsNV (GLenum target, GLenum mode); +#endif +#endif /* GL_NV_evaluators */ + +#ifndef GL_NV_explicit_multisample +#define GL_NV_explicit_multisample 1 +#define GL_SAMPLE_POSITION_NV 0x8E50 +#define GL_SAMPLE_MASK_NV 0x8E51 +#define GL_SAMPLE_MASK_VALUE_NV 0x8E52 +#define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 +#define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 +#define GL_TEXTURE_RENDERBUFFER_NV 0x8E55 +#define GL_SAMPLER_RENDERBUFFER_NV 0x8E56 +#define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 +#define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 +#define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val); +typedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask); +typedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetMultisamplefvNV (GLenum pname, GLuint index, GLfloat *val); +GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint index, GLbitfield mask); +GLAPI void APIENTRY glTexRenderbufferNV (GLenum target, GLuint renderbuffer); +#endif +#endif /* GL_NV_explicit_multisample */ + +#ifndef GL_NV_fence +#define GL_NV_fence 1 +#define GL_ALL_COMPLETED_NV 0x84F2 +#define GL_FENCE_STATUS_NV 0x84F3 +#define GL_FENCE_CONDITION_NV 0x84F4 +typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); +typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); +typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences); +GLAPI void APIENTRY glGenFencesNV (GLsizei n, GLuint *fences); +GLAPI GLboolean APIENTRY glIsFenceNV (GLuint fence); +GLAPI GLboolean APIENTRY glTestFenceNV (GLuint fence); +GLAPI void APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params); +GLAPI void APIENTRY glFinishFenceNV (GLuint fence); +GLAPI void APIENTRY glSetFenceNV (GLuint fence, GLenum condition); +#endif +#endif /* GL_NV_fence */ + +#ifndef GL_NV_fill_rectangle +#define GL_NV_fill_rectangle 1 +#define GL_FILL_RECTANGLE_NV 0x933C +#endif /* GL_NV_fill_rectangle */ + +#ifndef GL_NV_float_buffer +#define GL_NV_float_buffer 1 +#define GL_FLOAT_R_NV 0x8880 +#define GL_FLOAT_RG_NV 0x8881 +#define GL_FLOAT_RGB_NV 0x8882 +#define GL_FLOAT_RGBA_NV 0x8883 +#define GL_FLOAT_R16_NV 0x8884 +#define GL_FLOAT_R32_NV 0x8885 +#define GL_FLOAT_RG16_NV 0x8886 +#define GL_FLOAT_RG32_NV 0x8887 +#define GL_FLOAT_RGB16_NV 0x8888 +#define GL_FLOAT_RGB32_NV 0x8889 +#define GL_FLOAT_RGBA16_NV 0x888A +#define GL_FLOAT_RGBA32_NV 0x888B +#define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C +#define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D +#define GL_FLOAT_RGBA_MODE_NV 0x888E +#endif /* GL_NV_float_buffer */ + +#ifndef GL_NV_fog_distance +#define GL_NV_fog_distance 1 +#define GL_FOG_DISTANCE_MODE_NV 0x855A +#define GL_EYE_RADIAL_NV 0x855B +#define GL_EYE_PLANE_ABSOLUTE_NV 0x855C +#endif /* GL_NV_fog_distance */ + +#ifndef GL_NV_fragment_coverage_to_color +#define GL_NV_fragment_coverage_to_color 1 +#define GL_FRAGMENT_COVERAGE_TO_COLOR_NV 0x92DD +#define GL_FRAGMENT_COVERAGE_COLOR_NV 0x92DE +typedef void (APIENTRYP PFNGLFRAGMENTCOVERAGECOLORNVPROC) (GLuint color); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFragmentCoverageColorNV (GLuint color); +#endif +#endif /* GL_NV_fragment_coverage_to_color */ + +#ifndef GL_NV_fragment_program +#define GL_NV_fragment_program 1 +#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 +#define GL_FRAGMENT_PROGRAM_NV 0x8870 +#define GL_MAX_TEXTURE_COORDS_NV 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 +#define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 +#define GL_PROGRAM_ERROR_STRING_NV 0x8874 +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); +typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); +GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); +GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); +GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); +#endif +#endif /* GL_NV_fragment_program */ + +#ifndef GL_NV_fragment_program2 +#define GL_NV_fragment_program2 1 +#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 +#define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 +#define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 +#define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 +#define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 +#endif /* GL_NV_fragment_program2 */ + +#ifndef GL_NV_fragment_program4 +#define GL_NV_fragment_program4 1 +#endif /* GL_NV_fragment_program4 */ + +#ifndef GL_NV_fragment_program_option +#define GL_NV_fragment_program_option 1 +#endif /* GL_NV_fragment_program_option */ + +#ifndef GL_NV_fragment_shader_interlock +#define GL_NV_fragment_shader_interlock 1 +#endif /* GL_NV_fragment_shader_interlock */ + +#ifndef GL_NV_framebuffer_mixed_samples +#define GL_NV_framebuffer_mixed_samples 1 +#define GL_COVERAGE_MODULATION_TABLE_NV 0x9331 +#define GL_COLOR_SAMPLES_NV 0x8E20 +#define GL_DEPTH_SAMPLES_NV 0x932D +#define GL_STENCIL_SAMPLES_NV 0x932E +#define GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV 0x932F +#define GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV 0x9330 +#define GL_COVERAGE_MODULATION_NV 0x9332 +#define GL_COVERAGE_MODULATION_TABLE_SIZE_NV 0x9333 +typedef void (APIENTRYP PFNGLCOVERAGEMODULATIONTABLENVPROC) (GLsizei n, const GLfloat *v); +typedef void (APIENTRYP PFNGLGETCOVERAGEMODULATIONTABLENVPROC) (GLsizei bufsize, GLfloat *v); +typedef void (APIENTRYP PFNGLCOVERAGEMODULATIONNVPROC) (GLenum components); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCoverageModulationTableNV (GLsizei n, const GLfloat *v); +GLAPI void APIENTRY glGetCoverageModulationTableNV (GLsizei bufsize, GLfloat *v); +GLAPI void APIENTRY glCoverageModulationNV (GLenum components); +#endif +#endif /* GL_NV_framebuffer_mixed_samples */ + +#ifndef GL_NV_framebuffer_multisample_coverage +#define GL_NV_framebuffer_multisample_coverage 1 +#define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB +#define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 +#define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 +#define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +#endif +#endif /* GL_NV_framebuffer_multisample_coverage */ + +#ifndef GL_NV_geometry_program4 +#define GL_NV_geometry_program4 1 +#define GL_GEOMETRY_PROGRAM_NV 0x8C26 +#define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 +#define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 +typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit); +GLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#endif +#endif /* GL_NV_geometry_program4 */ + +#ifndef GL_NV_geometry_shader4 +#define GL_NV_geometry_shader4 1 +#endif /* GL_NV_geometry_shader4 */ + +#ifndef GL_NV_geometry_shader_passthrough +#define GL_NV_geometry_shader_passthrough 1 +#endif /* GL_NV_geometry_shader_passthrough */ + +#ifndef GL_NV_gpu_program4 +#define GL_NV_gpu_program4 1 +#define GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905 +#define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 +#define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 +#define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 +#define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 +#define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 +#define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum target, GLuint index, const GLint *params); +GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); +GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); +GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum target, GLuint index, const GLint *params); +GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); +GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); +GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum target, GLuint index, GLint *params); +GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum target, GLuint index, GLuint *params); +GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum target, GLuint index, GLint *params); +GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum target, GLuint index, GLuint *params); +#endif +#endif /* GL_NV_gpu_program4 */ + +#ifndef GL_NV_gpu_program5 +#define GL_NV_gpu_program5 1 +#define GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A +#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B +#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C +#define GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F +#define GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44 +#define GL_MAX_PROGRAM_SUBROUTINE_NUM_NV 0x8F45 +typedef void (APIENTRYP PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC) (GLenum target, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC) (GLenum target, GLuint index, GLuint *param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramSubroutineParametersuivNV (GLenum target, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint index, GLuint *param); +#endif +#endif /* GL_NV_gpu_program5 */ + +#ifndef GL_NV_gpu_program5_mem_extended +#define GL_NV_gpu_program5_mem_extended 1 +#endif /* GL_NV_gpu_program5_mem_extended */ + +#ifndef GL_NV_gpu_shader5 +#define GL_NV_gpu_shader5 1 +#endif /* GL_NV_gpu_shader5 */ + +#ifndef GL_NV_half_float +#define GL_NV_half_float 1 +typedef unsigned short GLhalfNV; +#define GL_HALF_FLOAT_NV 0x140B +typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y); +typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z); +typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); +typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); +typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s); +typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t); +typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r); +typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog); +typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y); +GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z); +GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); +GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); +GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV s); +GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV s, GLhalfNV t); +GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r); +GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum target, GLhalfNV s); +GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t); +GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); +GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog); +GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog); +GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight); +GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight); +GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x); +GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y); +GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); +GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +#endif +#endif /* GL_NV_half_float */ + +#ifndef GL_NV_internalformat_sample_query +#define GL_NV_internalformat_sample_query 1 +#define GL_MULTISAMPLES_NV 0x9371 +#define GL_SUPERSAMPLE_SCALE_X_NV 0x9372 +#define GL_SUPERSAMPLE_SCALE_Y_NV 0x9373 +#define GL_CONFORMANT_NV 0x9374 +typedef void (APIENTRYP PFNGLGETINTERNALFORMATSAMPLEIVNVPROC) (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei bufSize, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetInternalformatSampleivNV (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei bufSize, GLint *params); +#endif +#endif /* GL_NV_internalformat_sample_query */ + +#ifndef GL_NV_light_max_exponent +#define GL_NV_light_max_exponent 1 +#define GL_MAX_SHININESS_NV 0x8504 +#define GL_MAX_SPOT_EXPONENT_NV 0x8505 +#endif /* GL_NV_light_max_exponent */ + +#ifndef GL_NV_multisample_coverage +#define GL_NV_multisample_coverage 1 +#endif /* GL_NV_multisample_coverage */ + +#ifndef GL_NV_multisample_filter_hint +#define GL_NV_multisample_filter_hint 1 +#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 +#endif /* GL_NV_multisample_filter_hint */ + +#ifndef GL_NV_occlusion_query +#define GL_NV_occlusion_query 1 +#define GL_PIXEL_COUNTER_BITS_NV 0x8864 +#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 +#define GL_PIXEL_COUNT_NV 0x8866 +#define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 +typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void); +typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids); +GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint id); +GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint id); +GLAPI void APIENTRY glEndOcclusionQueryNV (void); +GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params); +#endif +#endif /* GL_NV_occlusion_query */ + +#ifndef GL_NV_packed_depth_stencil +#define GL_NV_packed_depth_stencil 1 +#define GL_DEPTH_STENCIL_NV 0x84F9 +#define GL_UNSIGNED_INT_24_8_NV 0x84FA +#endif /* GL_NV_packed_depth_stencil */ + +#ifndef GL_NV_parameter_buffer_object +#define GL_NV_parameter_buffer_object 1 +#define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 +#define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 +#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 +#define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 +#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params); +GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params); +GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params); +#endif +#endif /* GL_NV_parameter_buffer_object */ + +#ifndef GL_NV_parameter_buffer_object2 +#define GL_NV_parameter_buffer_object2 1 +#endif /* GL_NV_parameter_buffer_object2 */ + +#ifndef GL_NV_path_rendering +#define GL_NV_path_rendering 1 +#define GL_PATH_FORMAT_SVG_NV 0x9070 +#define GL_PATH_FORMAT_PS_NV 0x9071 +#define GL_STANDARD_FONT_NAME_NV 0x9072 +#define GL_SYSTEM_FONT_NAME_NV 0x9073 +#define GL_FILE_NAME_NV 0x9074 +#define GL_PATH_STROKE_WIDTH_NV 0x9075 +#define GL_PATH_END_CAPS_NV 0x9076 +#define GL_PATH_INITIAL_END_CAP_NV 0x9077 +#define GL_PATH_TERMINAL_END_CAP_NV 0x9078 +#define GL_PATH_JOIN_STYLE_NV 0x9079 +#define GL_PATH_MITER_LIMIT_NV 0x907A +#define GL_PATH_DASH_CAPS_NV 0x907B +#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C +#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D +#define GL_PATH_DASH_OFFSET_NV 0x907E +#define GL_PATH_CLIENT_LENGTH_NV 0x907F +#define GL_PATH_FILL_MODE_NV 0x9080 +#define GL_PATH_FILL_MASK_NV 0x9081 +#define GL_PATH_FILL_COVER_MODE_NV 0x9082 +#define GL_PATH_STROKE_COVER_MODE_NV 0x9083 +#define GL_PATH_STROKE_MASK_NV 0x9084 +#define GL_COUNT_UP_NV 0x9088 +#define GL_COUNT_DOWN_NV 0x9089 +#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A +#define GL_CONVEX_HULL_NV 0x908B +#define GL_BOUNDING_BOX_NV 0x908D +#define GL_TRANSLATE_X_NV 0x908E +#define GL_TRANSLATE_Y_NV 0x908F +#define GL_TRANSLATE_2D_NV 0x9090 +#define GL_TRANSLATE_3D_NV 0x9091 +#define GL_AFFINE_2D_NV 0x9092 +#define GL_AFFINE_3D_NV 0x9094 +#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 +#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 +#define GL_UTF8_NV 0x909A +#define GL_UTF16_NV 0x909B +#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C +#define GL_PATH_COMMAND_COUNT_NV 0x909D +#define GL_PATH_COORD_COUNT_NV 0x909E +#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F +#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 +#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 +#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 +#define GL_SQUARE_NV 0x90A3 +#define GL_ROUND_NV 0x90A4 +#define GL_TRIANGULAR_NV 0x90A5 +#define GL_BEVEL_NV 0x90A6 +#define GL_MITER_REVERT_NV 0x90A7 +#define GL_MITER_TRUNCATE_NV 0x90A8 +#define GL_SKIP_MISSING_GLYPH_NV 0x90A9 +#define GL_USE_MISSING_GLYPH_NV 0x90AA +#define GL_PATH_ERROR_POSITION_NV 0x90AB +#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD +#define GL_ADJACENT_PAIRS_NV 0x90AE +#define GL_FIRST_TO_REST_NV 0x90AF +#define GL_PATH_GEN_MODE_NV 0x90B0 +#define GL_PATH_GEN_COEFF_NV 0x90B1 +#define GL_PATH_GEN_COMPONENTS_NV 0x90B3 +#define GL_PATH_STENCIL_FUNC_NV 0x90B7 +#define GL_PATH_STENCIL_REF_NV 0x90B8 +#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 +#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD +#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE +#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF +#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 +#define GL_MOVE_TO_RESETS_NV 0x90B5 +#define GL_MOVE_TO_CONTINUES_NV 0x90B6 +#define GL_CLOSE_PATH_NV 0x00 +#define GL_MOVE_TO_NV 0x02 +#define GL_RELATIVE_MOVE_TO_NV 0x03 +#define GL_LINE_TO_NV 0x04 +#define GL_RELATIVE_LINE_TO_NV 0x05 +#define GL_HORIZONTAL_LINE_TO_NV 0x06 +#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 +#define GL_VERTICAL_LINE_TO_NV 0x08 +#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 +#define GL_QUADRATIC_CURVE_TO_NV 0x0A +#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B +#define GL_CUBIC_CURVE_TO_NV 0x0C +#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D +#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E +#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F +#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 +#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 +#define GL_SMALL_CCW_ARC_TO_NV 0x12 +#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 +#define GL_SMALL_CW_ARC_TO_NV 0x14 +#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 +#define GL_LARGE_CCW_ARC_TO_NV 0x16 +#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 +#define GL_LARGE_CW_ARC_TO_NV 0x18 +#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 +#define GL_RESTART_PATH_NV 0xF0 +#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 +#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 +#define GL_RECT_NV 0xF6 +#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 +#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA +#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC +#define GL_ARC_TO_NV 0xFE +#define GL_RELATIVE_ARC_TO_NV 0xFF +#define GL_BOLD_BIT_NV 0x01 +#define GL_ITALIC_BIT_NV 0x02 +#define GL_GLYPH_WIDTH_BIT_NV 0x01 +#define GL_GLYPH_HEIGHT_BIT_NV 0x02 +#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 +#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 +#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 +#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 +#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 +#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 +#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 +#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 +#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 +#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 +#define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 +#define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 +#define GL_FONT_ASCENDER_BIT_NV 0x00200000 +#define GL_FONT_DESCENDER_BIT_NV 0x00400000 +#define GL_FONT_HEIGHT_BIT_NV 0x00800000 +#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 +#define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000 +#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000 +#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000 +#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 +#define GL_ROUNDED_RECT_NV 0xE8 +#define GL_RELATIVE_ROUNDED_RECT_NV 0xE9 +#define GL_ROUNDED_RECT2_NV 0xEA +#define GL_RELATIVE_ROUNDED_RECT2_NV 0xEB +#define GL_ROUNDED_RECT4_NV 0xEC +#define GL_RELATIVE_ROUNDED_RECT4_NV 0xED +#define GL_ROUNDED_RECT8_NV 0xEE +#define GL_RELATIVE_ROUNDED_RECT8_NV 0xEF +#define GL_RELATIVE_RECT_NV 0xF7 +#define GL_FONT_GLYPHS_AVAILABLE_NV 0x9368 +#define GL_FONT_TARGET_UNAVAILABLE_NV 0x9369 +#define GL_FONT_UNAVAILABLE_NV 0x936A +#define GL_FONT_UNINTELLIGIBLE_NV 0x936B +#define GL_CONIC_CURVE_TO_NV 0x1A +#define GL_RELATIVE_CONIC_CURVE_TO_NV 0x1B +#define GL_FONT_NUM_GLYPH_INDICES_BIT_NV 0x20000000 +#define GL_STANDARD_FONT_FORMAT_NV 0x936C +#define GL_2_BYTES_NV 0x1407 +#define GL_3_BYTES_NV 0x1408 +#define GL_4_BYTES_NV 0x1409 +#define GL_EYE_LINEAR_NV 0x2400 +#define GL_OBJECT_LINEAR_NV 0x2401 +#define GL_CONSTANT_NV 0x8576 +#define GL_PATH_FOG_GEN_MODE_NV 0x90AC +#define GL_PRIMARY_COLOR_NV 0x852C +#define GL_SECONDARY_COLOR_NV 0x852D +#define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2 +#define GL_PATH_PROJECTION_NV 0x1701 +#define GL_PATH_MODELVIEW_NV 0x1700 +#define GL_PATH_MODELVIEW_STACK_DEPTH_NV 0x0BA3 +#define GL_PATH_MODELVIEW_MATRIX_NV 0x0BA6 +#define GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV 0x0D36 +#define GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV 0x84E3 +#define GL_PATH_PROJECTION_STACK_DEPTH_NV 0x0BA4 +#define GL_PATH_PROJECTION_MATRIX_NV 0x0BA7 +#define GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV 0x0D38 +#define GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV 0x84E4 +#define GL_FRAGMENT_INPUT_NV 0x936D +typedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); +typedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); +typedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path); +typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString); +typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); +typedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); +typedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); +typedef void (APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value); +typedef void (APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value); +typedef void (APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value); +typedef void (APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); +typedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask); +typedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); +typedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); +typedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); +typedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); +typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); +typedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); +typedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); +typedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); +typedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); +typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); +typedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); +typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); +typedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y); +typedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); +typedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); +typedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); +typedef void (APIENTRYP PFNGLMATRIXLOAD3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXLOAD3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULT3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULT3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); +typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode); +typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); +typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef GLenum (APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params); +typedef void (APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); +typedef void (APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); +typedef void (APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode); +typedef void (APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value); +typedef void (APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value); +typedef void (APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value); +typedef void (APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint APIENTRY glGenPathsNV (GLsizei range); +GLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range); +GLAPI GLboolean APIENTRY glIsPathNV (GLuint path); +GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const void *pathString); +GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); +GLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath); +GLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); +GLAPI void APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value); +GLAPI void APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value); +GLAPI void APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value); +GLAPI void APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value); +GLAPI void APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray); +GLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units); +GLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask); +GLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask); +GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func); +GLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode); +GLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode); +GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value); +GLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value); +GLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands); +GLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords); +GLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray); +GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); +GLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); +GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); +GLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y); +GLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y); +GLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments); +GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); +GLAPI void APIENTRY glMatrixLoad3x2fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glMatrixLoad3x3fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glMatrixLoadTranspose3x3fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMult3x2fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMult3x3fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMultTranspose3x3fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glStencilThenCoverFillPathNV (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); +GLAPI void APIENTRY glStencilThenCoverStrokePathNV (GLuint path, GLint reference, GLuint mask, GLenum coverMode); +GLAPI void APIENTRY glStencilThenCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glStencilThenCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI GLenum APIENTRY glPathGlyphIndexRangeNV (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); +GLAPI GLenum APIENTRY glPathGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI GLenum APIENTRY glPathMemoryGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glProgramPathFragmentInputGenNV (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); +GLAPI void APIENTRY glGetProgramResourcefvNV (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params); +GLAPI void APIENTRY glPathColorGenNV (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); +GLAPI void APIENTRY glPathTexGenNV (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); +GLAPI void APIENTRY glPathFogGenNV (GLenum genMode); +GLAPI void APIENTRY glGetPathColorGenivNV (GLenum color, GLenum pname, GLint *value); +GLAPI void APIENTRY glGetPathColorGenfvNV (GLenum color, GLenum pname, GLfloat *value); +GLAPI void APIENTRY glGetPathTexGenivNV (GLenum texCoordSet, GLenum pname, GLint *value); +GLAPI void APIENTRY glGetPathTexGenfvNV (GLenum texCoordSet, GLenum pname, GLfloat *value); +#endif +#endif /* GL_NV_path_rendering */ + +#ifndef GL_NV_path_rendering_shared_edge +#define GL_NV_path_rendering_shared_edge 1 +#define GL_SHARED_EDGE_NV 0xC0 +#endif /* GL_NV_path_rendering_shared_edge */ + +#ifndef GL_NV_pixel_data_range +#define GL_NV_pixel_data_range 1 +#define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 +#define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 +#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A +#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B +#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C +#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D +typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, const void *pointer); +typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, const void *pointer); +GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target); +#endif +#endif /* GL_NV_pixel_data_range */ + +#ifndef GL_NV_point_sprite +#define GL_NV_point_sprite 1 +#define GL_POINT_SPRITE_NV 0x8861 +#define GL_COORD_REPLACE_NV 0x8862 +#define GL_POINT_SPRITE_R_MODE_NV 0x8863 +typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameteriNV (GLenum pname, GLint param); +GLAPI void APIENTRY glPointParameterivNV (GLenum pname, const GLint *params); +#endif +#endif /* GL_NV_point_sprite */ + +#ifndef GL_NV_present_video +#define GL_NV_present_video 1 +#define GL_FRAME_NV 0x8E26 +#define GL_FIELDS_NV 0x8E27 +#define GL_CURRENT_TIME_NV 0x8E28 +#define GL_NUM_FILL_STREAMS_NV 0x8E29 +#define GL_PRESENT_TIME_NV 0x8E2A +#define GL_PRESENT_DURATION_NV 0x8E2B +typedef void (APIENTRYP PFNGLPRESENTFRAMEKEYEDNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); +typedef void (APIENTRYP PFNGLPRESENTFRAMEDUALFILLNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); +typedef void (APIENTRYP PFNGLGETVIDEOIVNVPROC) (GLuint video_slot, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVIDEOUIVNVPROC) (GLuint video_slot, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLGETVIDEOI64VNVPROC) (GLuint video_slot, GLenum pname, GLint64EXT *params); +typedef void (APIENTRYP PFNGLGETVIDEOUI64VNVPROC) (GLuint video_slot, GLenum pname, GLuint64EXT *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPresentFrameKeyedNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); +GLAPI void APIENTRY glPresentFrameDualFillNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); +GLAPI void APIENTRY glGetVideoivNV (GLuint video_slot, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVideouivNV (GLuint video_slot, GLenum pname, GLuint *params); +GLAPI void APIENTRY glGetVideoi64vNV (GLuint video_slot, GLenum pname, GLint64EXT *params); +GLAPI void APIENTRY glGetVideoui64vNV (GLuint video_slot, GLenum pname, GLuint64EXT *params); +#endif +#endif /* GL_NV_present_video */ + +#ifndef GL_NV_primitive_restart +#define GL_NV_primitive_restart 1 +#define GL_PRIMITIVE_RESTART_NV 0x8558 +#define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void); +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPrimitiveRestartNV (void); +GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint index); +#endif +#endif /* GL_NV_primitive_restart */ + +#ifndef GL_NV_register_combiners +#define GL_NV_register_combiners 1 +#define GL_REGISTER_COMBINERS_NV 0x8522 +#define GL_VARIABLE_A_NV 0x8523 +#define GL_VARIABLE_B_NV 0x8524 +#define GL_VARIABLE_C_NV 0x8525 +#define GL_VARIABLE_D_NV 0x8526 +#define GL_VARIABLE_E_NV 0x8527 +#define GL_VARIABLE_F_NV 0x8528 +#define GL_VARIABLE_G_NV 0x8529 +#define GL_CONSTANT_COLOR0_NV 0x852A +#define GL_CONSTANT_COLOR1_NV 0x852B +#define GL_SPARE0_NV 0x852E +#define GL_SPARE1_NV 0x852F +#define GL_DISCARD_NV 0x8530 +#define GL_E_TIMES_F_NV 0x8531 +#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 +#define GL_UNSIGNED_IDENTITY_NV 0x8536 +#define GL_UNSIGNED_INVERT_NV 0x8537 +#define GL_EXPAND_NORMAL_NV 0x8538 +#define GL_EXPAND_NEGATE_NV 0x8539 +#define GL_HALF_BIAS_NORMAL_NV 0x853A +#define GL_HALF_BIAS_NEGATE_NV 0x853B +#define GL_SIGNED_IDENTITY_NV 0x853C +#define GL_SIGNED_NEGATE_NV 0x853D +#define GL_SCALE_BY_TWO_NV 0x853E +#define GL_SCALE_BY_FOUR_NV 0x853F +#define GL_SCALE_BY_ONE_HALF_NV 0x8540 +#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 +#define GL_COMBINER_INPUT_NV 0x8542 +#define GL_COMBINER_MAPPING_NV 0x8543 +#define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 +#define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 +#define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 +#define GL_COMBINER_MUX_SUM_NV 0x8547 +#define GL_COMBINER_SCALE_NV 0x8548 +#define GL_COMBINER_BIAS_NV 0x8549 +#define GL_COMBINER_AB_OUTPUT_NV 0x854A +#define GL_COMBINER_CD_OUTPUT_NV 0x854B +#define GL_COMBINER_SUM_OUTPUT_NV 0x854C +#define GL_MAX_GENERAL_COMBINERS_NV 0x854D +#define GL_NUM_GENERAL_COMBINERS_NV 0x854E +#define GL_COLOR_SUM_CLAMP_NV 0x854F +#define GL_COMBINER0_NV 0x8550 +#define GL_COMBINER1_NV 0x8551 +#define GL_COMBINER2_NV 0x8552 +#define GL_COMBINER3_NV 0x8553 +#define GL_COMBINER4_NV 0x8554 +#define GL_COMBINER5_NV 0x8555 +#define GL_COMBINER6_NV 0x8556 +#define GL_COMBINER7_NV 0x8557 +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); +typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCombinerParameterfvNV (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glCombinerParameterfNV (GLenum pname, GLfloat param); +GLAPI void APIENTRY glCombinerParameterivNV (GLenum pname, const GLint *params); +GLAPI void APIENTRY glCombinerParameteriNV (GLenum pname, GLint param); +GLAPI void APIENTRY glCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +GLAPI void APIENTRY glCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); +GLAPI void APIENTRY glFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params); +#endif +#endif /* GL_NV_register_combiners */ + +#ifndef GL_NV_register_combiners2 +#define GL_NV_register_combiners2 1 +#define GL_PER_STAGE_CONSTANTS_NV 0x8535 +typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params); +#endif +#endif /* GL_NV_register_combiners2 */ + +#ifndef GL_NV_sample_locations +#define GL_NV_sample_locations 1 +#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV 0x933D +#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV 0x933E +#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_NV 0x933F +#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_NV 0x9340 +#define GL_SAMPLE_LOCATION_NV 0x8E50 +#define GL_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9341 +#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV 0x9342 +#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV 0x9343 +typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLRESOLVEDEPTHVALUESNVPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFramebufferSampleLocationsfvNV (GLenum target, GLuint start, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glNamedFramebufferSampleLocationsfvNV (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glResolveDepthValuesNV (void); +#endif +#endif /* GL_NV_sample_locations */ + +#ifndef GL_NV_sample_mask_override_coverage +#define GL_NV_sample_mask_override_coverage 1 +#endif /* GL_NV_sample_mask_override_coverage */ + +#ifndef GL_NV_shader_atomic_counters +#define GL_NV_shader_atomic_counters 1 +#endif /* GL_NV_shader_atomic_counters */ + +#ifndef GL_NV_shader_atomic_float +#define GL_NV_shader_atomic_float 1 +#endif /* GL_NV_shader_atomic_float */ + +#ifndef GL_NV_shader_atomic_fp16_vector +#define GL_NV_shader_atomic_fp16_vector 1 +#endif /* GL_NV_shader_atomic_fp16_vector */ + +#ifndef GL_NV_shader_atomic_int64 +#define GL_NV_shader_atomic_int64 1 +#endif /* GL_NV_shader_atomic_int64 */ + +#ifndef GL_NV_shader_buffer_load +#define GL_NV_shader_buffer_load 1 +#define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D +#define GL_GPU_ADDRESS_NV 0x8F34 +#define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 +typedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access); +typedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target); +typedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target); +typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access); +typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer); +typedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result); +typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value); +typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access); +GLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target); +GLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target); +GLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access); +GLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer); +GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer); +GLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params); +GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params); +GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result); +GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value); +GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value); +GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#endif +#endif /* GL_NV_shader_buffer_load */ + +#ifndef GL_NV_shader_buffer_store +#define GL_NV_shader_buffer_store 1 +#define GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010 +#endif /* GL_NV_shader_buffer_store */ + +#ifndef GL_NV_shader_storage_buffer_object +#define GL_NV_shader_storage_buffer_object 1 +#endif /* GL_NV_shader_storage_buffer_object */ + +#ifndef GL_NV_shader_thread_group +#define GL_NV_shader_thread_group 1 +#define GL_WARP_SIZE_NV 0x9339 +#define GL_WARPS_PER_SM_NV 0x933A +#define GL_SM_COUNT_NV 0x933B +#endif /* GL_NV_shader_thread_group */ + +#ifndef GL_NV_shader_thread_shuffle +#define GL_NV_shader_thread_shuffle 1 +#endif /* GL_NV_shader_thread_shuffle */ + +#ifndef GL_NV_tessellation_program5 +#define GL_NV_tessellation_program5 1 +#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8 +#define GL_TESS_CONTROL_PROGRAM_NV 0x891E +#define GL_TESS_EVALUATION_PROGRAM_NV 0x891F +#define GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74 +#define GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75 +#endif /* GL_NV_tessellation_program5 */ + +#ifndef GL_NV_texgen_emboss +#define GL_NV_texgen_emboss 1 +#define GL_EMBOSS_LIGHT_NV 0x855D +#define GL_EMBOSS_CONSTANT_NV 0x855E +#define GL_EMBOSS_MAP_NV 0x855F +#endif /* GL_NV_texgen_emboss */ + +#ifndef GL_NV_texgen_reflection +#define GL_NV_texgen_reflection 1 +#define GL_NORMAL_MAP_NV 0x8511 +#define GL_REFLECTION_MAP_NV 0x8512 +#endif /* GL_NV_texgen_reflection */ + +#ifndef GL_NV_texture_barrier +#define GL_NV_texture_barrier 1 +typedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureBarrierNV (void); +#endif +#endif /* GL_NV_texture_barrier */ + +#ifndef GL_NV_texture_compression_vtc +#define GL_NV_texture_compression_vtc 1 +#endif /* GL_NV_texture_compression_vtc */ + +#ifndef GL_NV_texture_env_combine4 +#define GL_NV_texture_env_combine4 1 +#define GL_COMBINE4_NV 0x8503 +#define GL_SOURCE3_RGB_NV 0x8583 +#define GL_SOURCE3_ALPHA_NV 0x858B +#define GL_OPERAND3_RGB_NV 0x8593 +#define GL_OPERAND3_ALPHA_NV 0x859B +#endif /* GL_NV_texture_env_combine4 */ + +#ifndef GL_NV_texture_expand_normal +#define GL_NV_texture_expand_normal 1 +#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F +#endif /* GL_NV_texture_expand_normal */ + +#ifndef GL_NV_texture_multisample +#define GL_NV_texture_multisample 1 +#define GL_TEXTURE_COVERAGE_SAMPLES_NV 0x9045 +#define GL_TEXTURE_COLOR_SAMPLES_NV 0x9046 +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexImage2DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTexImage3DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage2DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage3DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage2DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +#endif +#endif /* GL_NV_texture_multisample */ + +#ifndef GL_NV_texture_rectangle +#define GL_NV_texture_rectangle 1 +#define GL_TEXTURE_RECTANGLE_NV 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 +#endif /* GL_NV_texture_rectangle */ + +#ifndef GL_NV_texture_shader +#define GL_NV_texture_shader 1 +#define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C +#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D +#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E +#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 +#define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA +#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB +#define GL_DSDT_MAG_INTENSITY_NV 0x86DC +#define GL_SHADER_CONSISTENT_NV 0x86DD +#define GL_TEXTURE_SHADER_NV 0x86DE +#define GL_SHADER_OPERATION_NV 0x86DF +#define GL_CULL_MODES_NV 0x86E0 +#define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 +#define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 +#define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 +#define GL_OFFSET_TEXTURE_2D_MATRIX_NV 0x86E1 +#define GL_OFFSET_TEXTURE_2D_SCALE_NV 0x86E2 +#define GL_OFFSET_TEXTURE_2D_BIAS_NV 0x86E3 +#define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 +#define GL_CONST_EYE_NV 0x86E5 +#define GL_PASS_THROUGH_NV 0x86E6 +#define GL_CULL_FRAGMENT_NV 0x86E7 +#define GL_OFFSET_TEXTURE_2D_NV 0x86E8 +#define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 +#define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA +#define GL_DOT_PRODUCT_NV 0x86EC +#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED +#define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE +#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 +#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 +#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 +#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 +#define GL_HILO_NV 0x86F4 +#define GL_DSDT_NV 0x86F5 +#define GL_DSDT_MAG_NV 0x86F6 +#define GL_DSDT_MAG_VIB_NV 0x86F7 +#define GL_HILO16_NV 0x86F8 +#define GL_SIGNED_HILO_NV 0x86F9 +#define GL_SIGNED_HILO16_NV 0x86FA +#define GL_SIGNED_RGBA_NV 0x86FB +#define GL_SIGNED_RGBA8_NV 0x86FC +#define GL_SIGNED_RGB_NV 0x86FE +#define GL_SIGNED_RGB8_NV 0x86FF +#define GL_SIGNED_LUMINANCE_NV 0x8701 +#define GL_SIGNED_LUMINANCE8_NV 0x8702 +#define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 +#define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 +#define GL_SIGNED_ALPHA_NV 0x8705 +#define GL_SIGNED_ALPHA8_NV 0x8706 +#define GL_SIGNED_INTENSITY_NV 0x8707 +#define GL_SIGNED_INTENSITY8_NV 0x8708 +#define GL_DSDT8_NV 0x8709 +#define GL_DSDT8_MAG8_NV 0x870A +#define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B +#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C +#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D +#define GL_HI_SCALE_NV 0x870E +#define GL_LO_SCALE_NV 0x870F +#define GL_DS_SCALE_NV 0x8710 +#define GL_DT_SCALE_NV 0x8711 +#define GL_MAGNITUDE_SCALE_NV 0x8712 +#define GL_VIBRANCE_SCALE_NV 0x8713 +#define GL_HI_BIAS_NV 0x8714 +#define GL_LO_BIAS_NV 0x8715 +#define GL_DS_BIAS_NV 0x8716 +#define GL_DT_BIAS_NV 0x8717 +#define GL_MAGNITUDE_BIAS_NV 0x8718 +#define GL_VIBRANCE_BIAS_NV 0x8719 +#define GL_TEXTURE_BORDER_VALUES_NV 0x871A +#define GL_TEXTURE_HI_SIZE_NV 0x871B +#define GL_TEXTURE_LO_SIZE_NV 0x871C +#define GL_TEXTURE_DS_SIZE_NV 0x871D +#define GL_TEXTURE_DT_SIZE_NV 0x871E +#define GL_TEXTURE_MAG_SIZE_NV 0x871F +#endif /* GL_NV_texture_shader */ + +#ifndef GL_NV_texture_shader2 +#define GL_NV_texture_shader2 1 +#define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF +#endif /* GL_NV_texture_shader2 */ + +#ifndef GL_NV_texture_shader3 +#define GL_NV_texture_shader3 1 +#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 +#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 +#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 +#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 +#define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 +#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 +#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 +#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 +#define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 +#define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 +#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A +#define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B +#define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C +#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D +#define GL_HILO8_NV 0x885E +#define GL_SIGNED_HILO8_NV 0x885F +#define GL_FORCE_BLUE_TO_ONE_NV 0x8860 +#endif /* GL_NV_texture_shader3 */ + +#ifndef GL_NV_transform_feedback +#define GL_NV_transform_feedback 1 +#define GL_BACK_PRIMARY_COLOR_NV 0x8C77 +#define GL_BACK_SECONDARY_COLOR_NV 0x8C78 +#define GL_TEXTURE_COORD_NV 0x8C79 +#define GL_CLIP_DISTANCE_NV 0x8C7A +#define GL_VERTEX_ID_NV 0x8C7B +#define GL_PRIMITIVE_ID_NV 0x8C7C +#define GL_GENERIC_ATTRIB_NV 0x8C7D +#define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 +#define GL_ACTIVE_VARYINGS_NV 0x8C81 +#define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 +#define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 +#define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 +#define GL_PRIMITIVES_GENERATED_NV 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 +#define GL_RASTERIZER_DISCARD_NV 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B +#define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C +#define GL_SEPARATE_ATTRIBS_NV 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F +#define GL_LAYER_NV 0x8DAA +#define GL_NEXT_BUFFER_NV -2 +#define GL_SKIP_COMPONENTS4_NV -3 +#define GL_SKIP_COMPONENTS3_NV -4 +#define GL_SKIP_COMPONENTS2_NV -5 +#define GL_SKIP_COMPONENTS1_NV -6 +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLenum bufferMode); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); +typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedbackNV (void); +GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLsizei count, const GLint *attribs, GLenum bufferMode); +GLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +GLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); +GLAPI void APIENTRY glActiveVaryingNV (GLuint program, const GLchar *name); +GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetActiveVaryingNV (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint program, GLuint index, GLint *location); +GLAPI void APIENTRY glTransformFeedbackStreamAttribsNV (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); +#endif +#endif /* GL_NV_transform_feedback */ + +#ifndef GL_NV_transform_feedback2 +#define GL_NV_transform_feedback2 1 +#define GL_TRANSFORM_FEEDBACK_NV 0x8E22 +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 +typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids); +typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei n, const GLuint *ids); +GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei n, GLuint *ids); +GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint id); +GLAPI void APIENTRY glPauseTransformFeedbackNV (void); +GLAPI void APIENTRY glResumeTransformFeedbackNV (void); +GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id); +#endif +#endif /* GL_NV_transform_feedback2 */ + +#ifndef GL_NV_uniform_buffer_unified_memory +#define GL_NV_uniform_buffer_unified_memory 1 +#define GL_UNIFORM_BUFFER_UNIFIED_NV 0x936E +#define GL_UNIFORM_BUFFER_ADDRESS_NV 0x936F +#define GL_UNIFORM_BUFFER_LENGTH_NV 0x9370 +#endif /* GL_NV_uniform_buffer_unified_memory */ + +#ifndef GL_NV_vdpau_interop +#define GL_NV_vdpau_interop 1 +typedef GLintptr GLvdpauSurfaceNV; +#define GL_SURFACE_STATE_NV 0x86EB +#define GL_SURFACE_REGISTERED_NV 0x86FD +#define GL_SURFACE_MAPPED_NV 0x8700 +#define GL_WRITE_DISCARD_NV 0x88BE +typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const void *vdpDevice, const void *getProcAddress); +typedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void); +typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +typedef GLboolean (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface); +typedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface); +typedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +typedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access); +typedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); +typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVDPAUInitNV (const void *vdpDevice, const void *getProcAddress); +GLAPI void APIENTRY glVDPAUFiniNV (void); +GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +GLAPI GLboolean APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface); +GLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface); +GLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +GLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access); +GLAPI void APIENTRY glVDPAUMapSurfacesNV (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); +GLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); +#endif +#endif /* GL_NV_vdpau_interop */ + +#ifndef GL_NV_vertex_array_range +#define GL_NV_vertex_array_range 1 +#define GL_VERTEX_ARRAY_RANGE_NV 0x851D +#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E +#define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F +#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 +#define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 +typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); +typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const void *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); +GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const void *pointer); +#endif +#endif /* GL_NV_vertex_array_range */ + +#ifndef GL_NV_vertex_array_range2 +#define GL_NV_vertex_array_range2 1 +#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 +#endif /* GL_NV_vertex_array_range2 */ + +#ifndef GL_NV_vertex_attrib_integer_64bit +#define GL_NV_vertex_attrib_integer_64bit 1 +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x); +GLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x); +GLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params); +GLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params); +GLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); +#endif +#endif /* GL_NV_vertex_attrib_integer_64bit */ + +#ifndef GL_NV_vertex_buffer_unified_memory +#define GL_NV_vertex_buffer_unified_memory 1 +#define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E +#define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F +#define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20 +#define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 +#define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 +#define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 +#define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 +#define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25 +#define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 +#define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27 +#define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 +#define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 +#define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A +#define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B +#define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C +#define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D +#define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E +#define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F +#define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 +#define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31 +#define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 +#define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 +#define GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40 +#define GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41 +#define GL_DRAW_INDIRECT_LENGTH_NV 0x8F42 +typedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); +typedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride); +typedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); +GLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride); +GLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride); +GLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride); +GLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride); +GLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); +GLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result); +#endif +#endif /* GL_NV_vertex_buffer_unified_memory */ + +#ifndef GL_NV_vertex_program +#define GL_NV_vertex_program 1 +#define GL_VERTEX_PROGRAM_NV 0x8620 +#define GL_VERTEX_STATE_PROGRAM_NV 0x8621 +#define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 +#define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 +#define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 +#define GL_CURRENT_ATTRIB_NV 0x8626 +#define GL_PROGRAM_LENGTH_NV 0x8627 +#define GL_PROGRAM_STRING_NV 0x8628 +#define GL_MODELVIEW_PROJECTION_NV 0x8629 +#define GL_IDENTITY_NV 0x862A +#define GL_INVERSE_NV 0x862B +#define GL_TRANSPOSE_NV 0x862C +#define GL_INVERSE_TRANSPOSE_NV 0x862D +#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E +#define GL_MAX_TRACK_MATRICES_NV 0x862F +#define GL_MATRIX0_NV 0x8630 +#define GL_MATRIX1_NV 0x8631 +#define GL_MATRIX2_NV 0x8632 +#define GL_MATRIX3_NV 0x8633 +#define GL_MATRIX4_NV 0x8634 +#define GL_MATRIX5_NV 0x8635 +#define GL_MATRIX6_NV 0x8636 +#define GL_MATRIX7_NV 0x8637 +#define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 +#define GL_CURRENT_MATRIX_NV 0x8641 +#define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 +#define GL_PROGRAM_PARAMETER_NV 0x8644 +#define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 +#define GL_PROGRAM_TARGET_NV 0x8646 +#define GL_PROGRAM_RESIDENT_NV 0x8647 +#define GL_TRACK_MATRIX_NV 0x8648 +#define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 +#define GL_VERTEX_PROGRAM_BINDING_NV 0x864A +#define GL_PROGRAM_ERROR_POSITION_NV 0x864B +#define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 +#define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 +#define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 +#define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 +#define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 +#define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 +#define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 +#define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 +#define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 +#define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 +#define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A +#define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B +#define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C +#define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D +#define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E +#define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F +#define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 +#define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 +#define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 +#define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 +#define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 +#define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 +#define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 +#define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 +#define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 +#define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 +#define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A +#define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B +#define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C +#define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D +#define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E +#define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F +#define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 +#define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 +#define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 +#define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 +#define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 +#define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 +#define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 +#define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 +#define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 +#define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 +#define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A +#define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B +#define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C +#define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D +#define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E +#define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F +typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences); +typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params); +typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs); +typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program); +typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, void **pointer); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences); +GLAPI void APIENTRY glBindProgramNV (GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteProgramsNV (GLsizei n, const GLuint *programs); +GLAPI void APIENTRY glExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params); +GLAPI void APIENTRY glGenProgramsNV (GLsizei n, GLuint *programs); +GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetProgramivNV (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program); +GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, void **pointer); +GLAPI GLboolean APIENTRY glIsProgramNV (GLuint id); +GLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program); +GLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v); +GLAPI void APIENTRY glProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v); +GLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs); +GLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform); +GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib1sNV (GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib2sNV (GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v); +#endif +#endif /* GL_NV_vertex_program */ + +#ifndef GL_NV_vertex_program1_1 +#define GL_NV_vertex_program1_1 1 +#endif /* GL_NV_vertex_program1_1 */ + +#ifndef GL_NV_vertex_program2 +#define GL_NV_vertex_program2 1 +#endif /* GL_NV_vertex_program2 */ + +#ifndef GL_NV_vertex_program2_option +#define GL_NV_vertex_program2_option 1 +#endif /* GL_NV_vertex_program2_option */ + +#ifndef GL_NV_vertex_program3 +#define GL_NV_vertex_program3 1 +#endif /* GL_NV_vertex_program3 */ + +#ifndef GL_NV_vertex_program4 +#define GL_NV_vertex_program4 1 +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x); +GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y); +GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x); +GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y); +GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params); +#endif +#endif /* GL_NV_vertex_program4 */ + +#ifndef GL_NV_video_capture +#define GL_NV_video_capture 1 +#define GL_VIDEO_BUFFER_NV 0x9020 +#define GL_VIDEO_BUFFER_BINDING_NV 0x9021 +#define GL_FIELD_UPPER_NV 0x9022 +#define GL_FIELD_LOWER_NV 0x9023 +#define GL_NUM_VIDEO_CAPTURE_STREAMS_NV 0x9024 +#define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025 +#define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026 +#define GL_LAST_VIDEO_CAPTURE_STATUS_NV 0x9027 +#define GL_VIDEO_BUFFER_PITCH_NV 0x9028 +#define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029 +#define GL_VIDEO_COLOR_CONVERSION_MAX_NV 0x902A +#define GL_VIDEO_COLOR_CONVERSION_MIN_NV 0x902B +#define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C +#define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D +#define GL_PARTIAL_SUCCESS_NV 0x902E +#define GL_SUCCESS_NV 0x902F +#define GL_FAILURE_NV 0x9030 +#define GL_YCBYCR8_422_NV 0x9031 +#define GL_YCBAYCR8A_4224_NV 0x9032 +#define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV 0x9033 +#define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034 +#define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV 0x9035 +#define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036 +#define GL_Z4Y12Z4CB12Z4CR12_444_NV 0x9037 +#define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV 0x9038 +#define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV 0x9039 +#define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A +#define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B +#define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C +typedef void (APIENTRYP PFNGLBEGINVIDEOCAPTURENVPROC) (GLuint video_capture_slot); +typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); +typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLENDVIDEOCAPTURENVPROC) (GLuint video_capture_slot); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTUREIVNVPROC) (GLuint video_capture_slot, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); +typedef GLenum (APIENTRYP PFNGLVIDEOCAPTURENVPROC) (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); +typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginVideoCaptureNV (GLuint video_capture_slot); +GLAPI void APIENTRY glBindVideoCaptureStreamBufferNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); +GLAPI void APIENTRY glBindVideoCaptureStreamTextureNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); +GLAPI void APIENTRY glEndVideoCaptureNV (GLuint video_capture_slot); +GLAPI void APIENTRY glGetVideoCaptureivNV (GLuint video_capture_slot, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVideoCaptureStreamivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVideoCaptureStreamfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVideoCaptureStreamdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); +GLAPI GLenum APIENTRY glVideoCaptureNV (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); +GLAPI void APIENTRY glVideoCaptureStreamParameterivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); +GLAPI void APIENTRY glVideoCaptureStreamParameterfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); +#endif +#endif /* GL_NV_video_capture */ + +#ifndef GL_NV_viewport_array2 +#define GL_NV_viewport_array2 1 +#endif /* GL_NV_viewport_array2 */ + +#ifndef GL_OML_interlace +#define GL_OML_interlace 1 +#define GL_INTERLACE_OML 0x8980 +#define GL_INTERLACE_READ_OML 0x8981 +#endif /* GL_OML_interlace */ + +#ifndef GL_OML_resample +#define GL_OML_resample 1 +#define GL_PACK_RESAMPLE_OML 0x8984 +#define GL_UNPACK_RESAMPLE_OML 0x8985 +#define GL_RESAMPLE_REPLICATE_OML 0x8986 +#define GL_RESAMPLE_ZERO_FILL_OML 0x8987 +#define GL_RESAMPLE_AVERAGE_OML 0x8988 +#define GL_RESAMPLE_DECIMATE_OML 0x8989 +#endif /* GL_OML_resample */ + +#ifndef GL_OML_subsample +#define GL_OML_subsample 1 +#define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 +#define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 +#endif /* GL_OML_subsample */ + +#ifndef GL_OVR_multiview +#define GL_OVR_multiview 1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632 +#define GL_MAX_VIEWS_OVR 0x9631 +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFramebufferTextureMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews); +#endif +#endif /* GL_OVR_multiview */ + +#ifndef GL_OVR_multiview2 +#define GL_OVR_multiview2 1 +#endif /* GL_OVR_multiview2 */ + +#ifndef GL_PGI_misc_hints +#define GL_PGI_misc_hints 1 +#define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 +#define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD +#define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE +#define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 +#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 +#define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 +#define GL_ALWAYS_FAST_HINT_PGI 0x1A20C +#define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D +#define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E +#define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F +#define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 +#define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 +#define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 +#define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 +#define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 +#define GL_FULL_STIPPLE_HINT_PGI 0x1A219 +#define GL_CLIP_NEAR_HINT_PGI 0x1A220 +#define GL_CLIP_FAR_HINT_PGI 0x1A221 +#define GL_WIDE_LINE_HINT_PGI 0x1A222 +#define GL_BACK_NORMALS_HINT_PGI 0x1A223 +typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glHintPGI (GLenum target, GLint mode); +#endif +#endif /* GL_PGI_misc_hints */ + +#ifndef GL_PGI_vertex_hints +#define GL_PGI_vertex_hints 1 +#define GL_VERTEX_DATA_HINT_PGI 0x1A22A +#define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B +#define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C +#define GL_MAX_VERTEX_HINT_PGI 0x1A22D +#define GL_COLOR3_BIT_PGI 0x00010000 +#define GL_COLOR4_BIT_PGI 0x00020000 +#define GL_EDGEFLAG_BIT_PGI 0x00040000 +#define GL_INDEX_BIT_PGI 0x00080000 +#define GL_MAT_AMBIENT_BIT_PGI 0x00100000 +#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 +#define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 +#define GL_MAT_EMISSION_BIT_PGI 0x00800000 +#define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 +#define GL_MAT_SHININESS_BIT_PGI 0x02000000 +#define GL_MAT_SPECULAR_BIT_PGI 0x04000000 +#define GL_NORMAL_BIT_PGI 0x08000000 +#define GL_TEXCOORD1_BIT_PGI 0x10000000 +#define GL_TEXCOORD2_BIT_PGI 0x20000000 +#define GL_TEXCOORD3_BIT_PGI 0x40000000 +#define GL_TEXCOORD4_BIT_PGI 0x80000000 +#define GL_VERTEX23_BIT_PGI 0x00000004 +#define GL_VERTEX4_BIT_PGI 0x00000008 +#endif /* GL_PGI_vertex_hints */ + +#ifndef GL_REND_screen_coordinates +#define GL_REND_screen_coordinates 1 +#define GL_SCREEN_COORDINATES_REND 0x8490 +#define GL_INVERTED_SCREEN_W_REND 0x8491 +#endif /* GL_REND_screen_coordinates */ + +#ifndef GL_S3_s3tc +#define GL_S3_s3tc 1 +#define GL_RGB_S3TC 0x83A0 +#define GL_RGB4_S3TC 0x83A1 +#define GL_RGBA_S3TC 0x83A2 +#define GL_RGBA4_S3TC 0x83A3 +#define GL_RGBA_DXT5_S3TC 0x83A4 +#define GL_RGBA4_DXT5_S3TC 0x83A5 +#endif /* GL_S3_s3tc */ + +#ifndef GL_SGIS_detail_texture +#define GL_SGIS_detail_texture 1 +#define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 +#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 +#define GL_LINEAR_DETAIL_SGIS 0x8097 +#define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 +#define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 +#define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A +#define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B +#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C +typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); +GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum target, GLfloat *points); +#endif +#endif /* GL_SGIS_detail_texture */ + +#ifndef GL_SGIS_fog_function +#define GL_SGIS_fog_function 1 +#define GL_FOG_FUNC_SGIS 0x812A +#define GL_FOG_FUNC_POINTS_SGIS 0x812B +#define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C +typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFogFuncSGIS (GLsizei n, const GLfloat *points); +GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *points); +#endif +#endif /* GL_SGIS_fog_function */ + +#ifndef GL_SGIS_generate_mipmap +#define GL_SGIS_generate_mipmap 1 +#define GL_GENERATE_MIPMAP_SGIS 0x8191 +#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 +#endif /* GL_SGIS_generate_mipmap */ + +#ifndef GL_SGIS_multisample +#define GL_SGIS_multisample 1 +#define GL_MULTISAMPLE_SGIS 0x809D +#define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F +#define GL_SAMPLE_MASK_SGIS 0x80A0 +#define GL_1PASS_SGIS 0x80A1 +#define GL_2PASS_0_SGIS 0x80A2 +#define GL_2PASS_1_SGIS 0x80A3 +#define GL_4PASS_0_SGIS 0x80A4 +#define GL_4PASS_1_SGIS 0x80A5 +#define GL_4PASS_2_SGIS 0x80A6 +#define GL_4PASS_3_SGIS 0x80A7 +#define GL_SAMPLE_BUFFERS_SGIS 0x80A8 +#define GL_SAMPLES_SGIS 0x80A9 +#define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA +#define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB +#define GL_SAMPLE_PATTERN_SGIS 0x80AC +typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert); +typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleMaskSGIS (GLclampf value, GLboolean invert); +GLAPI void APIENTRY glSamplePatternSGIS (GLenum pattern); +#endif +#endif /* GL_SGIS_multisample */ + +#ifndef GL_SGIS_pixel_texture +#define GL_SGIS_pixel_texture 1 +#define GL_PIXEL_TEXTURE_SGIS 0x8353 +#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 +#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 +#define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum pname, GLint param); +GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum pname, const GLint *params); +GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params); +GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params); +#endif +#endif /* GL_SGIS_pixel_texture */ + +#ifndef GL_SGIS_point_line_texgen +#define GL_SGIS_point_line_texgen 1 +#define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 +#define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 +#define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 +#define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 +#define GL_EYE_POINT_SGIS 0x81F4 +#define GL_OBJECT_POINT_SGIS 0x81F5 +#define GL_EYE_LINE_SGIS 0x81F6 +#define GL_OBJECT_LINE_SGIS 0x81F7 +#endif /* GL_SGIS_point_line_texgen */ + +#ifndef GL_SGIS_point_parameters +#define GL_SGIS_point_parameters 1 +#define GL_POINT_SIZE_MIN_SGIS 0x8126 +#define GL_POINT_SIZE_MAX_SGIS 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 +#define GL_DISTANCE_ATTENUATION_SGIS 0x8129 +typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfSGIS (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfvSGIS (GLenum pname, const GLfloat *params); +#endif +#endif /* GL_SGIS_point_parameters */ + +#ifndef GL_SGIS_sharpen_texture +#define GL_SGIS_sharpen_texture 1 +#define GL_LINEAR_SHARPEN_SGIS 0x80AD +#define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE +#define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF +#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 +typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); +GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points); +#endif +#endif /* GL_SGIS_sharpen_texture */ + +#ifndef GL_SGIS_texture4D +#define GL_SGIS_texture4D 1 +#define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 +#define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 +#define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 +#define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 +#define GL_TEXTURE_4D_SGIS 0x8134 +#define GL_PROXY_TEXTURE_4D_SGIS 0x8135 +#define GL_TEXTURE_4DSIZE_SGIS 0x8136 +#define GL_TEXTURE_WRAP_Q_SGIS 0x8137 +#define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 +#define GL_TEXTURE_4D_BINDING_SGIS 0x814F +typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels); +#endif +#endif /* GL_SGIS_texture4D */ + +#ifndef GL_SGIS_texture_border_clamp +#define GL_SGIS_texture_border_clamp 1 +#define GL_CLAMP_TO_BORDER_SGIS 0x812D +#endif /* GL_SGIS_texture_border_clamp */ + +#ifndef GL_SGIS_texture_color_mask +#define GL_SGIS_texture_color_mask 1 +#define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF +typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +#endif +#endif /* GL_SGIS_texture_color_mask */ + +#ifndef GL_SGIS_texture_edge_clamp +#define GL_SGIS_texture_edge_clamp 1 +#define GL_CLAMP_TO_EDGE_SGIS 0x812F +#endif /* GL_SGIS_texture_edge_clamp */ + +#ifndef GL_SGIS_texture_filter4 +#define GL_SGIS_texture_filter4 1 +#define GL_FILTER4_SGIS 0x8146 +#define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 +typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights); +typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights); +GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); +#endif +#endif /* GL_SGIS_texture_filter4 */ + +#ifndef GL_SGIS_texture_lod +#define GL_SGIS_texture_lod 1 +#define GL_TEXTURE_MIN_LOD_SGIS 0x813A +#define GL_TEXTURE_MAX_LOD_SGIS 0x813B +#define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C +#define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D +#endif /* GL_SGIS_texture_lod */ + +#ifndef GL_SGIS_texture_select +#define GL_SGIS_texture_select 1 +#define GL_DUAL_ALPHA4_SGIS 0x8110 +#define GL_DUAL_ALPHA8_SGIS 0x8111 +#define GL_DUAL_ALPHA12_SGIS 0x8112 +#define GL_DUAL_ALPHA16_SGIS 0x8113 +#define GL_DUAL_LUMINANCE4_SGIS 0x8114 +#define GL_DUAL_LUMINANCE8_SGIS 0x8115 +#define GL_DUAL_LUMINANCE12_SGIS 0x8116 +#define GL_DUAL_LUMINANCE16_SGIS 0x8117 +#define GL_DUAL_INTENSITY4_SGIS 0x8118 +#define GL_DUAL_INTENSITY8_SGIS 0x8119 +#define GL_DUAL_INTENSITY12_SGIS 0x811A +#define GL_DUAL_INTENSITY16_SGIS 0x811B +#define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C +#define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D +#define GL_QUAD_ALPHA4_SGIS 0x811E +#define GL_QUAD_ALPHA8_SGIS 0x811F +#define GL_QUAD_LUMINANCE4_SGIS 0x8120 +#define GL_QUAD_LUMINANCE8_SGIS 0x8121 +#define GL_QUAD_INTENSITY4_SGIS 0x8122 +#define GL_QUAD_INTENSITY8_SGIS 0x8123 +#define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 +#define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 +#endif /* GL_SGIS_texture_select */ + +#ifndef GL_SGIX_async +#define GL_SGIX_async 1 +#define GL_ASYNC_MARKER_SGIX 0x8329 +typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker); +typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp); +typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp); +typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range); +typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range); +typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint marker); +GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *markerp); +GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *markerp); +GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei range); +GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range); +GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint marker); +#endif +#endif /* GL_SGIX_async */ + +#ifndef GL_SGIX_async_histogram +#define GL_SGIX_async_histogram 1 +#define GL_ASYNC_HISTOGRAM_SGIX 0x832C +#define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D +#endif /* GL_SGIX_async_histogram */ + +#ifndef GL_SGIX_async_pixel +#define GL_SGIX_async_pixel 1 +#define GL_ASYNC_TEX_IMAGE_SGIX 0x835C +#define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D +#define GL_ASYNC_READ_PIXELS_SGIX 0x835E +#define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F +#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 +#define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 +#endif /* GL_SGIX_async_pixel */ + +#ifndef GL_SGIX_blend_alpha_minmax +#define GL_SGIX_blend_alpha_minmax 1 +#define GL_ALPHA_MIN_SGIX 0x8320 +#define GL_ALPHA_MAX_SGIX 0x8321 +#endif /* GL_SGIX_blend_alpha_minmax */ + +#ifndef GL_SGIX_calligraphic_fragment +#define GL_SGIX_calligraphic_fragment 1 +#define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 +#endif /* GL_SGIX_calligraphic_fragment */ + +#ifndef GL_SGIX_clipmap +#define GL_SGIX_clipmap 1 +#define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 +#define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 +#define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 +#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 +#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 +#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 +#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 +#define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 +#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 +#define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D +#define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E +#define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F +#endif /* GL_SGIX_clipmap */ + +#ifndef GL_SGIX_convolution_accuracy +#define GL_SGIX_convolution_accuracy 1 +#define GL_CONVOLUTION_HINT_SGIX 0x8316 +#endif /* GL_SGIX_convolution_accuracy */ + +#ifndef GL_SGIX_depth_pass_instrument +#define GL_SGIX_depth_pass_instrument 1 +#endif /* GL_SGIX_depth_pass_instrument */ + +#ifndef GL_SGIX_depth_texture +#define GL_SGIX_depth_texture 1 +#define GL_DEPTH_COMPONENT16_SGIX 0x81A5 +#define GL_DEPTH_COMPONENT24_SGIX 0x81A6 +#define GL_DEPTH_COMPONENT32_SGIX 0x81A7 +#endif /* GL_SGIX_depth_texture */ + +#ifndef GL_SGIX_flush_raster +#define GL_SGIX_flush_raster 1 +typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFlushRasterSGIX (void); +#endif +#endif /* GL_SGIX_flush_raster */ + +#ifndef GL_SGIX_fog_offset +#define GL_SGIX_fog_offset 1 +#define GL_FOG_OFFSET_SGIX 0x8198 +#define GL_FOG_OFFSET_VALUE_SGIX 0x8199 +#endif /* GL_SGIX_fog_offset */ + +#ifndef GL_SGIX_fragment_lighting +#define GL_SGIX_fragment_lighting 1 +#define GL_FRAGMENT_LIGHTING_SGIX 0x8400 +#define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 +#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 +#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 +#define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 +#define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 +#define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 +#define GL_LIGHT_ENV_MODE_SGIX 0x8407 +#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 +#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 +#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A +#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B +#define GL_FRAGMENT_LIGHT0_SGIX 0x840C +#define GL_FRAGMENT_LIGHT1_SGIX 0x840D +#define GL_FRAGMENT_LIGHT2_SGIX 0x840E +#define GL_FRAGMENT_LIGHT3_SGIX 0x840F +#define GL_FRAGMENT_LIGHT4_SGIX 0x8410 +#define GL_FRAGMENT_LIGHT5_SGIX 0x8411 +#define GL_FRAGMENT_LIGHT6_SGIX 0x8412 +#define GL_FRAGMENT_LIGHT7_SGIX 0x8413 +typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum face, GLenum mode); +GLAPI void APIENTRY glFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param); +GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glFragmentLightiSGIX (GLenum light, GLenum pname, GLint param); +GLAPI void APIENTRY glFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params); +GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum pname, GLfloat param); +GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum pname, GLint param); +GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum pname, const GLint *params); +GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param); +GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param); +GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params); +GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params); +GLAPI void APIENTRY glLightEnviSGIX (GLenum pname, GLint param); +#endif +#endif /* GL_SGIX_fragment_lighting */ + +#ifndef GL_SGIX_framezoom +#define GL_SGIX_framezoom 1 +#define GL_FRAMEZOOM_SGIX 0x818B +#define GL_FRAMEZOOM_FACTOR_SGIX 0x818C +#define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D +typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFrameZoomSGIX (GLint factor); +#endif +#endif /* GL_SGIX_framezoom */ + +#ifndef GL_SGIX_igloo_interface +#define GL_SGIX_igloo_interface 1 +typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const void *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const void *params); +#endif +#endif /* GL_SGIX_igloo_interface */ + +#ifndef GL_SGIX_instruments +#define GL_SGIX_instruments 1 +#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 +#define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 +typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void); +typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer); +typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p); +typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker); +typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void); +typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLint APIENTRY glGetInstrumentsSGIX (void); +GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei size, GLint *buffer); +GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *marker_p); +GLAPI void APIENTRY glReadInstrumentsSGIX (GLint marker); +GLAPI void APIENTRY glStartInstrumentsSGIX (void); +GLAPI void APIENTRY glStopInstrumentsSGIX (GLint marker); +#endif +#endif /* GL_SGIX_instruments */ + +#ifndef GL_SGIX_interlace +#define GL_SGIX_interlace 1 +#define GL_INTERLACE_SGIX 0x8094 +#endif /* GL_SGIX_interlace */ + +#ifndef GL_SGIX_ir_instrument1 +#define GL_SGIX_ir_instrument1 1 +#define GL_IR_INSTRUMENT1_SGIX 0x817F +#endif /* GL_SGIX_ir_instrument1 */ + +#ifndef GL_SGIX_list_priority +#define GL_SGIX_list_priority 1 +#define GL_LIST_PRIORITY_SGIX 0x8182 +typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params); +GLAPI void APIENTRY glListParameterfSGIX (GLuint list, GLenum pname, GLfloat param); +GLAPI void APIENTRY glListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glListParameteriSGIX (GLuint list, GLenum pname, GLint param); +GLAPI void APIENTRY glListParameterivSGIX (GLuint list, GLenum pname, const GLint *params); +#endif +#endif /* GL_SGIX_list_priority */ + +#ifndef GL_SGIX_pixel_texture +#define GL_SGIX_pixel_texture 1 +#define GL_PIXEL_TEX_GEN_SGIX 0x8139 +#define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B +typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTexGenSGIX (GLenum mode); +#endif +#endif /* GL_SGIX_pixel_texture */ + +#ifndef GL_SGIX_pixel_tiles +#define GL_SGIX_pixel_tiles 1 +#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E +#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F +#define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 +#define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 +#define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 +#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 +#define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 +#define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 +#endif /* GL_SGIX_pixel_tiles */ + +#ifndef GL_SGIX_polynomial_ffd +#define GL_SGIX_polynomial_ffd 1 +#define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 +#define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 +#define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 +#define GL_TEXTURE_DEFORMATION_SGIX 0x8195 +#define GL_DEFORMATIONS_MASK_SGIX 0x8196 +#define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 +typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); +typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); +typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); +GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); +GLAPI void APIENTRY glDeformSGIX (GLbitfield mask); +GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield mask); +#endif +#endif /* GL_SGIX_polynomial_ffd */ + +#ifndef GL_SGIX_reference_plane +#define GL_SGIX_reference_plane 1 +#define GL_REFERENCE_PLANE_SGIX 0x817D +#define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E +typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *equation); +#endif +#endif /* GL_SGIX_reference_plane */ + +#ifndef GL_SGIX_resample +#define GL_SGIX_resample 1 +#define GL_PACK_RESAMPLE_SGIX 0x842E +#define GL_UNPACK_RESAMPLE_SGIX 0x842F +#define GL_RESAMPLE_REPLICATE_SGIX 0x8433 +#define GL_RESAMPLE_ZERO_FILL_SGIX 0x8434 +#define GL_RESAMPLE_DECIMATE_SGIX 0x8430 +#endif /* GL_SGIX_resample */ + +#ifndef GL_SGIX_scalebias_hint +#define GL_SGIX_scalebias_hint 1 +#define GL_SCALEBIAS_HINT_SGIX 0x8322 +#endif /* GL_SGIX_scalebias_hint */ + +#ifndef GL_SGIX_shadow +#define GL_SGIX_shadow 1 +#define GL_TEXTURE_COMPARE_SGIX 0x819A +#define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B +#define GL_TEXTURE_LEQUAL_R_SGIX 0x819C +#define GL_TEXTURE_GEQUAL_R_SGIX 0x819D +#endif /* GL_SGIX_shadow */ + +#ifndef GL_SGIX_shadow_ambient +#define GL_SGIX_shadow_ambient 1 +#define GL_SHADOW_AMBIENT_SGIX 0x80BF +#endif /* GL_SGIX_shadow_ambient */ + +#ifndef GL_SGIX_sprite +#define GL_SGIX_sprite 1 +#define GL_SPRITE_SGIX 0x8148 +#define GL_SPRITE_MODE_SGIX 0x8149 +#define GL_SPRITE_AXIS_SGIX 0x814A +#define GL_SPRITE_TRANSLATION_SGIX 0x814B +#define GL_SPRITE_AXIAL_SGIX 0x814C +#define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D +#define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E +typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum pname, GLfloat param); +GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum pname, GLint param); +GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum pname, const GLint *params); +#endif +#endif /* GL_SGIX_sprite */ + +#ifndef GL_SGIX_subsample +#define GL_SGIX_subsample 1 +#define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 +#define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 +#define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 +#define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 +#define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 +#endif /* GL_SGIX_subsample */ + +#ifndef GL_SGIX_tag_sample_buffer +#define GL_SGIX_tag_sample_buffer 1 +typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTagSampleBufferSGIX (void); +#endif +#endif /* GL_SGIX_tag_sample_buffer */ + +#ifndef GL_SGIX_texture_add_env +#define GL_SGIX_texture_add_env 1 +#define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE +#endif /* GL_SGIX_texture_add_env */ + +#ifndef GL_SGIX_texture_coordinate_clamp +#define GL_SGIX_texture_coordinate_clamp 1 +#define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 +#define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A +#define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B +#endif /* GL_SGIX_texture_coordinate_clamp */ + +#ifndef GL_SGIX_texture_lod_bias +#define GL_SGIX_texture_lod_bias 1 +#define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E +#define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F +#define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 +#endif /* GL_SGIX_texture_lod_bias */ + +#ifndef GL_SGIX_texture_multi_buffer +#define GL_SGIX_texture_multi_buffer 1 +#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E +#endif /* GL_SGIX_texture_multi_buffer */ + +#ifndef GL_SGIX_texture_scale_bias +#define GL_SGIX_texture_scale_bias 1 +#define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 +#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A +#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B +#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C +#endif /* GL_SGIX_texture_scale_bias */ + +#ifndef GL_SGIX_vertex_preclip +#define GL_SGIX_vertex_preclip 1 +#define GL_VERTEX_PRECLIP_SGIX 0x83EE +#define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF +#endif /* GL_SGIX_vertex_preclip */ + +#ifndef GL_SGIX_ycrcb +#define GL_SGIX_ycrcb 1 +#define GL_YCRCB_422_SGIX 0x81BB +#define GL_YCRCB_444_SGIX 0x81BC +#endif /* GL_SGIX_ycrcb */ + +#ifndef GL_SGIX_ycrcb_subsample +#define GL_SGIX_ycrcb_subsample 1 +#endif /* GL_SGIX_ycrcb_subsample */ + +#ifndef GL_SGIX_ycrcba +#define GL_SGIX_ycrcba 1 +#define GL_YCRCB_SGIX 0x8318 +#define GL_YCRCBA_SGIX 0x8319 +#endif /* GL_SGIX_ycrcba */ + +#ifndef GL_SGI_color_matrix +#define GL_SGI_color_matrix 1 +#define GL_COLOR_MATRIX_SGI 0x80B1 +#define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 +#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 +#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 +#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 +#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 +#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 +#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 +#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 +#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA +#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB +#endif /* GL_SGI_color_matrix */ + +#ifndef GL_SGI_color_table +#define GL_SGI_color_table 1 +#define GL_COLOR_TABLE_SGI 0x80D0 +#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 +#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 +#define GL_PROXY_COLOR_TABLE_SGI 0x80D3 +#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 +#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 +#define GL_COLOR_TABLE_SCALE_SGI 0x80D6 +#define GL_COLOR_TABLE_BIAS_SGI 0x80D7 +#define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 +#define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 +#define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA +#define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB +#define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC +#define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD +#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE +#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF +typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, void *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); +GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, void *table); +GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params); +#endif +#endif /* GL_SGI_color_table */ + +#ifndef GL_SGI_texture_color_table +#define GL_SGI_texture_color_table 1 +#define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC +#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD +#endif /* GL_SGI_texture_color_table */ + +#ifndef GL_SUNX_constant_data +#define GL_SUNX_constant_data 1 +#define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 +#define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 +typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFinishTextureSUNX (void); +#endif +#endif /* GL_SUNX_constant_data */ + +#ifndef GL_SUN_convolution_border_modes +#define GL_SUN_convolution_border_modes 1 +#define GL_WRAP_BORDER_SUN 0x81D4 +#endif /* GL_SUN_convolution_border_modes */ + +#ifndef GL_SUN_global_alpha +#define GL_SUN_global_alpha 1 +#define GL_GLOBAL_ALPHA_SUN 0x81D9 +#define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte factor); +GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort factor); +GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint factor); +GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat factor); +GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble factor); +GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte factor); +GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort factor); +GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint factor); +#endif +#endif /* GL_SUN_global_alpha */ + +#ifndef GL_SUN_mesh_array +#define GL_SUN_mesh_array 1 +#define GL_QUAD_MESH_SUN 0x8614 +#define GL_TRIANGLE_MESH_SUN 0x8615 +typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width); +#endif +#endif /* GL_SUN_mesh_array */ + +#ifndef GL_SUN_slice_accum +#define GL_SUN_slice_accum 1 +#define GL_SLICE_ACCUM_SUN 0x85CC +#endif /* GL_SUN_slice_accum */ + +#ifndef GL_SUN_triangle_list +#define GL_SUN_triangle_list 1 +#define GL_RESTART_SUN 0x0001 +#define GL_REPLACE_MIDDLE_SUN 0x0002 +#define GL_REPLACE_OLDEST_SUN 0x0003 +#define GL_TRIANGLE_LIST_SUN 0x81D7 +#define GL_REPLACEMENT_CODE_SUN 0x81D8 +#define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 +#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 +#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 +#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 +#define GL_R1UI_V3F_SUN 0x85C4 +#define GL_R1UI_C4UB_V3F_SUN 0x85C5 +#define GL_R1UI_C3F_V3F_SUN 0x85C6 +#define GL_R1UI_N3F_V3F_SUN 0x85C7 +#define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 +#define GL_R1UI_T2F_V3F_SUN 0x85C9 +#define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA +#define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const void **pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code); +GLAPI void APIENTRY glReplacementCodeusSUN (GLushort code); +GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code); +GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code); +GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code); +GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code); +GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const void **pointer); +#endif +#endif /* GL_SUN_triangle_list */ + +#ifndef GL_SUN_vertex +#define GL_SUN_vertex 1 +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); +GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v); +GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v); +GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +#endif +#endif /* GL_SUN_vertex */ + +#ifndef GL_WIN_phong_shading +#define GL_WIN_phong_shading 1 +#define GL_PHONG_WIN 0x80EA +#define GL_PHONG_HINT_WIN 0x80EB +#endif /* GL_WIN_phong_shading */ + +#ifndef GL_WIN_specular_fog +#define GL_WIN_specular_fog 1 +#define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC +#endif /* GL_WIN_specular_fog */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/engine/code/glqnotes.txt b/engine/code/glqnotes.txt new file mode 100644 index 0000000..2224072 --- /dev/null +++ b/engine/code/glqnotes.txt @@ -0,0 +1,171 @@ +Glquake v0.99, Quake v1.09 release notes + +3dfx owners -- read the 3dfx.txt file. + +On a standard OpenGL system, all you should need to do to run glquake is put +glquake.exe in your quake directory, and run it from there. DO NOT install +the opengl32.dll unless you have a 3dfx! Glquake should change the screen +resolution to 640*480*32k colors and run full screen by default. + +If you are running win-95, your desktop must be set to 32k or 64k colors +before running glquake. NT can switch automatically. + +Theoretically, glquake will run on any compliant OpenGL that supports the +texture objects extensions, but unless it is very powerfull hardware that +accelerates everything needed, the game play will not be acceptable. If it +has to go through any software emulation paths, the performance will likely +by well under one frame per second. + +3dfx has provided an opengl32.dll that implements everything glquake needs, +but it is not a full opengl implementation. Other opengl applications are +very unlikely to work with it, so consider it basically a "glquake driver". +See the encluded 3dfx.txt for specific instalation notes. 3dfx can only run +full screen, but you must still have your desktop set to a 16 bit color mode +for glquake to start. + +resolution options +------------------ +We had dynamic resolution changing in glquake for a while, but every single +opengl driver I tried it on messed up in one way or another, so it is now +limited to startup time only. + +glquake -window +This will start glquake in a window on your desktop instead of switching the +screen to lower resolution and covering everything. + +glquake -width 800 -height 600 +Tries to run glquake at the specified resolution. Combined with -window, it +creates a desktop window that size, otherwise it tries to set a full screen +resolution. + +You can also specify the resolution of the console independant of the screen +resolution. + +glquake -conwidth 320 +This will specify a console resolution of 320 by 240 (the height is +automatically determined by the default 4:3 aspect ratio, you can also +specify the height directly with -conheight). + +In higher resolution modes such as 800x600 and 1024x768, glquake will default +to a 640x480 console, since the font becomes small enough at higher +resolutions to become unreadable. If do you wish to have a higher resolution +console and status bar, specify it as well, such as: +glquake -width 800 -height 600 -conwidth 800 + +texture options +--------------- +The amount of textures used in the game can have a large impact on performance. +There are several options that let you trade off visual quality for better +performance. + +There is no way to flush already loaded textures, so it is best to change +these options on the command line, or they will only take effect on some of +the textures when you change levels. + +OpenGL only allows textures to repeat on power of two boundaries (32, 64, +128, etc), but software quake had a number of textures that repeated at 24 +or 96 pixel boundaries. These need to be either stretched out to the next +higher size, or shrunk down to the next lower. By default, they are filtered +down to the smaller size, but you can cause it to use the larger size if you +really want by using: + +glquake +gl_round_down 0 +This will generally run well on a normal 4 MB 3dfx card, but for other cards +that have either worse texture management or slower texture swapping speeds, +there are some additional settings that can drastically lower the amount of +textures to be managed. + +glquake +gl_picmip 1 +This causes all textures to have one half the dimensions they otherwise would. +This makes them blurry, but very small. You can set this to 2 to make the +textures one quarter the resolution on each axis for REALLY blurry textures. + +glquake +gl_playermip 1 +This is similar to picmip, but is only used for other players in deathmatch. +Each player in a deathmatch requires an individual skin texture, so this can +be a serious problem for texture management. It wouldn't be unreasonable to +set this to 2 or even 3 if you are playing competatively (and don't care if +the other guys have smudged skins). If you change this during the game, it +will take effect as soon as a player changes their skin colors. + +GLQuake also supports the following extensions for faster texture operation: + +GL_SGIS_multitexture +Multitextures support allows certain hardware to render the world in one +pass instead of two. GLQuake uses two passes, one for the world textures +and the second for the lightmaps that are blended on the textures. On some +hardware, with a GL_SIGS_multitexture supported OpenGL implementation, this +can be done in one pass. On hardware that supports this, you will get a +60% to 100% increase in frame rate. Currently, only 3DFX dual TMU cards +(such as the Obsidian 2220) support this extension, but other hardware will +soon follow. + +This extension will be autodetected and used. If for some reason it is not +working correctly, specify the command line option "-nomtex" to disable it. + +GL_EXT_shared_texture_palette +GLQuake uses 16bit textures by default but on OpenGL implementations +that support the GL_EXT_shared_texture_palette extension, GLQuake will use +8bit textures instead. This results in using half the needed texture memory +of 16bit texture and can improve performance. This is very little difference +in visual quality due to the fact that the textures are 8bit sources to +begin with. + +run time options +---------------- +At the console, you can set these values to effect drawing. + +gl_texturemode GL_NEAREST +Sets texture mapping to point sampled, which may be faster on some GL systems +(not on 3dfx). + +gl_texturemode GL_LINEAR_MIPMAP +This is the default texture mode. + +gl_texturemode GL_LINEAR_MIPMAP_LINEAR +This is the highest quality texture mapping (trilinear), but only very high +end hardware (intergraph intense 3D / realizm) supports it. Not that big of +a deal, actually. + +gl_finish 0 +This causes the game to not issue a glFinish() call each frame, which may make +some hardware run faster. If this is cleared, the 3dfx will back up a number +of frames and not be very playable. + +gl_flashblend 0 +By default, glquake just draws a shaded ball around objects that are emiting +light. Clearing this variable will cause it to properly relight the world +like normal quake, but it can be a significant speed hit on some systems. + +gl_ztrick 0 +Glquake uses a buffering method that avoids clearing the Z buffer, but some +hardware platforms don't like it. If the status bar and console are flashing +every other frame, clear this variable. + +gl_keeptjunctions 0 +If you clear this, glquake will remove colinear vertexes when it reloads the +level. This can give a few percent speedup, but it can leave a couple stray +blinking pixels on the screen. + +novelty features +---------------- +These are some rendering tricks that were easy to do in glquake. They aren't +very robust, but they are pretty cool to look at. + +r_shadows 1 +This causes every object to cast a shadow. + +r_wateralpha 0.7 +This sets the opacity of water textures, so you can see through it in properly +processed maps. 0.3 is very faint, almost like fog. 1 is completely solid +(the default). Unfortunately, the standard quake maps don't contain any +visibility information for seeing past water surfaces, so you can't just play +quake with this turned on. If you just want to see what it looks like, you +can set "r_novis 1", but that will make things go very slow. When I get a +chance, I will probably release some maps that have been processed properly +for this. + +r_mirroralpha 0.3 +This changes one particular texture (the stained glass texture in the EASY +start hall) into a mirror. The value is the opacity of the mirror surface. + diff --git a/engine/code/glquake.h b/engine/code/glquake.h new file mode 100644 index 0000000..48217f1 --- /dev/null +++ b/engine/code/glquake.h @@ -0,0 +1,358 @@ +/* +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. + +*/ +// disable data conversion warnings + +#pragma warning(disable : 4244) // MIPS +#pragma warning(disable : 4136) // X86 +#pragma warning(disable : 4051) // ALPHA + +#ifdef _WIN32 +#include +#endif + +#include +#include + +#include "glext.h" // jkrige - opengl extensions +#include "wglext.h" // jkrige - windows opengl extensions + + +void GL_BeginRendering (int *x, int *y, int *width, int *height); +void GL_EndRendering (void); + + +#ifdef _WIN32 +// Function prototypes for the Texture Object Extension routines +typedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *, + const GLboolean *); +typedef void (APIENTRY *BINDTEXFUNCPTR)(GLenum, GLuint); +typedef void (APIENTRY *DELTEXFUNCPTR)(GLsizei, const GLuint *); +typedef void (APIENTRY *GENTEXFUNCPTR)(GLsizei, GLuint *); +typedef GLboolean (APIENTRY *ISTEXFUNCPTR)(GLuint); +typedef void (APIENTRY *PRIORTEXFUNCPTR)(GLsizei, const GLuint *, + const GLclampf *); +typedef void (APIENTRY *TEXSUBIMAGEPTR)(int, int, int, int, int, int, int, int, void *); + +extern BINDTEXFUNCPTR bindTexFunc; +extern DELTEXFUNCPTR delTexFunc; +extern TEXSUBIMAGEPTR TexSubImage2DFunc; +#endif + + +// jkrige - moved to glquake.h +typedef struct +{ + int texnum; + + qboolean tex_luma; // jkrige - luma textures + qboolean tex_luma8bit; // jkrige - fullbright pixels + + char identifier[64]; + int width, height; + qboolean mipmap; + int lhcsum; // jkrige - memleak & texture mismatch +} gltexture_t; + +//#define MAX_GLTEXTURES 2048 +#define MAX_GLTEXTURES 4096 // jkrige - increased maximum number of opengl textures +// jkrige - moved to glquake.h + + +extern gltexture_t gltextures[MAX_GLTEXTURES]; +extern int numgltextures; + +// jkrige - luma textures +#define JK_LUMA_TEX (MAX_GLTEXTURES) +// jkrige - luma textures + +extern int texture_extension_number; +extern int texture_mode; + +extern float gldepthmin, gldepthmax; + + +// jkrige - gamma +extern BOOL ( WINAPI * qwglGetDeviceGammaRamp3DFX)( HDC, LPVOID ); +extern BOOL ( WINAPI * qwglSetDeviceGammaRamp3DFX)( HDC, LPVOID ); +// jkrige - gamma + + +// jkrige - anisotropic filtering +extern qboolean anisotropic_ext; +extern float maximumAnisotrophy; +// jkrige - anisotropic filtering + + +// jkrige - non power of two +extern qboolean npow2_ext; +// jkrige - non power of two + + +void GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap, qboolean alpha); +void GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean alpha); + +// jkrige - bytesperpixel +//int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha); +int GL_LoadTexture (char *identifier, char *textype, int width, int height, byte *data, int mipmap, int alpha, int bytesperpixel); +// jkrige - bytesperpixel + +int GL_FindTexture (char *identifier); + +// jkrige - .lit colored lights +void GL_SetupLightmapFmt (qboolean check_cmdline); +// jkrige - .lit colored lights + +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; + +// jkrige - opengl extensions +//#ifdef _WIN32 +//extern PROC glArrayElementEXT; +//extern PROC glColorPointerEXT; +//extern PROC glTexturePointerEXT; +//extern PROC glVertexPointerEXT; +//#endif +// jkrige - opengl extensions + +// 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); + +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 entity_t r_worldentity; +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]; +extern int c_brush_polys, c_alias_polys; + + +// +// 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 texture_t *r_notexture_mip; +extern int d_lightstylevalue[256]; // 8.8 fraction of base light value + +extern qboolean envmap; +extern int currenttexture; +extern int cnttextures[2]; + +// jkrige - texture mode +extern int particletexture_linear; +extern int particletexture_point; +// jkrige - texture mode + +extern int playertextures; + +extern int skytexturenum; // index in cl.loadmodel, not gl texture object + +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; // jkrige - removed alias shadows +extern cvar_t r_mirroralpha; +extern cvar_t r_wateralpha; +extern cvar_t r_dynamic; +extern cvar_t r_novis; + +// jkrige - fix dynamic light shine through +extern cvar_t r_dynamic_sidemark; +// jkrige - fix dynamic light shine through + +extern cvar_t gl_clear; +extern cvar_t gl_cull; +extern cvar_t gl_poly; +extern cvar_t gl_texsort; +extern cvar_t gl_smoothmodels; +extern cvar_t gl_affinemodels; +extern cvar_t gl_polyblend; + +// jkrige - disabled tjunction removal +//extern cvar_t gl_keeptjunctions; +//extern cvar_t gl_reporttjunctions; +// jkrige - disabled tjunction removal + +// jkrige - flashblend removal +//extern cvar_t gl_flashblend; +// jkrige - flashblend removal + +extern cvar_t gl_nocolors; +extern cvar_t gl_skytype; // jkrige - skybox +extern cvar_t gl_doubleeyes; + +// jkrige - .lit colored lights +extern int gl_coloredstatic; +// jkrige - .lit colored lights + +extern int gl_lightmap_format; +extern int gl_solid_format; +extern int gl_alpha_format; + +extern cvar_t gl_max_size; +extern cvar_t gl_playermip; + +// jkrige - texture mode +extern cvar_t gl_texturemode; +// jkrige - texture mode + +// jkrige - wireframe +extern cvar_t gl_wireframe; +// jkrige - wireframe + +// jkrige - .lit colored lights +extern cvar_t gl_coloredlight; +extern cvar_t gl_lightmapfmt; +// jkrige - .lit colored lights + +// jkrige - luma textures +extern cvar_t gl_lumatex_render; +// jkrige - luma textures + + +extern int mirrortexturenum; // quake texturenum, not gltexturenum +extern qboolean mirror; +extern mplane_t *mirror_plane; + +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 GL_Bind (int texnum); + +// Multitexture +// jkrige - remove multitexture +//#define TEXTURE0_SGIS 0x835E +//#define TEXTURE1_SGIS 0x835F +// jkrige - remove multitexture + +#ifndef _WIN32 +#define APIENTRY /* */ +#endif + +// jkrige - overbrights +extern cvar_t gl_overbright; +// jkrige - overbrights + +// jkrige - remove multitexture +/*typedef void (APIENTRY *lpMTexFUNC) (GLenum, GLfloat, GLfloat); +typedef void (APIENTRY *lpSelTexFUNC) (GLenum); +extern lpMTexFUNC qglMTexCoord2fSGIS; +extern lpSelTexFUNC qglSelectTextureSGIS; + +extern qboolean gl_mtexable; + +void GL_DisableMultitexture(void); +void GL_EnableMultitexture(void);*/ +// jkrige - remove multitexture diff --git a/engine/code/host.c b/engine/code/host.c new file mode 100644 index 0000000..88b076f --- /dev/null +++ b/engine/code/host.c @@ -0,0 +1,1040 @@ +/* +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. + +*/ +// host.c -- coordinates spawning and killing of local servers + +#include "quakedef.h" +//#include "r_local.h" // jkrige - removed + +/* + +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_basepal; +byte *host_colormap; + +// jkrige - configurable fps caps +extern cvar_t sv_fps; +// jkrige - configurable fps caps + +cvar_t host_framerate = {"host_framerate","0"}; // set for slow motion +cvar_t host_speeds = {"host_speeds","0"}; // set for running times + +// jkrige - configurable fps caps +// defaults to 0 since sv_fps takes care of framerate +cvar_t sys_ticrate = {"sys_ticrate","0"}; +//cvar_t sys_ticrate = {"sys_ticrate","0.05"}; +// jkrige - configurable fps caps + +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}; + +#ifdef QUAKE2 +cvar_t developer = {"developer","1"}; // should be 0 for release! +#else +cvar_t developer = {"developer","0"}; +#endif + +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 temp1 = {"temp1","0"}; + + +// jkrige - fps counter +cvar_t r_fps = {"r_fps","0",true}; +int fps_count; +// jkrige - fps counter + + +/* +================ +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; + + 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); + Cvar_RegisterVariable (&host_speeds); + + Cvar_RegisterVariable (&sys_ticrate); + Cvar_RegisterVariable (&serverprofile); + + Cvar_RegisterVariable (&fraglimit); + Cvar_RegisterVariable (&timelimit); + Cvar_RegisterVariable (&teamplay); + Cvar_RegisterVariable (&samelevel); + Cvar_RegisterVariable (&noexit); + Cvar_RegisterVariable (&skill); + Cvar_RegisterVariable (&developer); + Cvar_RegisterVariable (&deathmatch); + Cvar_RegisterVariable (&coop); + + Cvar_RegisterVariable (&pausable); + + Cvar_RegisterVariable (&temp1); + + Cvar_RegisterVariable (&r_fps); // jkrige - fps counter + + 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; + } + + Key_WriteBindings (f); + Cvar_WriteVariables (f); + + fclose (f); + } +} + + +/* +================= +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_FilterTime + +Returns false if the time is too short to run a frame +=================== +*/ +qboolean Host_FilterTime (float time) +{ + // jkrige - configurable fps caps + static double min_frametime; + // jkrige - configurable fps caps + + realtime += time; + + + // jkrige - configurable fps caps + // added configurable fps caps, different for dedicated and + // listen servers. Listen servers run at 72 fps by default, + // dedicated ones at 20. + if (cls.state != ca_dedicated) + { + min_frametime = 1.0 / cl_maxfps.value; + } + else + { + min_frametime = 1.0 / sv_fps.value; + } + + // Avoid infinite loop + if (min_frametime > 1) + { + min_frametime = 1.0; + } + if ((realtime - oldrealtime < min_frametime) && !cls.timedemo) + { + // Keep the CPU cool for the remainder of time, rather than run + // a loop delay. And always keep a slack of 15% of frametime for + // ouselves, so that we don't "oversleep" our next frame. + if (realtime - oldrealtime < 0.80 * min_frametime) + { + Sys_LongSleep((0.85 * min_frametime - (realtime - oldrealtime)) * 1000.0); + } + return false; + } + + //if (!cls.timedemo && realtime - oldrealtime < 1.0/72.0) + // return false; // framerate is too high + // jkrige - configurable fps caps + + host_frametime = realtime - oldrealtime; + oldrealtime = realtime; + + if (host_framerate.value > 0) + host_frametime = host_framerate.value; + else + { // don't allow really long or short frames + if (host_frametime > 0.1) + host_frametime = 0.1; + + // jkrige - configurable fps caps + // short frames should better be allowed now; it seems + // that 1000 fps is in fact attainable nowadays, and we + // got rid of framerate cap + //if (host_frametime < 0.001) + // host_frametime = 0.001; + // jkrige - configurable fps caps + } + + 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 + +================== +*/ +#ifdef FPS_20 + +void _Host_ServerFrame (void) +{ +// run the world state + pr_global_struct->frametime = host_frametime; + +// 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 (); +} + +void Host_ServerFrame (void) +{ + float save_host_frametime; + float temp_host_frametime; + +// 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 (); + + temp_host_frametime = save_host_frametime = host_frametime; + while(temp_host_frametime > (1.0/72.0)) + { + if (temp_host_frametime > 0.05) + host_frametime = 0.05; + else + host_frametime = temp_host_frametime; + temp_host_frametime -= host_frametime; + _Host_ServerFrame (); + } + host_frametime = save_host_frametime; + +// send all messages to the clients + SV_SendClientMessages (); +} + +#else + +void Host_ServerFrame (void) +{ +// 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 (); + +// send all messages to the clients + SV_SendClientMessages (); +} + +#endif + + +/* +================== +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 (); + +// 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 (); + + 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); + + // jkrige - fmod sound system - begin +#ifdef UQE_FMOD + FMOD_MusicUpdate(NULL); +#else + CDAudio_Update(); +#endif + // jkrige - fmod sound system - end + + 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++; + + fps_count++; // jkrige - fps counter +} + +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 ; iargv[0]; + for (i = 0; i < com_argc; i++) + { + Sys_FileRead (vcrFile, &len, sizeof(int)); + p = malloc(len); + Sys_FileRead (vcrFile, p, len); + com_argv[i+1] = p; + } + com_argc++; /* add one for arg[0] */ + parms->argc = com_argc; + parms->argv = com_argv; + } + + if ( (n = COM_CheckParm("-record")) != 0) + { + vcrFile = Sys_FileOpenWrite("quake.vcr"); + + i = VCR_SIGNATURE; + Sys_FileWrite(vcrFile, &i, sizeof(int)); + i = com_argc - 1; + Sys_FileWrite(vcrFile, &i, sizeof(int)); + for (i = 1; i < com_argc; i++) + { + if (i == n) + { + len = 10; + Sys_FileWrite(vcrFile, &len, sizeof(int)); + Sys_FileWrite(vcrFile, "-playback", len); + continue; + } + len = Q_strlen(com_argv[i]) + 1; + Sys_FileWrite(vcrFile, &len, sizeof(int)); + Sys_FileWrite(vcrFile, com_argv[i], len); + } + } + +} + +/* +==================== +Host_Init +==================== +*/ +void Host_Init (quakeparms_t *parms) +{ + + if (standard_quake) + minimum_memory = MINIMUM_MEMORY; + else + minimum_memory = MINIMUM_MEMORY_LEVELPAK; + + if (COM_CheckParm ("-minmemory")) + parms->memsize = 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 (); + V_Init (); + + // jkrige - removed chase + //Chase_Init (); + // jkrige - removed chase + + Host_InitVCR (parms); + COM_Init (parms->basedir); + Host_InitLocal (); + W_LoadWadFile ("gfx.wad"); + Key_Init (); + Con_Init (); + M_Init (); + PR_Init (); + Mod_Init (); + NET_Init (); + SV_Init (); + + Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); + Con_Printf ("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0)); + + R_InitTextures (); // needed even for dedicated servers + + if (cls.state != ca_dedicated) + { + host_basepal = (byte *)COM_LoadHunkFile ("gfx/palette.lmp"); + if (!host_basepal) + Sys_Error ("Couldn't load gfx/palette.lmp"); + host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp"); + if (!host_colormap) + Sys_Error ("Couldn't load gfx/colormap.lmp"); + +#ifndef _WIN32 // on non win32, mouse comes before video for security reasons + IN_Init (); +#endif + VID_Init (host_basepal); + + Draw_Init (); + SCR_Init (); + R_Init (); +#ifndef _WIN32 + // on Win32, sound initialization has to come before video initialization, so we + // can put up a popup if the sound hardware is in use + S_Init (); +#else + +#ifdef GLQUAKE + // FIXME: doesn't use the new one-window approach yet + S_Init (); +#endif + +#endif // _WIN32 + + //CDAudio_Init (); // jkrige - fmod sound system + + Sbar_Init (); + CL_Init (); +#ifdef _WIN32 // on non win32, mouse comes before video for security reasons + IN_Init (); +#endif + } + + Cbuf_InsertText ("exec quake.rc\n"); + + Hunk_AllocName (0, "-HOST_HUNKLEVEL-"); + host_hunklevel = Hunk_LowMark (); + + host_initialized = true; + + Sys_Printf ("========Quake Initialized=========\n"); +} + + +/* +=============== +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 (); // jkrige - fmod sound system + + NET_Shutdown (); + + // jkrige - fmod sound system - begin +#ifdef UQE_FMOD + FMOD_Shutdown(); +#else + CDAudio_Shutdown(); +#endif + // jkrige - fmod sound system - end + + S_Shutdown(); + IN_Shutdown (); + + if (cls.state != ca_dedicated) + { + VID_Shutdown(); + } +} + diff --git a/engine/code/host_cmd.c b/engine/code/host_cmd.c new file mode 100644 index 0000000..485321b --- /dev/null +++ b/engine/code/host_cmd.c @@ -0,0 +1,1935 @@ +/* +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. + +*/ + +#include "quakedef.h" + +extern cvar_t pausable; + +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 (); +} + + +/* +================== +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", QUAKE_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; + + 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"); +} + +void Host_Notarget_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + 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"); +} + +qboolean noclip_anglehack; + +void Host_Noclip_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + 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"); + } +} + +/* +================== +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; + + 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"); + } +} + + +/* +================== +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); + + 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; + } + + strcpy (level, Cmd_Argv(1)); + if (Cmd_Argc() == 2) + startspot = NULL; + else + { + strcpy (_startspot, Cmd_Argv(2)); + startspot = _startspot; + } + + SV_SaveSpawnparms (); + SV_SpawnServer (level, startspot); +#else + char level[MAX_QPATH]; + + if (Cmd_Argc() != 2) + { + Con_Printf ("changelevel : continue game on a new level\n"); + return; + } + if (!sv.active || cls.demoplayback) + { + Con_Printf ("Only the server may changelevel\n"); + return; + } + SV_SaveSpawnparms (); + strcpy (level, Cmd_Argv(1)); + SV_SpawnServer (level); +#endif +} + +/* +================== +Host_Restart_f + +Restarts the current server for a dead player +================== +*/ +void Host_Restart_f (void) +{ + char mapname[MAX_QPATH]; +#ifdef QUAKE2 + char startspot[MAX_QPATH]; +#endif + + 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 +#ifdef QUAKE2 + strcpy(startspot, sv.startspot); + SV_SpawnServer (mapname, startspot); +#else + SV_SpawnServer (mapname); +#endif +} + +/* +================== +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; + } + } + + // jkrige - savegame directory + sprintf (name, "%s/saves", com_gamedir); + Sys_mkdir (name); + sprintf (name, "%s/saves/%s", com_gamedir, Cmd_Argv(1)); + //sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); + // jkrige - savegame directory + + 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 + + // jkrige - savegame directory + sprintf (name, "%s/saves/%s", com_gamedir, Cmd_Argv(1)); + //sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); + // jkrige - savegame directory + + 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 (); + } +} + +#ifdef QUAKE2 +void SaveGamestate() +{ + char name[256]; + FILE *f; + int i; + char comment[SAVEGAME_COMMENT_LENGTH+1]; + edict_t *ent; + + sprintf (name, "%s/%s.gip", com_gamedir, sv.name); + + 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, "%f\n", skill.value); + fprintf (f, "%s\n", sv.name); + fprintf (f, "%f\n", sv.time); + +// write the light styles + + for (i=0 ; iv.flags & FL_ARCHIVE_OVERRIDE) + continue; + fprintf (f, "%i\n",i); + ED_Write (f, ent); + fflush (f); + } + fclose (f); + Con_Printf ("done.\n"); +} + +int LoadGamestate(char *level, char *startspot) +{ + char name[MAX_OSPATH]; + FILE *f; + char mapname[MAX_QPATH]; + float time, sk; + char str[32768], *start; + int i, r; + edict_t *ent; + int entnum; + int version; +// float spawn_parms[NUM_SPAWN_PARMS]; + + sprintf (name, "%s/%s.gip", com_gamedir, level); + + Con_Printf ("Loading game from %s...\n", name); + f = fopen (name, "r"); + if (!f) + { + Con_Printf ("ERROR: couldn't open.\n"); + return -1; + } + + fscanf (f, "%i\n", &version); + if (version != SAVEGAME_VERSION) + { + fclose (f); + Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); + return -1; + } + 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); + } + +// sv.num_edicts = entnum; + sv.time = time; + fclose (f); + +// for (i=0 ; ispawn_parms[i] = spawn_parms[i]; + + return 0; +} + +// changing levels within a unit +void Host_Changelevel2_f (void) +{ + char level[MAX_QPATH]; + char _startspot[MAX_QPATH]; + char *startspot; + + if (Cmd_Argc() < 2) + { + Con_Printf ("changelevel2 : continue game on a new level in the unit\n"); + return; + } + if (!sv.active || cls.demoplayback) + { + Con_Printf ("Only the server may changelevel\n"); + return; + } + + strcpy (level, Cmd_Argv(1)); + if (Cmd_Argc() == 2) + startspot = NULL; + else + { + strcpy (_startspot, Cmd_Argv(2)); + startspot = _startspot; + } + + SV_SaveSpawnparms (); + + // save the current level's state + SaveGamestate (); + + // try to restore the new level + if (LoadGamestate (level, startspot)) + SV_SpawnServer (level, startspot); +} +#endif + + +//============================================================================ + +/* +====================== +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 ("Version %4.2f\n", QUAKE_VERSION); + Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); +} + +#ifdef IDGODS +void Host_Please_f (void) +{ + client_t *cl; + int j; + + if (cmd_source != src_command) + return; + + if ((Cmd_Argc () == 3) && Q_strcmp(Cmd_Argv(1), "#") == 0) + { + j = Q_atof(Cmd_Argv(2)) - 1; + if (j < 0 || j >= svs.maxclients) + return; + if (!svs.clients[j].active) + return; + cl = &svs.clients[j]; + if (cl->privileged) + { + cl->privileged = false; + cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET); + cl->edict->v.movetype = MOVETYPE_WALK; + noclip_anglehack = false; + } + else + cl->privileged = true; + } + + if (Cmd_Argc () != 2) + return; + + for (j=0, cl = svs.clients ; jactive) + continue; + if (Q_strcasecmp(cl->name, Cmd_Argv(1)) == 0) + { + if (cl->privileged) + { + cl->privileged = false; + cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET); + cl->edict->v.movetype = MOVETYPE_WALK; + noclip_anglehack = false; + } + else + cl->privileged = true; + break; + } + } +} +#endif + + +void Host_Say(qboolean teamonly) +{ + client_t *client; + client_t *save; + int j; + char *p; + unsigned 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, w; + 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; + } +} + +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 +#include "quakedef.h" +#include "winquake.h" +//#include "dosisms.h" // jkrige - removed + +//#define DINPUT_BUFFERSIZE 16 +//#define iDirectInputCreate(a,b,c,d) pDirectInputCreate(a,b,c,d) + +//HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUT * lplpDirectInput, LPUNKNOWN punkOuter); + +// mouse variables +// jkrige - configurable fps caps +// default to filtered now, to take advantage of higher default fps cap +// for smoother gameplay +cvar_t m_filter = {"m_filter","1", true}; +//cvar_t m_filter = {"m_filter","0"}; +// jkrige - configurable fps caps + +int mouse_buttons; +int mouse_oldbuttonstate; +POINT current_pos; +int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; + +static qboolean restore_spi; +static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; + +unsigned int uiWheelMessage; +qboolean mouseactive; +qboolean mouseinitialized; +static qboolean mouseparmsvalid, mouseactivatetoggle; +static qboolean mouseshowtoggle = 1; +static qboolean dinput_acquired; + + +// jkrige - mouse thumb buttons +static int buttonremap[] = +{ + K_MOUSE1, + K_MOUSE2, + K_MOUSE3, + K_MOUSE4, + K_MOUSE5 +}; // do NOT include the wheel enums +#define NUM_MOUSEBUTTONS (sizeof(buttonremap) / sizeof(buttonremap[0])) +// jkrige - mouse thumb buttons + + +static unsigned int mstate_di; + +// joystick defines and variables +// where should defines be moved? +#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick +#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball +#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V +#define JOY_AXIS_X 0 +#define JOY_AXIS_Y 1 +#define JOY_AXIS_Z 2 +#define JOY_AXIS_R 3 +#define JOY_AXIS_U 4 +#define JOY_AXIS_V 5 + +enum _ControlList +{ + AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn +}; + +DWORD dwAxisFlags[JOY_MAX_AXES] = +{ + JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV +}; + +DWORD dwAxisMap[JOY_MAX_AXES]; +DWORD dwControlMap[JOY_MAX_AXES]; +PDWORD pdwRawValue[JOY_MAX_AXES]; + +// none of these cvars are saved over a session +// this means that advanced controller configuration needs to be executed +// each time. this avoids any problems with getting back to a default usage +// or when changing from one controller to another. this way at least something +// works. +cvar_t in_joystick = {"joystick","1"}; +cvar_t joy_name = {"joyname", "joystick"}; +cvar_t joy_advanced = {"joyadvanced", "0"}; +cvar_t joy_advaxisx = {"joyadvaxisx", "0"}; +cvar_t joy_advaxisy = {"joyadvaxisy", "0"}; +cvar_t joy_advaxisz = {"joyadvaxisz", "0"}; +cvar_t joy_advaxisr = {"joyadvaxisr", "0"}; +cvar_t joy_advaxisu = {"joyadvaxisu", "0"}; +cvar_t joy_advaxisv = {"joyadvaxisv", "0"}; +cvar_t joy_forwardthreshold = {"joyforwardthreshold", "0.15"}; +cvar_t joy_sidethreshold = {"joysidethreshold", "0.15"}; +cvar_t joy_pitchthreshold = {"joypitchthreshold", "0.15"}; +cvar_t joy_yawthreshold = {"joyyawthreshold", "0.15"}; +cvar_t joy_forwardsensitivity = {"joyforwardsensitivity", "-1.0"}; +cvar_t joy_sidesensitivity = {"joysidesensitivity", "-1.0"}; +cvar_t joy_pitchsensitivity = {"joypitchsensitivity", "1.0"}; +cvar_t joy_yawsensitivity = {"joyyawsensitivity", "-1.0"}; +cvar_t joy_wwhack1 = {"joywwhack1", "0.0"}; +cvar_t joy_wwhack2 = {"joywwhack2", "0.0"}; + +qboolean joy_avail, joy_advancedinit, joy_haspov; +DWORD joy_oldbuttonstate, joy_oldpovstate; + +int joy_id; +DWORD joy_flags; +DWORD joy_numbuttons; + +//static LPDIRECTINPUT g_pdi; +//static LPDIRECTINPUTDEVICE g_pMouse; + +static JOYINFOEX ji; + +//static HINSTANCE hInstDI; + +//static qboolean dinput; + +/*typedef struct MYDATA { + LONG lX; // X axis goes here + LONG lY; // Y axis goes here + LONG lZ; // Z axis goes here + BYTE bButtonA; // One button goes here + BYTE bButtonB; // Another button goes here + BYTE bButtonC; // Another button goes here + BYTE bButtonD; // Another button goes here +} MYDATA; + +static DIOBJECTDATAFORMAT rgodf[] = { + { &GUID_XAxis, FIELD_OFFSET(MYDATA, lX), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, + { &GUID_YAxis, FIELD_OFFSET(MYDATA, lY), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, + { &GUID_ZAxis, FIELD_OFFSET(MYDATA, lZ), 0x80000000 | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, + { 0, FIELD_OFFSET(MYDATA, bButtonA), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, + { 0, FIELD_OFFSET(MYDATA, bButtonB), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, + { 0, FIELD_OFFSET(MYDATA, bButtonC), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, + { 0, FIELD_OFFSET(MYDATA, bButtonD), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, +}; + +#define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0])) + +static DIDATAFORMAT df = { + sizeof(DIDATAFORMAT), // this structure + sizeof(DIOBJECTDATAFORMAT), // size of object data format + DIDF_RELAXIS, // absolute axis coordinates + sizeof(MYDATA), // device data size + NUM_OBJECTS, // number of objects + rgodf, // and here they are +};*/ + +// forward-referenced functions +void IN_StartupJoystick (void); +void Joy_AdvancedUpdate_f (void); +void IN_JoyMove (usercmd_t *cmd); + + +/* +=========== +Force_CenterView_f +=========== +*/ +void Force_CenterView_f (void) +{ + cl.viewangles[PITCH] = 0; +} + + +/* +=========== +IN_UpdateClipCursor +=========== +*/ +void IN_UpdateClipCursor (void) +{ + + if (mouseinitialized && mouseactive /*&& !dinput*/) + { + ClipCursor (&window_rect); + } +} + + +/* +=========== +IN_ShowMouse +=========== +*/ +void IN_ShowMouse (void) +{ + + if (!mouseshowtoggle) + { + ShowCursor (TRUE); + mouseshowtoggle = 1; + } +} + + +/* +=========== +IN_HideMouse +=========== +*/ +void IN_HideMouse (void) +{ + + if (mouseshowtoggle) + { + ShowCursor (FALSE); + mouseshowtoggle = 0; + } +} + + +/* +=========== +IN_ActivateMouse +=========== +*/ +void IN_ActivateMouse (void) +{ + + mouseactivatetoggle = true; + + if (mouseinitialized) + { + /*if (dinput) + { + if (g_pMouse) + { + if (!dinput_acquired) + { + IDirectInputDevice_Acquire(g_pMouse); + dinput_acquired = true; + } + } + else + { + return; + } + } + else*/ + //{ + if (mouseparmsvalid) + restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0); + + SetCursorPos (window_center_x, window_center_y); + SetCapture (mainwindow); + ClipCursor (&window_rect); + //} + + mouseactive = true; + } +} + + +/* +=========== +IN_SetQuakeMouseState +=========== +*/ +void IN_SetQuakeMouseState (void) +{ + if (mouseactivatetoggle) + IN_ActivateMouse (); +} + + +/* +=========== +IN_DeactivateMouse +=========== +*/ +void IN_DeactivateMouse (void) +{ + + mouseactivatetoggle = false; + + if (mouseinitialized) + { + /*if (dinput) + { + if (g_pMouse) + { + if (dinput_acquired) + { + IDirectInputDevice_Unacquire(g_pMouse); + dinput_acquired = false; + } + } + } + else*/ + //{ + if (restore_spi) + SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); + + ClipCursor (NULL); + ReleaseCapture (); + //} + + mouseactive = false; + } +} + + +/* +=========== +IN_RestoreOriginalMouseState +=========== +*/ +void IN_RestoreOriginalMouseState (void) +{ + if (mouseactivatetoggle) + { + IN_DeactivateMouse (); + mouseactivatetoggle = true; + } + +// try to redraw the cursor so it gets reinitialized, because sometimes it +// has garbage after the mode switch + ShowCursor (TRUE); + ShowCursor (FALSE); +} + + +/* +=========== +IN_InitDInput +=========== +*/ +/*qboolean IN_InitDInput (void) +{ + HRESULT hr; + DIPROPDWORD dipdw = { + { + sizeof(DIPROPDWORD), // diph.dwSize + sizeof(DIPROPHEADER), // diph.dwHeaderSize + 0, // diph.dwObj + DIPH_DEVICE, // diph.dwHow + }, + DINPUT_BUFFERSIZE, // dwData + }; + + if (!hInstDI) + { + hInstDI = LoadLibrary("dinput.dll"); + + if (hInstDI == NULL) + { + Con_SafePrintf ("Couldn't load dinput.dll\n"); + return false; + } + } + + if (!pDirectInputCreate) + { + pDirectInputCreate = (void *)GetProcAddress(hInstDI,"DirectInputCreateA"); + + if (!pDirectInputCreate) + { + Con_SafePrintf ("Couldn't get DI proc addr\n"); + return false; + } + } + +// register with DirectInput and get an IDirectInput to play with. + hr = iDirectInputCreate(global_hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL); + + if (FAILED(hr)) + { + return false; + } + +// obtain an interface to the system mouse device. + hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL); + + if (FAILED(hr)) + { + Con_SafePrintf ("Couldn't open DI mouse device\n"); + return false; + } + +// set the data format to "mouse format". + hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df); + + if (FAILED(hr)) + { + Con_SafePrintf ("Couldn't set DI mouse format\n"); + return false; + } + +// set the cooperativity level. + hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, mainwindow, + DISCL_EXCLUSIVE | DISCL_FOREGROUND); + + if (FAILED(hr)) + { + Con_SafePrintf ("Couldn't set DI coop level\n"); + return false; + } + + +// set the buffer size to DINPUT_BUFFERSIZE elements. +// the buffer size is a DWORD property associated with the device + hr = IDirectInputDevice_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph); + + if (FAILED(hr)) + { + Con_SafePrintf ("Couldn't set DI buffersize\n"); + return false; + } + + return true; +}*/ + + +/* +=========== +IN_StartupMouse +=========== +*/ +void IN_StartupMouse (void) +{ + HDC hdc; + + if ( COM_CheckParm ("-nomouse") ) + return; + + mouseinitialized = true; + + /*if (COM_CheckParm ("-dinput")) + { + dinput = IN_InitDInput (); + + if (dinput) + { + Con_SafePrintf ("DirectInput initialized\n"); + } + else + { + Con_SafePrintf ("DirectInput not initialized\n"); + } + }*/ + + //if (!dinput) + //{ + mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0); + + if (mouseparmsvalid) + { + if ( COM_CheckParm ("-noforcemspd") ) + newmouseparms[2] = originalmouseparms[2]; + + if ( COM_CheckParm ("-noforcemaccel") ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + } + + if ( COM_CheckParm ("-noforcemparms") ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + newmouseparms[2] = originalmouseparms[2]; + } + } + //} + + mouse_buttons = 3; + +// if a fullscreen video mode was set before the mouse was initialized, +// set the mouse state appropriately + if (mouseactivatetoggle) + IN_ActivateMouse (); +} + + +/* +=========== +IN_Init +=========== +*/ +void IN_Init (void) +{ + // mouse variables + Cvar_RegisterVariable (&m_filter); + + // joystick variables + Cvar_RegisterVariable (&in_joystick); + Cvar_RegisterVariable (&joy_name); + Cvar_RegisterVariable (&joy_advanced); + Cvar_RegisterVariable (&joy_advaxisx); + Cvar_RegisterVariable (&joy_advaxisy); + Cvar_RegisterVariable (&joy_advaxisz); + Cvar_RegisterVariable (&joy_advaxisr); + Cvar_RegisterVariable (&joy_advaxisu); + Cvar_RegisterVariable (&joy_advaxisv); + Cvar_RegisterVariable (&joy_forwardthreshold); + Cvar_RegisterVariable (&joy_sidethreshold); + Cvar_RegisterVariable (&joy_pitchthreshold); + Cvar_RegisterVariable (&joy_yawthreshold); + Cvar_RegisterVariable (&joy_forwardsensitivity); + Cvar_RegisterVariable (&joy_sidesensitivity); + Cvar_RegisterVariable (&joy_pitchsensitivity); + Cvar_RegisterVariable (&joy_yawsensitivity); + Cvar_RegisterVariable (&joy_wwhack1); + Cvar_RegisterVariable (&joy_wwhack2); + + Cmd_AddCommand ("force_centerview", Force_CenterView_f); + Cmd_AddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f); + + uiWheelMessage = RegisterWindowMessage ( "MSWHEEL_ROLLMSG" ); + + IN_StartupMouse (); + IN_StartupJoystick (); +} + +/* +=========== +IN_Shutdown +=========== +*/ +void IN_Shutdown (void) +{ + + IN_DeactivateMouse (); + IN_ShowMouse (); + + /*if (g_pMouse) + { + IDirectInputDevice_Release(g_pMouse); + g_pMouse = NULL; + } + + if (g_pdi) + { + IDirectInput_Release(g_pdi); + g_pdi = NULL; + }*/ +} + + +/* +=========== +IN_MouseEvent +=========== +*/ +void IN_MouseEvent (int mstate) +{ + int i; + + if (mouseactive /*&& !dinput*/) // perform button actions + { + // jkrige - mouse thumb buttons + /*for (i=0 ; isidemove += m_side.value * mouse_x; + else + { + if (cl.time != cl.oldtime) // jkrige - mlook (don't mouselook when paused) + cl.viewangles[YAW] -= m_yaw.value * mouse_x; + } + + if (cl_mlook.value == 1.0 /*| lookspring.value == 0.0*/ /*in_mlook.state & 1*/) // jkrige - mlook cvar + V_StopPitchDrift (); + + if ( (cl_mlook.value /*in_mlook.state & 1*/) && !(in_strafe.state & 1)) // jkrige - mlook cvar + { + if (cl.time != cl.oldtime) // jkrige - mlook (don't mouselook when paused) + cl.viewangles[PITCH] += m_pitch.value * mouse_y; + + if (cl.viewangles[PITCH] > 80) + cl.viewangles[PITCH] = 80; + if (cl.viewangles[PITCH] < -70) + cl.viewangles[PITCH] = -70; + } + else + { + if ((in_strafe.state & 1) && noclip_anglehack) + cmd->upmove -= m_forward.value * mouse_y; + else + cmd->forwardmove -= m_forward.value * mouse_y; + } + +// if the mouse has moved, force it to the center, so there's room to move + if (mx || my) + { + SetCursorPos (window_center_x, window_center_y); + } +} + + +/* +=========== +IN_Move +=========== +*/ +void IN_Move (usercmd_t *cmd) +{ + + if (mouseactive) + { + IN_MouseMove (cmd); + } + + if (ActiveApp) + IN_JoyMove (cmd); + + /*if (ActiveApp && !Minimized) + { + IN_MouseMove (cmd); + IN_JoyMove (cmd); + }*/ +} + + +/* +=========== +IN_Accumulate +=========== +*/ +void IN_Accumulate (void) +{ + int mx, my; + HDC hdc; + + if (mouseactive) + { + //if (!dinput) + //{ + GetCursorPos (¤t_pos); + + mx_accum += current_pos.x - window_center_x; + my_accum += current_pos.y - window_center_y; + + // force the mouse to the center, so there's room to move + SetCursorPos (window_center_x, window_center_y); + //} + } +} + + +/* +=================== +IN_ClearStates +=================== +*/ +void IN_ClearStates (void) +{ + + if (mouseactive) + { + mx_accum = 0; + my_accum = 0; + mouse_oldbuttonstate = 0; + } +} + + +/* +=============== +IN_StartupJoystick +=============== +*/ +void IN_StartupJoystick (void) +{ + int i, numdevs; + JOYCAPS jc; + MMRESULT mmr; + + // assume no joystick + joy_avail = false; + + // abort startup if user requests no joystick + if ( COM_CheckParm ("-nojoy") ) + return; + + // verify joystick driver is present + if ((numdevs = joyGetNumDevs ()) == 0) + { + Con_Printf ("\njoystick not found -- driver not present\n\n"); + return; + } + + // cycle through the joystick ids for the first valid one + for (joy_id=0 ; joy_id 14000.0) + fTemp = 14000.0; + // restore direction information + fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; + } + } + + // convert range from -32768..32767 to -1..1 + fAxisValue /= 32768.0; + + switch (dwAxisMap[i]) + { + case AxisForward: + if ((joy_advanced.value == 0.0) && (cl_mlook.value /*in_mlook.state & 1*/)) // jkrige - mlook cvar + { + // user wants forward control to become look control + if (fabs(fAxisValue) > joy_pitchthreshold.value) + { + // if mouse invert is on, invert the joystick pitch value + // only absolute control support here (joy_advanced is false) + if (m_pitch.value < 0.0) + { + cl.viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value; + } + else + { + cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + + // jkrige - lookspring fix + //if(lookspring.value == 0.0) + // V_StopPitchDrift(); + // jkrige - lookspring fix + } + } + else + { + // user wants forward control to be forward control + if (fabs(fAxisValue) > joy_forwardthreshold.value) + { + cmd->forwardmove += (fAxisValue * joy_forwardsensitivity.value) * speed * cl_forwardspeed.value; + } + } + break; + + case AxisSide: + if (fabs(fAxisValue) > joy_sidethreshold.value) + { + cmd->sidemove += (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value; + } + break; + + case AxisTurn: + if ((in_strafe.state & 1) || (lookstrafe.value && (cl_mlook.value /*in_mlook.state & 1*/))) // jkrige - mlook cvar + { + // user wants turn control to become side control + if (fabs(fAxisValue) > joy_sidethreshold.value) + { + cmd->sidemove -= (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value; + } + } + else + { + // user wants turn control to be turn control + if (fabs(fAxisValue) > joy_yawthreshold.value) + { + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * aspeed * cl_yawspeed.value; + } + else + { + cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * speed * 180.0; + } + + } + } + break; + + case AxisLook: + if (cl_mlook.value /*in_mlook.state & 1*/) // jkrige - mlook cvar + { + if (fabs(fAxisValue) > joy_pitchthreshold.value) + { + // pitch movement detected and pitch movement desired by user + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value; + } + else + { + cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * speed * 180.0; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + + // jkrige - lookspring fix + //if(lookspring.value == 0.0) + // V_StopPitchDrift(); + // jkrige - lookspring fix + } + } + break; + + default: + break; + } + } + + // bounds check pitch + if (cl.viewangles[PITCH] > 80.0) + cl.viewangles[PITCH] = 80.0; + if (cl.viewangles[PITCH] < -70.0) + cl.viewangles[PITCH] = -70.0; +} diff --git a/engine/code/input.h b/engine/code/input.h new file mode 100644 index 0000000..c3daa17 --- /dev/null +++ b/engine/code/input.h @@ -0,0 +1,34 @@ +/* +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. + +*/ +// 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 + +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 + diff --git a/engine/code/keys.c b/engine/code/keys.c new file mode 100644 index 0000000..7f858e1 --- /dev/null +++ b/engine/code/keys.c @@ -0,0 +1,763 @@ +/* +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. + +*/ +#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 edit_line=0; +int history_line=0; + +keydest_t key_dest; + +int key_count; // incremented every key event + +char *keybindings[256]; +qboolean consolekeys[256]; // if true, can't be rebound while in console +qboolean menubound[256]; // if true, can't be rebound while in menu +int keyshift[256]; // key to map to if shift held down in console +int key_repeats[256]; // if > 1, it is autorepeating +qboolean keydown[256]; + +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}, + + {"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}, + + + // jkrige - mouse thumb buttons + { "MOUSE4", K_MOUSE4 }, + { "MOUSE5", K_MOUSE5 }, + // jkrige - mouse thumb buttons + + + {"SEMICOLON", ';'}, // because a raw semicolon seperates commands + + {NULL,0} +}; + +/* +============================================================================== + + LINE TYPING INTO THE CONSOLE + +============================================================================== +*/ + +/* +==================== +Key_Console + +Interactive line editing and console scrollback +==================== +*/ +void Key_Console (int key) +{ + char *cmd; + + if (key == K_ENTER) + { + Cbuf_AddText (key_lines[edit_line]+1); // skip the > + 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_linepos = 1; + if (cls.state == ca_disconnected) + SCR_UpdateScreen (); // force an update, because the command + // may take some time + return; + } + + if (key == K_TAB) + { // command completion + cmd = Cmd_CompleteCommand (key_lines[edit_line]+1); + if (!cmd) + cmd = Cvar_CompleteVariable (key_lines[edit_line]+1); + if (cmd) + { + Q_strcpy (key_lines[edit_line]+1, cmd); + key_linepos = Q_strlen(cmd)+1; + key_lines[edit_line][key_linepos] = ' '; + key_linepos++; + key_lines[edit_line][key_linepos] = 0; + return; + } + } + + if (key == K_BACKSPACE || key == K_LEFTARROW) + { + if (key_linepos > 1) + key_linepos--; + return; + } + + if (key == K_UPARROW) + { + 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; + } + + if (key == K_DOWNARROW) + { + if (history_line == edit_line) 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; + } + + if (key == K_PGUP || key==K_MWHEELUP) + { + con_backscroll += 2; + if (con_backscroll > con_totallines - (vid.height>>3) - 1) + con_backscroll = con_totallines - (vid.height>>3) - 1; + return; + } + + if (key == K_PGDN || key==K_MWHEELDOWN) + { + con_backscroll -= 2; + if (con_backscroll < 0) + con_backscroll = 0; + return; + } + + if (key == K_HOME) + { + con_backscroll = con_totallines - (vid.height>>3) - 1; + return; + } + + if (key == K_END) + { + con_backscroll = 0; + return; + } + + if (key < 32 || key > 127) + return; // non printable + + if (key_linepos < MAXCMDLINE-1) + { + key_lines[edit_line][key_linepos] = key; + key_linepos++; + key_lines[edit_line][key_linepos] = 0; + } + +} + +//============================================================================ + +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_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; + + for (i=0 ; i<32 ; i++) + { + key_lines[i][0] = ']'; + key_lines[i][1] = 0; + } + key_linepos = 1; + +// +// init ascii characters in console mode +// + for (i=32 ; i<128 ; i++) + consolekeys[i] = true; + consolekeys[K_ENTER] = true; + 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_PGUP] = true; + consolekeys[K_PGDN] = true; + consolekeys[K_SHIFT] = true; + consolekeys[K_MWHEELUP] = true; + consolekeys[K_MWHEELDOWN] = true; + consolekeys['`'] = false; + consolekeys['~'] = false; + + 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 ("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 != K_BACKSPACE && key != K_PAUSE && key_repeats[key] > 1) + { + 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; + } + +// +// 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/engine/code/keys.h b/engine/code/keys.h new file mode 100644 index 0000000..db13aa9 --- /dev/null +++ b/engine/code/keys.h @@ -0,0 +1,136 @@ +/* +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. + +*/ + +// +// 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 + +#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 + +// jkrige - mouse thumb buttons +#define K_MOUSE4 241 +#define K_MOUSE5 242 +// jkrige - mouse thumb buttons + + +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/engine/code/mathlib.c b/engine/code/mathlib.c new file mode 100644 index 0000000..0598eef --- /dev/null +++ b/engine/code/mathlib.c @@ -0,0 +1,587 @@ +/* +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. + +*/ +// mathlib.c -- math primitives + +#include +#include "quakedef.h" + +void Sys_Error (char *error, ...); + +vec3_t vec3_origin = {0,0,0}; +int nanmask = 255<<23; + +/*-----------------------------------------------------------------*/ + +// jkrige - quake2 warps +//#define DEG2RAD( a ) ( a * M_PI ) / 180.0F +// jkrige - quake2 warps + +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 ); +} + +#ifdef _WIN32 +#pragma optimize( "", off ) +#endif + + +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ) +{ + float m[3][3]; + float im[3][3]; + float zrot[3][3]; + float tmpmat[3][3]; + float rot[3][3]; + int i; + vec3_t vr, vup, vf; + + vf[0] = dir[0]; + vf[1] = dir[1]; + vf[2] = dir[2]; + + PerpendicularVector( vr, dir ); + CrossProduct( vr, vf, vup ); + + m[0][0] = vr[0]; + m[1][0] = vr[1]; + m[2][0] = vr[2]; + + m[0][1] = vup[0]; + m[1][1] = vup[1]; + m[2][1] = vup[2]; + + m[0][2] = vf[0]; + m[1][2] = vf[1]; + m[2][2] = vf[2]; + + memcpy( im, m, sizeof( im ) ); + + im[0][1] = m[1][0]; + im[0][2] = m[2][0]; + im[1][0] = m[0][1]; + im[1][2] = m[2][1]; + im[2][0] = m[0][2]; + im[2][1] = m[1][2]; + + memset( zrot, 0, sizeof( zrot ) ); + zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F; + + zrot[0][0] = cos( DEG2RAD( degrees ) ); + zrot[0][1] = sin( DEG2RAD( degrees ) ); + zrot[1][0] = -sin( DEG2RAD( degrees ) ); + zrot[1][1] = cos( DEG2RAD( degrees ) ); + + R_ConcatRotations( m, zrot, tmpmat ); + R_ConcatRotations( tmpmat, im, rot ); + + for ( i = 0; i < 3; i++ ) + { + dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2]; + } +} + +#ifdef _WIN32 +#pragma optimize( "", on ) +#endif + +/*-----------------------------------------------------------------*/ + + +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"); +} + + +#if !id386 + +/* +================== +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; +} + +#endif + + +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/engine/code/mathlib.h b/engine/code/mathlib.h new file mode 100644 index 0000000..81e420c --- /dev/null +++ b/engine/code/mathlib.h @@ -0,0 +1,107 @@ +/* +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. + +*/ +// 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 + +// jkrige - quake2 warps +#ifndef DEG2RAD +#define DEG2RAD( a ) ( a * M_PI ) / 180.0F +#endif +// jkrige - quake2 warps + +struct mplane_s; + +extern vec3_t vec3_origin; +extern int nanmask; + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +#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];} + +// jkrige - quake2 warps +#define VectorClear(a) (a[0]=a[1]=a[2]=0) +#define VectorNegate(a,b) (b[0]=-a[0],b[1]=-a[1],b[2]=-a[2]) +#define VectorSet(v, x, y, z) (v[0]=(x), v[1]=(y), v[2]=(z)) +// jkrige - quake2 warps + + +// jkrige - field of view (fov) fix +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); +// jkrige - field of view (fov) fix + + +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/engine/code/menu.c b/engine/code/menu.c new file mode 100644 index 0000000..d06f682 --- /dev/null +++ b/engine/code/menu.c @@ -0,0 +1,3364 @@ +/* +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. + +*/ +#include "quakedef.h" + +#ifdef _WIN32 +#include "winquake.h" +#endif + + +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_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_Menu_SerialConfig_f (void); + void M_Menu_ModemConfig_f (void); +void M_Menu_LanConfig_f (void); +void M_Menu_GameOptions_f (void); +void M_Menu_Search_f (void); +void M_Menu_ServerList_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_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_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_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_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); +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); + +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 + ((vid.width - 320)>>1), 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_TransPic (x + ((vid.width - 320)>>1), y, pic); +} + +void M_DrawPic (int x, int y, qpic_t *pic) +{ + Draw_Pic (x + ((vid.width - 320)>>1), y, pic); +} + +byte identityTable[256]; +byte translationTable[256]; + +void M_BuildTranslationTable(int top, int bottom) +{ + int j; + byte *dest, *source; + + for (j = 0; j < 256; j++) + identityTable[j] = j; + dest = translationTable; + source = identityTable; + memcpy (dest, source, 256); + + if (top < 128) // the artists made some backwards ranges. sigh. + memcpy (dest + TOP_RANGE, source + top, 16); + else + for (j=0 ; j<16 ; j++) + dest[TOP_RANGE+j] = source[top+15-j]; + + if (bottom < 128) + memcpy (dest + BOTTOM_RANGE, source + bottom, 16); + else + for (j=0 ; j<16 ; j++) + dest[BOTTOM_RANGE+j] = source[bottom+15-j]; +} + + +void M_DrawTransPicTranslate (int x, int y, qpic_t *pic) +{ + Draw_TransPicTranslate (x + ((vid.width - 320)>>1), y, pic, translationTable); +} + + +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; + } + 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; + } + 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)(host_time * 10)%6; + + 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: + 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) +{ + 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)(host_time * 10)%6; + + 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")) + break; + key_dest = key_game; + if (sv.active) + Cbuf_AddText ("disconnect\n"); + Cbuf_AddText ("maxplayers 1\n"); + 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 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; + 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) +{ + 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)(host_time * 10)%6; + + 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) +{ + 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_BuildTranslationTable(setup_top*16, setup_bottom*16); + M_DrawTransPicTranslate (172, 72, p); + + 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) +{ + 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)(host_time * 10)%6; + 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*/ + +// jkrige - menu items +#ifdef _WIN32 +#define OPTIONS_ITEMS 16 +#else +#define OPTIONS_ITEMS 15 +#endif +// jkrige - menu items + +#define SLIDER_RANGE 10 + +int options_cursor; + +void M_Menu_Options_f (void) +{ + key_dest = key_menu; + m_state = m_options; + m_entersound = true; + +#ifdef _WIN32 + if ((options_cursor == 16) && (modestate != MS_WINDOWED)) + { + options_cursor = 0; + } +#endif +} + + +void M_AdjustSliders (int dir) +{ + S_LocalSound ("misc/menu3.wav"); + + switch (options_cursor) + { + // jkrige - scr_viewsize removal + /*case 2: // screen size + scr_viewsize.value += dir * 10; + // jkrige - viewsize decreased + //if (scr_viewsize.value < 30) + // scr_viewsize.value = 30; + //if (scr_viewsize.value > 120) + // scr_viewsize.value = 120; + if (scr_viewsize.value < 10) + scr_viewsize.value = 10; + if (scr_viewsize.value > 100) + scr_viewsize.value = 100; + // jkrige - viewsize decreased + Cvar_SetValue ("viewsize", scr_viewsize.value); + break;*/ + // jkrige - scr_viewsize removal + + // jkrige - change brightness slider for opengl +#ifdef GLQUAKE + case 2: // gamma + // jkrige - gamma + gl_gamma.value -= dir * 0.05; + if (gl_gamma.value < 0.5) + gl_gamma.value = 0.5; + if (gl_gamma.value > 2.75) + gl_gamma.value = 2.75; + Cvar_SetValue ("gamma", gl_gamma.value); + // jkrige - gamma + break; +#else + case 2: // gamma + v_gamma.value -= dir * 0.05; + if (v_gamma.value < 0.5) + v_gamma.value = 0.5; + if (v_gamma.value > 1) + v_gamma.value = 1; + Cvar_SetValue ("gamma", v_gamma.value); + break; +#endif + // jkrige - change brightness slider for opengl + + // jkrige - anisotropic filtering +#ifdef GLQUAKE + case 3: // texture mode + gl_texturemode.value += dir * 1; + if(anisotropic_ext == false) + { + if (gl_texturemode.value < 0.0f) + gl_texturemode.value = 0.0f; + if (gl_texturemode.value > 2.0f) + gl_texturemode.value = 2.0f; + } + if(anisotropic_ext == true) + { + if (gl_texturemode.value < 0.0f) + gl_texturemode.value = 0.0f; + if (gl_texturemode.value > ((int)2.0f + (int)floor((log(maximumAnisotrophy)/log(2.0f)) + 0.5f))) + gl_texturemode.value = ((int)2.0f + (int)floor((log(maximumAnisotrophy)/log(2.0f)) + 0.5f)); + } + Cvar_SetValue ("gl_texturemode", gl_texturemode.value); + break; +#endif + // jkrige - anisotropic filtering + + case 4: // 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 5: // music volume + // jkrige - cd audio volume fix +//#ifdef _WIN32 +// bgmvolume.value += dir * 1.0; +//#else + bgmvolume.value += dir * 0.1; +//#endif + // jkrige - cd audio volume fix + + if (bgmvolume.value < 0) + bgmvolume.value = 0; + if (bgmvolume.value > 1) + bgmvolume.value = 1; + Cvar_SetValue ("bgmvolume", bgmvolume.value); + break; + + case 6: // 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 7: // 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 8: // invert mouse + Cvar_SetValue ("m_pitch", -m_pitch.value); + break; + + case 9: // lookspring + Cvar_SetValue ("lookspring", !lookspring.value); + break; + + case 10: // lookstrafe + Cvar_SetValue ("lookstrafe", !lookstrafe.value); + break; + + case 11: // crosshair + Cvar_SetValue ("crosshair", !crosshair.value); // jkrige - crosshair + break; + + case 12: + Cvar_SetValue ("cl_mlook", !cl_mlook.value); // jkrige - mlook cvar + break; + + case 13: + Cvar_SetValue ("cl_slook", !cl_slook.value); // jkrige - slook cvar + break; + +#ifdef _WIN32 + case 15: // _windowed_mouse + Cvar_SetValue ("_windowed_mouse", !_windowed_mouse.value); + break; +#endif + } +} + + +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, 40, " Reset to defaults"); + + // jkrige - scr_viewsize removal + /*M_Print (16, 48, " Screen size"); + // jkrige - viewsize decreased + //r = (scr_viewsize.value - 30) / (120 - 30); + r = (scr_viewsize.value - 10) / (100 - 10); + // jkrige - viewsize decreased + M_DrawSlider (220, 48, r);*/ + // jkrige - scr_viewsize removal + + // jkrige - change brightness slider for opengl + M_Print (16, 48, " Brightness"); +#ifdef GLQUAKE + r = (2.75 - gl_gamma.value) / 2.25; +#else + r = (1.0 - v_gamma.value) / 0.5; +#endif + M_DrawSlider (220, 48, r); + // jkrige - change brightness slider for opengl + + + // jkrige - anisotropic filtering + M_Print (16, 56, " Texture Mode"); +#ifdef GLQUAKE + if (gl_texturemode.value == 0.0f) + M_Print (220, 56, "Point"); + else if (gl_texturemode.value == 1.0f) + M_Print (220, 56, "Bilinear"); + else if (gl_texturemode.value == 2.0f) + M_Print (220, 56, "Trilinear"); + else + { + if (modelist[(int)vid_mode.value].width > 640) + M_Print (220, 56, va("Anisotropic %.0fx", pow(2.0f, gl_texturemode.value - 2.0f))); + else + M_Print (220, 56, va("AF %.0fx", pow(2.0f, gl_texturemode.value - 2.0f))); + } +#else + M_Print (220, 56, "Point"); +#endif + // jkrige - anisotropic filtering + + + M_Print (16, 64, " Mouse Speed"); + M_DrawSlider (220, 64, (float)((sensitivity.value - 1) / 10)); + + M_Print (16, 72, " Music Volume"); + M_DrawSlider (220, 72, bgmvolume.value); + + M_Print (16, 80, " Sound Volume"); + M_DrawSlider (220, 80, volume.value); + + M_Print (16, 88, " Always Run"); + M_DrawCheckbox (220, 88, cl_forwardspeed.value > 200); + + M_Print (16, 96, " Invert Mouse"); + M_DrawCheckbox (220, 96, m_pitch.value < 0); + + M_Print (16, 104, " Lookspring"); + M_DrawCheckbox (220, 104, lookspring.value); + + M_Print (16, 112, " Lookstrafe"); + M_DrawCheckbox (220, 112, lookstrafe.value); + + // jkrige - crosshair + M_Print (16, 120, " Crosshair"); + M_DrawCheckbox (220, 120, crosshair.value); + // jkrige - crosshair + + M_Print (16, 128, " Mouse Look"); + M_DrawCheckbox (220, 128, cl_mlook.value /*in_mlook.state & 1*/); // jkrige - mlook cvar + + M_Print (16, 136, " Slope Look"); + M_DrawCheckbox (220, 136, cl_slook.value); // jkrige - slook cvar + + if (vid_menudrawfn) + M_Print (16, 144, " Video Options"); + +#ifdef _WIN32 + if (modestate == MS_WINDOWED) + { + M_Print (16, 152, " Use Mouse"); + M_DrawCheckbox (220, 152, _windowed_mouse.value); + } +#endif + +// 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 1: + Cbuf_AddText ("exec default.cfg\n"); + break; + case 14: + 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 == 14 && vid_menudrawfn == NULL) + { + if (k == K_UPARROW) + { + if (modestate == MS_WINDOWED) + options_cursor = 13; + } + else + { + if (modestate != MS_WINDOWED) + options_cursor = 0; + else + options_cursor = 15; + } + } + +#ifdef _WIN32 + if ((options_cursor == 15) && (modestate != MS_WINDOWED)) + { + if (k == K_UPARROW) + options_cursor = (vid_menudrawfn == NULL) ? 13 : 14; + else + options_cursor = 0; + } +#endif +} + +//============================================================================= +/* 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"}, // jkrige - removed mlook command +//{"+klook", "keyboard look"}, // jkrige - removed klook command +{"+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) +{ + 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; + 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) +{ + key_dest = key_menu; + m_state = m_video; + m_entersound = true; +} + + +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) +{ + 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; + +#ifndef _WIN32 +char *quitMessage [] = +{ +/* .........1.........2.... */ + " Are you gonna quit ", + " this game just like ", + " everything else? ", + " ", + + " Milord, methinks that ", + " thou art a lowly ", + " quitter. Is this true? ", + " ", + + " Do I need to bust your ", + " face open for trying ", + " to quit? ", + " ", + + " Man, I oughta smack you", + " for trying to quit! ", + " Press Y to get ", + " smacked out. ", + + " Press Y to quit like a ", + " big loser in life. ", + " Press N to stay proud ", + " and successful! ", + + " If you press Y to ", + " quit, I will summon ", + " Satan all over your ", + " hard drive! ", + + " Um, Asmodeus dislikes ", + " his children trying to ", + " quit. Press Y to return", + " to your Tinkertoys. ", + + " If you quit now, I'll ", + " throw a blanket-party ", + " for you next time! ", + " " +}; +#endif + +void M_Menu_Quit_f (void) +{ + if (m_state == m_quit) + return; + wasInMenus = (key_dest == key_menu); + 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 + { + key_dest = key_game; + m_state = m_none; + } + break; + + case 'Y': + case 'y': + key_dest = key_console; + Host_Quit_f (); + break; + + default: + break; + } + +} + + +void M_Quit_Draw (void) +{ + if (wasInMenus) + { + m_state = m_quit_prevstate; + m_recursiveDraw = true; + M_Draw (); + m_state = m_quit; + } + +#ifdef _WIN32 + M_DrawTextBox (0, 0, 38, 24); + + // jkrige - new version + //M_PrintWhite (16, 12, va(" Quake version %.2f by id Software\n\n", QUAKE_VERSION)); + M_PrintWhite (16, 12, va(" UQE Quake v%.2f by Jacques Krige ", QUAKE_VERSION)); + M_PrintWhite (16, 20, " www.jacqueskrige.com "); + // jkrige - new version + + M_PrintWhite (16, 36, "Programming Art"); + M_Print (16, 44, " John Carmack Adrian Carmack"); + M_Print (16, 52, " Michael Abrash Kevin Cloud"); + M_Print (16, 60, " John Cash Paul Steed"); + M_Print (16, 68, " Dave 'Zoid' Kirsch"); + M_PrintWhite (16, 76, "Design Biz"); + M_Print (16, 84, " John Romero Jay Wilbur"); + M_Print (16, 92, " Sandy Petersen Mike Wilson"); + M_Print (16, 100, " American McGee Donna Jackson"); + M_Print (16, 108, " Tim Willits Todd Hollenshead"); + M_PrintWhite (16, 116, "Support Projects"); + M_Print (16, 124, " Barrett Alexander Shawn Green"); + M_PrintWhite (16, 132, "Sound Effects"); + M_Print (16, 140, " Trent Reznor and Nine Inch Nails"); + M_PrintWhite (16, 148, "Quake is a trademark of Id Software,"); + M_PrintWhite (16, 156, "inc., (c)1996 Id Software, inc. All"); + M_PrintWhite (16, 164, "rights reserved. NIN logo is a"); + M_PrintWhite (16, 172, "registered trademark licensed to"); + M_PrintWhite (16, 180, "Nothing Interactive, Inc. All rights"); + M_PrintWhite (16, 188, "reserved. Press y to exit"); +#else + M_DrawTextBox (56, 76, 24, 4); + M_Print (64, 84, quitMessage[msgNumber*4+0]); + M_Print (64, 92, quitMessage[msgNumber*4+1]); + M_Print (64, 100, quitMessage[msgNumber*4+2]); + M_Print (64, 108, quitMessage[msgNumber*4+3]); +#endif +} + +//============================================================================= + +/* 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; + + 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; + 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) +{ + 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) +{ + 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; + 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) +{ + 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) +{ + 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) +{ + 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; + 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) + { + scr_copyeverything = 1; + + if (scr_con_current) + { + Draw_ConsoleBackground (vid.height); + VID_UnlockBuffer (); + S_ExtraUpdate (); + VID_LockBuffer (); + } + else + Draw_FadeScreen (); + + scr_fullupdate = 0; + } + else + { + m_recursiveDraw = false; + } + + 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; + } + + VID_UnlockBuffer (); + S_ExtraUpdate (); + VID_LockBuffer (); +} + + +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/engine/code/menu.h b/engine/code/menu.h new file mode 100644 index 0000000..616de3f --- /dev/null +++ b/engine/code/menu.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. + +*/ + +// +// 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/engine/code/modelgen.h b/engine/code/modelgen.h new file mode 100644 index 0000000..be9ad92 --- /dev/null +++ b/engine/code/modelgen.h @@ -0,0 +1,134 @@ +/* +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. + +*/ +// +// 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/engine/code/net.h b/engine/code/net.h new file mode 100644 index 0000000..af46125 --- /dev/null +++ b/engine/code/net.h @@ -0,0 +1,337 @@ +/* +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.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 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 + +#ifdef IDGODS +qboolean IsID(struct qsockaddr *addr); +#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/engine/code/net_dgrm.c b/engine/code/net_dgrm.c new file mode 100644 index 0000000..a293b77 --- /dev/null +++ b/engine/code/net_dgrm.c @@ -0,0 +1,1390 @@ +/* +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_dgrm.c + +// This is enables a simple IP banning mechanism +#define BAN_TEST + +#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]; + + +#ifdef DEBUG +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; +} +#endif + + +#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 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; + } + +#ifdef BAN_TEST + Cmd_AddCommand ("ban", NET_Ban_f); +#endif + Cmd_AddCommand ("test", Test_f); + Cmd_AddCommand ("test2", Test2_f); + + 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\n", StrAddr (&sendaddr)); + Con_Printf("Received: %s\n", 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/engine/code/net_dgrm.h b/engine/code/net_dgrm.h new file mode 100644 index 0000000..da052e7 --- /dev/null +++ b/engine/code/net_dgrm.h @@ -0,0 +1,34 @@ +/* +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_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/engine/code/net_loop.c b/engine/code/net_loop.c new file mode 100644 index 0000000..35aa370 --- /dev/null +++ b/engine/code/net_loop.c @@ -0,0 +1,245 @@ +/* +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_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/engine/code/net_loop.h b/engine/code/net_loop.h new file mode 100644 index 0000000..90cdb2c --- /dev/null +++ b/engine/code/net_loop.h @@ -0,0 +1,33 @@ +/* +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_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/engine/code/net_main.c b/engine/code/net_main.c new file mode 100644 index 0000000..98d986d --- /dev/null +++ b/engine/code/net_main.c @@ -0,0 +1,1012 @@ +/* +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_main.c + +#include "quakedef.h" +#include "net_vcr.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}; + +#ifdef IDGODS +cvar_t idgods = {"idgods", "0"}; +#endif + +int vcrFile = -1; +qboolean recording = false; + +// 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; + + // jkrige - coop and deathmatch flag fix + //if (n == 1) + // Cvar_Set ("deathmatch", "0"); + //else + // Cvar_Set ("deathmatch", "1"); + if (n == 1) + { + Cvar_Set ("deathmatch", "0"); + Cvar_Set ("coop", "0"); + } + else + { + if (coop.value) + Cvar_Set ("deathmatch", "0"); + else + Cvar_Set ("deathmatch", "1"); + } + // jkrige - coop and deathmatch flag fix +} + + +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_driverleveladdress, NET_NAMELEN); + } + return ret; + } + } + + if (recording) + { + vcrConnect.time = host_time; + vcrConnect.op = VCR_OP_CONNECT; + vcrConnect.session = 0; + Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect)); + } + + return NULL; +} + +/* +=================== +NET_Close +=================== +*/ +void NET_Close (qsocket_t *sock) +{ + if (!sock) + return; + + if (sock->disconnected) + 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 +================= +*/ + +struct +{ + double time; + int op; + long session; + int ret; + int len; +} vcrGetMessage; + +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++; + } + + if (recording) + { + vcrGetMessage.time = host_time; + vcrGetMessage.op = VCR_OP_GETMESSAGE; + vcrGetMessage.session = (long)sock; + vcrGetMessage.ret = ret; + vcrGetMessage.len = net_message.cursize; + Sys_FileWrite (vcrFile, &vcrGetMessage, 24); + Sys_FileWrite (vcrFile, net_message.data, net_message.cursize); + } + } + else + { + if (recording) + { + vcrGetMessage.time = host_time; + vcrGetMessage.op = VCR_OP_GETMESSAGE; + vcrGetMessage.session = (long)sock; + vcrGetMessage.ret = ret; + Sys_FileWrite (vcrFile, &vcrGetMessage, 20); + } + } + + 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 +================== +*/ +struct +{ + double time; + int op; + long session; + int r; +} vcrSendMessage; + +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++; + + if (recording) + { + vcrSendMessage.time = host_time; + vcrSendMessage.op = VCR_OP_SENDMESSAGE; + vcrSendMessage.session = (long)sock; + vcrSendMessage.r = r; + Sys_FileWrite (vcrFile, &vcrSendMessage, 20); + } + + 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++; + + if (recording) + { + vcrSendMessage.time = host_time; + vcrSendMessage.op = VCR_OP_SENDMESSAGE; + vcrSendMessage.session = (long)sock; + vcrSendMessage.r = r; + Sys_FileWrite (vcrFile, &vcrSendMessage, 20); + } + + 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); + + if (recording) + { + vcrSendMessage.time = host_time; + vcrSendMessage.op = VCR_OP_CANSENDMESSAGE; + vcrSendMessage.session = (long)sock; + vcrSendMessage.r = r; + Sys_FileWrite (vcrFile, &vcrSendMessage, 20); + } + + 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; + + if (COM_CheckParm("-playback")) + { + net_numdrivers = 1; + net_drivers[0].Init = VCR_Init; + } + + if (COM_CheckParm("-record")) + recording = true; + + 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); + Cvar_RegisterVariable (&hostname); + Cvar_RegisterVariable (&config_com_port); + Cvar_RegisterVariable (&config_com_irq); + Cvar_RegisterVariable (&config_com_baud); + Cvar_RegisterVariable (&config_com_modem); + Cvar_RegisterVariable (&config_modem_dialtype); + Cvar_RegisterVariable (&config_modem_clear); + Cvar_RegisterVariable (&config_modem_init); + Cvar_RegisterVariable (&config_modem_hangup); +#ifdef IDGODS + Cvar_RegisterVariable (&idgods); +#endif + + 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; + } + } + + if (vcrFile != -1) + { + Con_Printf ("Closing vcrfile.\n"); + Sys_FileClose(vcrFile); + } +} + + +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; +} + + +#ifdef IDGODS +#define IDNET 0xc0f62800 + +qboolean IsID(struct qsockaddr *addr) +{ + if (idgods.value == 0.0) + return false; + + if (addr->sa_family != 2) + return false; + + if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET) + return true; + return false; +} +#endif diff --git a/engine/code/net_vcr.c b/engine/code/net_vcr.c new file mode 100644 index 0000000..ba8f40d --- /dev/null +++ b/engine/code/net_vcr.c @@ -0,0 +1,167 @@ +/* +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_vcr.c + +#include "quakedef.h" +#include "net_vcr.h" + +extern int vcrFile; + +// This is the playback portion of the VCR. It reads the file produced +// by the recorder and plays it back to the host. The recording contains +// everything necessary (events, timestamps, and data) to duplicate the game +// from the viewpoint of everything above the network layer. + +static struct +{ + double time; + int op; + long session; +} next; + +int VCR_Init (void) +{ + net_drivers[0].Init = VCR_Init; + + net_drivers[0].SearchForHosts = VCR_SearchForHosts; + net_drivers[0].Connect = VCR_Connect; + net_drivers[0].CheckNewConnections = VCR_CheckNewConnections; + net_drivers[0].QGetMessage = VCR_GetMessage; + net_drivers[0].QSendMessage = VCR_SendMessage; + net_drivers[0].CanSendMessage = VCR_CanSendMessage; + net_drivers[0].Close = VCR_Close; + net_drivers[0].Shutdown = VCR_Shutdown; + + Sys_FileRead(vcrFile, &next, sizeof(next)); + return 0; +} + +void VCR_ReadNext (void) +{ + if (Sys_FileRead(vcrFile, &next, sizeof(next)) == 0) + { + next.op = 255; + Sys_Error ("=== END OF PLAYBACK===\n"); + } + if (next.op < 1 || next.op > VCR_MAX_MESSAGE) + Sys_Error ("VCR_ReadNext: bad op"); +} + + +void VCR_Listen (qboolean state) +{ +} + + +void VCR_Shutdown (void) +{ +} + + +int VCR_GetMessage (qsocket_t *sock) +{ + int ret; + + if (host_time != next.time || next.op != VCR_OP_GETMESSAGE || next.session != *(long *)(&sock->driverdata)) + Sys_Error ("VCR missmatch"); + + Sys_FileRead(vcrFile, &ret, sizeof(int)); + if (ret != 1) + { + VCR_ReadNext (); + return ret; + } + + Sys_FileRead(vcrFile, &net_message.cursize, sizeof(int)); + Sys_FileRead(vcrFile, net_message.data, net_message.cursize); + + VCR_ReadNext (); + + return 1; +} + + +int VCR_SendMessage (qsocket_t *sock, sizebuf_t *data) +{ + int ret; + + if (host_time != next.time || next.op != VCR_OP_SENDMESSAGE || next.session != *(long *)(&sock->driverdata)) + Sys_Error ("VCR missmatch"); + + Sys_FileRead(vcrFile, &ret, sizeof(int)); + + VCR_ReadNext (); + + return ret; +} + + +qboolean VCR_CanSendMessage (qsocket_t *sock) +{ + qboolean ret; + + if (host_time != next.time || next.op != VCR_OP_CANSENDMESSAGE || next.session != *(long *)(&sock->driverdata)) + Sys_Error ("VCR missmatch"); + + Sys_FileRead(vcrFile, &ret, sizeof(int)); + + VCR_ReadNext (); + + return ret; +} + + +void VCR_Close (qsocket_t *sock) +{ +} + + +void VCR_SearchForHosts (qboolean xmit) +{ +} + + +qsocket_t *VCR_Connect (char *host) +{ + return NULL; +} + + +qsocket_t *VCR_CheckNewConnections (void) +{ + qsocket_t *sock; + + if (host_time != next.time || next.op != VCR_OP_CONNECT) + Sys_Error ("VCR missmatch"); + + if (!next.session) + { + VCR_ReadNext (); + return NULL; + } + + sock = NET_NewQSocket (); + *(long *)(&sock->driverdata) = next.session; + + Sys_FileRead (vcrFile, sock->address, NET_NAMELEN); + VCR_ReadNext (); + + return sock; +} diff --git a/engine/code/net_vcr.h b/engine/code/net_vcr.h new file mode 100644 index 0000000..95c2f34 --- /dev/null +++ b/engine/code/net_vcr.h @@ -0,0 +1,37 @@ +/* +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_vcr.h + +#define VCR_OP_CONNECT 1 +#define VCR_OP_GETMESSAGE 2 +#define VCR_OP_SENDMESSAGE 3 +#define VCR_OP_CANSENDMESSAGE 4 +#define VCR_MAX_MESSAGE 4 + +int VCR_Init (void); +void VCR_Listen (qboolean state); +void VCR_SearchForHosts (qboolean xmit); +qsocket_t *VCR_Connect (char *host); +qsocket_t *VCR_CheckNewConnections (void); +int VCR_GetMessage (qsocket_t *sock); +int VCR_SendMessage (qsocket_t *sock, sizebuf_t *data); +qboolean VCR_CanSendMessage (qsocket_t *sock); +void VCR_Close (qsocket_t *sock); +void VCR_Shutdown (void); diff --git a/engine/code/net_win.c b/engine/code/net_win.c new file mode 100644 index 0000000..019a9c7 --- /dev/null +++ b/engine/code/net_win.c @@ -0,0 +1,120 @@ +/* +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. + +*/ +#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/engine/code/net_wins.c b/engine/code/net_wins.c new file mode 100644 index 0000000..1ac445b --- /dev/null +++ b/engine/code/net_wins.c @@ -0,0 +1,580 @@ +/* +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_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) + { + // jkrige - vs2005 + //int errno = pWSAGetLastError(); + + //if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) + // return 0; + int err = pWSAGetLastError(); + + if (err == WSAEWOULDBLOCK || err == WSAECONNREFUSED) + return 0; + // jkrige - vs2005 + } + 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/engine/code/net_wins.h b/engine/code/net_wins.h new file mode 100644 index 0000000..756ce64 --- /dev/null +++ b/engine/code/net_wins.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_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/engine/code/net_wipx.c b/engine/code/net_wipx.c new file mode 100644 index 0000000..c6f9f10 --- /dev/null +++ b/engine/code/net_wipx.c @@ -0,0 +1,440 @@ +/* +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_wipx.c + +#include "quakedef.h" +#include "winquake.h" +#include +#include "net_wipx.h" + +extern cvar_t hostname; + +#define MAXHOSTNAMELEN 256 + +static int net_acceptsocket = -1; // socket for fielding new connections +static int net_controlsocket; +static struct qsockaddr broadcastaddr; + +extern qboolean winsock_initialized; +extern WSADATA winsockdata; + +#define IPXSOCKETS 18 +static int ipxsocket[IPXSOCKETS]; +static int sequence[IPXSOCKETS]; + +//============================================================================= + +int WIPX_Init (void) +{ + int i; + char buff[MAXHOSTNAMELEN]; + struct qsockaddr addr; + char *p; + int r; + WORD wVersionRequested; + + if (COM_CheckParm ("-noipx")) + return -1; + +// make sure LoadLibrary has happened successfully + if (!winsock_lib_initialized) + return -1; + + if (winsock_initialized == 0) + { + wVersionRequested = MAKEWORD(1, 1); + + r = pWSAStartup (MAKEWORD(1, 1), &winsockdata); + + if (r) + { + Con_Printf ("Winsock initialization failed.\n"); + return -1; + } + } + winsock_initialized++; + + for (i = 0; i < IPXSOCKETS; i++) + ipxsocket[i] = 0; + + // determine my name & address + if (pgethostname(buff, MAXHOSTNAMELEN) == 0) + { + // 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); + } + } + + if ((net_controlsocket = WIPX_OpenSocket (0)) == -1) + { + Con_Printf("WIPX_Init: Unable to open control socket\n"); + if (--winsock_initialized == 0) + pWSACleanup (); + return -1; + } + + ((struct sockaddr_ipx *)&broadcastaddr)->sa_family = AF_IPX; + memset(((struct sockaddr_ipx *)&broadcastaddr)->sa_netnum, 0, 4); + memset(((struct sockaddr_ipx *)&broadcastaddr)->sa_nodenum, 0xff, 6); + ((struct sockaddr_ipx *)&broadcastaddr)->sa_socket = htons((unsigned short)net_hostport); + + WIPX_GetSocketAddr (net_controlsocket, &addr); + Q_strcpy(my_ipx_address, WIPX_AddrToString (&addr)); + p = Q_strrchr (my_ipx_address, ':'); + if (p) + *p = 0; + + Con_Printf("Winsock IPX Initialized\n"); + ipxAvailable = true; + + return net_controlsocket; +} + +//============================================================================= + +void WIPX_Shutdown (void) +{ + WIPX_Listen (false); + WIPX_CloseSocket (net_controlsocket); + if (--winsock_initialized == 0) + pWSACleanup (); +} + +//============================================================================= + +void WIPX_Listen (qboolean state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + if ((net_acceptsocket = WIPX_OpenSocket (net_hostport)) == -1) + Sys_Error ("WIPX_Listen: Unable to open accept socket\n"); + return; + } + + // disable listening + if (net_acceptsocket == -1) + return; + WIPX_CloseSocket (net_acceptsocket); + net_acceptsocket = -1; +} + +//============================================================================= + +int WIPX_OpenSocket (int port) +{ + int handle; + int newsocket; + struct sockaddr_ipx address; + u_long _true = 1; + + for (handle = 0; handle < IPXSOCKETS; handle++) + if (ipxsocket[handle] == 0) + break; + if (handle == IPXSOCKETS) + return -1; + + if ((newsocket = psocket (AF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == INVALID_SOCKET) + return -1; + + if (pioctlsocket (newsocket, FIONBIO, &_true) == -1) + goto ErrorReturn; + + if (psetsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) < 0) + goto ErrorReturn; + + address.sa_family = AF_IPX; + memset(address.sa_netnum, 0, 4); + memset(address.sa_nodenum, 0, 6);; + address.sa_socket = htons((unsigned short)port); + if( bind (newsocket, (void *)&address, sizeof(address)) == 0) + { + ipxsocket[handle] = newsocket; + sequence[handle] = 0; + return handle; + } + + Sys_Error ("Winsock IPX bind failed\n"); +ErrorReturn: + pclosesocket (newsocket); + return -1; +} + +//============================================================================= + +int WIPX_CloseSocket (int handle) +{ + int socket = ipxsocket[handle]; + int ret; + + ret = pclosesocket (socket); + ipxsocket[handle] = 0; + return ret; +} + + +//============================================================================= + +int WIPX_Connect (int handle, struct qsockaddr *addr) +{ + return 0; +} + +//============================================================================= + +int WIPX_CheckNewConnections (void) +{ + unsigned long available; + + if (net_acceptsocket == -1) + return -1; + + if (pioctlsocket (ipxsocket[net_acceptsocket], FIONREAD, &available) == -1) + Sys_Error ("WIPX: ioctlsocket (FIONREAD) failed\n"); + if (available) + return net_acceptsocket; + return -1; +} + +//============================================================================= + +static byte packetBuffer[NET_DATAGRAMSIZE + 4]; + +int WIPX_Read (int handle, byte *buf, int len, struct qsockaddr *addr) +{ + int addrlen = sizeof (struct qsockaddr); + int socket = ipxsocket[handle]; + int ret; + + ret = precvfrom (socket, packetBuffer, len+4, 0, (struct sockaddr *)addr, &addrlen); + if (ret == -1) + { + // jkrige - vs2005 + //int errno = pWSAGetLastError(); + + //if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) + // return 0; + int err = pWSAGetLastError(); + + if (err == WSAEWOULDBLOCK || err == WSAECONNREFUSED) + return 0; + // jkrige - vs2005 + } + + if (ret < 4) + return 0; + + // remove sequence number, it's only needed for DOS IPX + ret -= 4; + memcpy(buf, packetBuffer+4, ret); + + return ret; +} + +//============================================================================= + +int WIPX_Broadcast (int handle, byte *buf, int len) +{ + return WIPX_Write (handle, buf, len, &broadcastaddr); +} + +//============================================================================= + +int WIPX_Write (int handle, byte *buf, int len, struct qsockaddr *addr) +{ + int socket = ipxsocket[handle]; + int ret; + + // build packet with sequence number + *(int *)(&packetBuffer[0]) = sequence[handle]; + sequence[handle]++; + memcpy(&packetBuffer[4], buf, len); + len += 4; + + ret = psendto (socket, packetBuffer, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr)); + if (ret == -1) + if (pWSAGetLastError() == WSAEWOULDBLOCK) + return 0; + + return ret; +} + +//============================================================================= + +char *WIPX_AddrToString (struct qsockaddr *addr) +{ + static char buf[28]; + + sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u", + ((struct sockaddr_ipx *)addr)->sa_netnum[0] & 0xff, + ((struct sockaddr_ipx *)addr)->sa_netnum[1] & 0xff, + ((struct sockaddr_ipx *)addr)->sa_netnum[2] & 0xff, + ((struct sockaddr_ipx *)addr)->sa_netnum[3] & 0xff, + ((struct sockaddr_ipx *)addr)->sa_nodenum[0] & 0xff, + ((struct sockaddr_ipx *)addr)->sa_nodenum[1] & 0xff, + ((struct sockaddr_ipx *)addr)->sa_nodenum[2] & 0xff, + ((struct sockaddr_ipx *)addr)->sa_nodenum[3] & 0xff, + ((struct sockaddr_ipx *)addr)->sa_nodenum[4] & 0xff, + ((struct sockaddr_ipx *)addr)->sa_nodenum[5] & 0xff, + ntohs(((struct sockaddr_ipx *)addr)->sa_socket) + ); + return buf; +} + +//============================================================================= + +int WIPX_StringToAddr (char *string, struct qsockaddr *addr) +{ + int val; + char buf[3]; + + buf[2] = 0; + Q_memset(addr, 0, sizeof(struct qsockaddr)); + addr->sa_family = AF_IPX; + +#define DO(src,dest) \ + buf[0] = string[src]; \ + buf[1] = string[src + 1]; \ + if (sscanf (buf, "%x", &val) != 1) \ + return -1; \ + ((struct sockaddr_ipx *)addr)->dest = val + + DO(0, sa_netnum[0]); + DO(2, sa_netnum[1]); + DO(4, sa_netnum[2]); + DO(6, sa_netnum[3]); + DO(9, sa_nodenum[0]); + DO(11, sa_nodenum[1]); + DO(13, sa_nodenum[2]); + DO(15, sa_nodenum[3]); + DO(17, sa_nodenum[4]); + DO(19, sa_nodenum[5]); +#undef DO + + sscanf (&string[22], "%u", &val); + ((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)val); + + return 0; +} + +//============================================================================= + +int WIPX_GetSocketAddr (int handle, struct qsockaddr *addr) +{ + int socket = ipxsocket[handle]; + int addrlen = sizeof(struct qsockaddr); + unsigned int a; + + Q_memset(addr, 0, sizeof(struct qsockaddr)); + if(pgetsockname(socket, (struct sockaddr *)addr, &addrlen) != 0) + { + // jkrige - vs2005 + //int errno = pWSAGetLastError(); + int err = pWSAGetLastError(); + // jkrige - vs2005 + } + + return 0; +} + +//============================================================================= + +int WIPX_GetNameFromAddr (struct qsockaddr *addr, char *name) +{ + Q_strcpy(name, WIPX_AddrToString(addr)); + return 0; +} + +//============================================================================= + +int WIPX_GetAddrFromName(char *name, struct qsockaddr *addr) +{ + int n; + char buf[32]; + + n = Q_strlen(name); + + if (n == 12) + { + sprintf(buf, "00000000:%s:%u", name, net_hostport); + return WIPX_StringToAddr (buf, addr); + } + if (n == 21) + { + sprintf(buf, "%s:%u", name, net_hostport); + return WIPX_StringToAddr (buf, addr); + } + if (n > 21 && n <= 27) + return WIPX_StringToAddr (name, addr); + + return -1; +} + +//============================================================================= + +int WIPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) +{ + if (addr1->sa_family != addr2->sa_family) + return -1; + + if (*((struct sockaddr_ipx *)addr1)->sa_netnum && *((struct sockaddr_ipx *)addr2)->sa_netnum) + if (memcmp(((struct sockaddr_ipx *)addr1)->sa_netnum, ((struct sockaddr_ipx *)addr2)->sa_netnum, 4) != 0) + return -1; + if (memcmp(((struct sockaddr_ipx *)addr1)->sa_nodenum, ((struct sockaddr_ipx *)addr2)->sa_nodenum, 6) != 0) + return -1; + + if (((struct sockaddr_ipx *)addr1)->sa_socket != ((struct sockaddr_ipx *)addr2)->sa_socket) + return 1; + + return 0; +} + +//============================================================================= + +int WIPX_GetSocketPort (struct qsockaddr *addr) +{ + return ntohs(((struct sockaddr_ipx *)addr)->sa_socket); +} + + +int WIPX_SetSocketPort (struct qsockaddr *addr, int port) +{ + ((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)port); + return 0; +} + +//============================================================================= diff --git a/engine/code/net_wipx.h b/engine/code/net_wipx.h new file mode 100644 index 0000000..ed82dc1 --- /dev/null +++ b/engine/code/net_wipx.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_wipx.h + +int WIPX_Init (void); +void WIPX_Shutdown (void); +void WIPX_Listen (qboolean state); +int WIPX_OpenSocket (int port); +int WIPX_CloseSocket (int socket); +int WIPX_Connect (int socket, struct qsockaddr *addr); +int WIPX_CheckNewConnections (void); +int WIPX_Read (int socket, byte *buf, int len, struct qsockaddr *addr); +int WIPX_Write (int socket, byte *buf, int len, struct qsockaddr *addr); +int WIPX_Broadcast (int socket, byte *buf, int len); +char *WIPX_AddrToString (struct qsockaddr *addr); +int WIPX_StringToAddr (char *string, struct qsockaddr *addr); +int WIPX_GetSocketAddr (int socket, struct qsockaddr *addr); +int WIPX_GetNameFromAddr (struct qsockaddr *addr, char *name); +int WIPX_GetAddrFromName (char *name, struct qsockaddr *addr); +int WIPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2); +int WIPX_GetSocketPort (struct qsockaddr *addr); +int WIPX_SetSocketPort (struct qsockaddr *addr, int port); diff --git a/engine/code/pr_cmds.c b/engine/code/pr_cmds.c new file mode 100644 index 0000000..79fd011 --- /dev/null +++ b/engine/code/pr_cmds.c @@ -0,0 +1,1940 @@ +/* +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. + +*/ + +#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"); +} + + + +/* +============== +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) + SetMinMaxSize (e, mod->mins, mod->maxs, true); + 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; + + 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; + } + +// add an svc_spawnambient command to the level signon packet + + MSG_WriteByte (&sv.signon,svc_spawnstaticsound); + for (i=0 ; i<3 ; i++) + MSG_WriteCoord(&sv.signon, pos[i]); + + MSG_WriteByte (&sv.signon, soundnum); + + 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); +} + + +#ifdef QUAKE2 +extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore); + +void PF_TraceToss (void) +{ + trace_t trace; + edict_t *ent; + edict_t *ignore; + + ent = G_EDICT(OFS_PARM0); + ignore = G_EDICT(OFS_PARM1); + + trace = SV_Trace_Toss (ent, ignore); + + 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); +} +#endif + + +/* +================= +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 + { + // jkrige - FTOS fix + //sprintf (pr_string_temp, "%5.1f",v); + sprintf (pr_string_temp, "%1f",v); + // jkrige - FTOS fix + } + + 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; +} + +#ifdef QUAKE2 +void PF_etos (void) +{ + sprintf (pr_string_temp, "entity %i", G_EDICTNUM(OFS_PARM0)); + G_INT(OFS_RETURN) = pr_string_temp - pr_strings; +} +#endif + +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) +#ifdef QUAKE2 +{ + int e; + int f; + char *s, *t; + edict_t *ed; + edict_t *first; + edict_t *second; + edict_t *last; + + first = second = last = (edict_t *)sv.edicts; + 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)) + { + if (first == (edict_t *)sv.edicts) + first = ed; + else if (second == (edict_t *)sv.edicts) + second = ed; + ed->v.chain = EDICT_TO_PROG(last); + last = ed; + } + } + + if (first != last) + { + if (last != second) + first->v.chain = last->v.chain; + else + first->v.chain = EDICT_TO_PROG(last); + last->v.chain = EDICT_TO_PROG((edict_t *)sv.edicts); + if (second && second != last) + second->v.chain = EDICT_TO_PROG(last); + } + RETURN_EDICT(first); +} +#else +{ + 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); +} +#endif + +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); +} + +#ifdef QUAKE2 +/* +============== +PF_changepitch +============== +*/ +void PF_changepitch (void) +{ + edict_t *ent; + float ideal, current, move, speed; + + ent = G_EDICT(OFS_PARM0); + current = anglemod( ent->v.angles[0] ); + ideal = ent->v.idealpitch; + speed = ent->v.pitch_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[0] = anglemod (current + move); +} +#endif + +/* +=============================================================================== + +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; + + ent = G_EDICT(OFS_PARM0); + + MSG_WriteByte (&sv.signon,svc_spawnstatic); + + MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->v.model)); + + MSG_WriteByte (&sv.signon, ent->v.frame); + 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]); + } + +// 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) +{ +#ifdef QUAKE2 + char *s1, *s2; + + if (svs.changelevel_issued) + return; + svs.changelevel_issued = true; + + s1 = G_STRING(OFS_PARM0); + s2 = G_STRING(OFS_PARM1); + + if ((int)pr_global_struct->serverflags & (SFL_NEW_UNIT | SFL_NEW_EPISODE)) + Cbuf_AddText (va("changelevel %s %s\n",s1, s2)); + else + Cbuf_AddText (va("changelevel2 %s %s\n",s1, s2)); +#else + 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)); +#endif +} + + +#ifdef QUAKE2 + +#define CONTENT_WATER -3 +#define CONTENT_SLIME -4 +#define CONTENT_LAVA -5 + +#define FL_IMMUNE_WATER 131072 +#define FL_IMMUNE_SLIME 262144 +#define FL_IMMUNE_LAVA 524288 + +#define CHAN_VOICE 2 +#define CHAN_BODY 4 + +#define ATTN_NORM 1 + +void PF_WaterMove (void) +{ + edict_t *self; + int flags; + int waterlevel; + int watertype; + float drownlevel; + float damage = 0.0; + + self = PROG_TO_EDICT(pr_global_struct->self); + + if (self->v.movetype == MOVETYPE_NOCLIP) + { + self->v.air_finished = sv.time + 12; + G_FLOAT(OFS_RETURN) = damage; + return; + } + + if (self->v.health < 0) + { + G_FLOAT(OFS_RETURN) = damage; + return; + } + + if (self->v.deadflag == DEAD_NO) + drownlevel = 3; + else + drownlevel = 1; + + flags = (int)self->v.flags; + waterlevel = (int)self->v.waterlevel; + watertype = (int)self->v.watertype; + + if (!(flags & (FL_IMMUNE_WATER + FL_GODMODE))) + if (((flags & FL_SWIM) && (waterlevel < drownlevel)) || (waterlevel >= drownlevel)) + { + if (self->v.air_finished < sv.time) + if (self->v.pain_finished < sv.time) + { + self->v.dmg = self->v.dmg + 2; + if (self->v.dmg > 15) + self->v.dmg = 10; +// T_Damage (self, world, world, self.dmg, 0, FALSE); + damage = self->v.dmg; + self->v.pain_finished = sv.time + 1.0; + } + } + else + { + if (self->v.air_finished < sv.time) +// sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_VOICE, "player/gasp2.wav", 255, ATTN_NORM); + else if (self->v.air_finished < sv.time + 9) +// sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_VOICE, "player/gasp1.wav", 255, ATTN_NORM); + self->v.air_finished = sv.time + 12.0; + self->v.dmg = 2; + } + + if (!waterlevel) + { + if (flags & FL_INWATER) + { + // play leave water sound +// sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_BODY, "misc/outwater.wav", 255, ATTN_NORM); + self->v.flags = (float)(flags &~FL_INWATER); + } + self->v.air_finished = sv.time + 12.0; + G_FLOAT(OFS_RETURN) = damage; + return; + } + + if (watertype == CONTENT_LAVA) + { // do damage + if (!(flags & (FL_IMMUNE_LAVA + FL_GODMODE))) + if (self->v.dmgtime < sv.time) + { + if (self->v.radsuit_finished < sv.time) + self->v.dmgtime = sv.time + 0.2; + else + self->v.dmgtime = sv.time + 1.0; +// T_Damage (self, world, world, 10*self.waterlevel, 0, TRUE); + damage = (float)(10*waterlevel); + } + } + else if (watertype == CONTENT_SLIME) + { // do damage + if (!(flags & (FL_IMMUNE_SLIME + FL_GODMODE))) + if (self->v.dmgtime < sv.time && self->v.radsuit_finished < sv.time) + { + self->v.dmgtime = sv.time + 1.0; +// T_Damage (self, world, world, 4*self.waterlevel, 0, TRUE); + damage = (float)(4*waterlevel); + } + } + + if ( !(flags & FL_INWATER) ) + { + +// player enter water sound + if (watertype == CONTENT_LAVA) +// sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_BODY, "player/inlava.wav", 255, ATTN_NORM); + if (watertype == CONTENT_WATER) +// sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_BODY, "player/inh2o.wav", 255, ATTN_NORM); + if (watertype == CONTENT_SLIME) +// sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_BODY, "player/slimbrn2.wav", 255, ATTN_NORM); + + self->v.flags = (float)(flags | FL_INWATER); + self->v.dmgtime = 0; + } + + if (! (flags & FL_WATERJUMP) ) + { +// self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity; + VectorMA (self->v.velocity, -0.8 * self->v.waterlevel * host_frametime, self->v.velocity, self->v.velocity); + } + + G_FLOAT(OFS_RETURN) = damage; +} + + +void PF_sin (void) +{ + G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0)); +} + +void PF_cos (void) +{ + G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0)); +} + +void PF_sqrt (void) +{ + G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0)); +} +#endif + +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, + +#ifdef QUAKE2 +PF_sin, +PF_cos, +PF_sqrt, +PF_changepitch, +PF_TraceToss, +PF_etos, +PF_WaterMove, +#else +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, +#endif + +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/engine/code/pr_comp.h b/engine/code/pr_comp.h new file mode 100644 index 0000000..b237ed5 --- /dev/null +++ b/engine/code/pr_comp.h @@ -0,0 +1,180 @@ +/* +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. + +*/ + +// 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/engine/code/pr_edict.c b/engine/code/pr_edict.c new file mode 100644 index 0000000..2a5292a --- /dev/null +++ b/engine/code/pr_edict.c @@ -0,0 +1,1112 @@ +/* +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. + +*/ +// sv_edict.c -- entity dictionary + +#include "quakedef.h" + +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 == MAX_EDICTS) + Sys_Error ("ED_Alloc: no free edicts"); + + 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->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; +} + + +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_Printf("\nEDICT %i:\n", NUM_FOR_EDICT(ed)); + 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)); + } +} + +/* +============= +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)); + } + + 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) + { + Con_Printf ("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 heynames 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; + + if (strcmpi(keyname,"SKY") == 0) // jkrige - skybox + { + strcpy(sv.skybox, com_token); + continue; + } + + key = ED_FindField (keyname); + if (!key) + { + Con_Printf ("'%s' is not a field\n", keyname); + 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_Printf ("No classname for:\n"); + ED_Print (ent); + ED_Free (ent); + continue; + } + + // look for the spawn function + func = ED_FindFunction ( pr_strings + ent->v.classname ); + + if (!func) + { + Con_Printf ("No spawn function for:\n"); + 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); + } + + 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); + } + + 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); + Cvar_RegisterVariable (&gamecfg); + Cvar_RegisterVariable (&scratch1); + Cvar_RegisterVariable (&scratch2); + Cvar_RegisterVariable (&scratch3); + Cvar_RegisterVariable (&scratch4); + Cvar_RegisterVariable (&savedgamecfg); + Cvar_RegisterVariable (&saved1); + Cvar_RegisterVariable (&saved2); + Cvar_RegisterVariable (&saved3); + Cvar_RegisterVariable (&saved4); +} + + + +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/engine/code/pr_exec.c b/engine/code/pr_exec.c new file mode 100644 index 0000000..62b9480 --- /dev/null +++ b/engine/code/pr_exec.c @@ -0,0 +1,673 @@ +/* +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. + +*/ + +#include "quakedef.h" + + +/* + +*/ + +typedef struct +{ + int s; + dfunction_t *f; +} prstack_t; + +// jkrige - increase stack size to avoid overflows +//#define MAX_STACK_DEPTH 32 +//#define LOCALSTACK_SIZE 2048 +#define MAX_STACK_DEPTH 64 +#define LOCALSTACK_SIZE 4096 +// jkrige - increase stack size to avoid overflows + +prstack_t pr_stack[MAX_STACK_DEPTH]; +int pr_depth; + +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); +#ifdef FPS_20 + ed->v.nextthink = pr_global_struct->time + 0.05; +#else + ed->v.nextthink = pr_global_struct->time + 0.1; +#endif + 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/engine/code/progdefs.h b/engine/code/progdefs.h new file mode 100644 index 0000000..db86de1 --- /dev/null +++ b/engine/code/progdefs.h @@ -0,0 +1,24 @@ +/* +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. + +*/ +#ifdef QUAKE2 +#include "progdefs.q2" +#else +#include "progdefs.q1" +#endif diff --git a/engine/code/progdefs.q1 b/engine/code/progdefs.q1 new file mode 100644 index 0000000..eb15c45 --- /dev/null +++ b/engine/code/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/engine/code/progdefs.q2 b/engine/code/progdefs.q2 new file mode 100644 index 0000000..dc7f3be --- /dev/null +++ b/engine/code/progdefs.q2 @@ -0,0 +1,158 @@ + +/* 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; + string_t startspot; + 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; + string_t null; + 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 basevelocity; + vec3_t punchangle; + string_t classname; + string_t model; + float frame; + float skin; + float effects; + float drawPercent; + float gravity; + float mass; + float light_level; + 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 items2; + 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; + float pitch_speed; + 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; + float dmg; + float dmgtime; + float air_finished; + float pain_finished; + float radsuit_finished; + float speed; +} entvars_t; + +#define PROGHEADER_CRC 31586 diff --git a/engine/code/progs.h b/engine/code/progs.h new file mode 100644 index 0000000..6d3aa8a --- /dev/null +++ b/engine/code/progs.h @@ -0,0 +1,134 @@ +/* +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. + +*/ + +#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; + + 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/engine/code/protocol.h b/engine/code/protocol.h new file mode 100644 index 0000000..e1390d9 --- /dev/null +++ b/engine/code/protocol.h @@ -0,0 +1,173 @@ +/* +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. + +*/ +// protocol.h -- communications protocols + +#define PROTOCOL_VERSION 15 + +// 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_NOLERP (1<<5) // don't interpolate movement +#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) + + +#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_AIMENT (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) + +// 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 + + +// 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 +// 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 + + +// jkrige - skybox +#define svc_skybox 35 // [string] name +// jkrige - skybox + + +// +// 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 + +#ifdef QUAKE2 +#define TE_IMPLOSION 14 +#define TE_RAILTRAIL 15 +#endif diff --git a/engine/code/quake.bmp b/engine/code/quake.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1d53cafd4c4c5371a143e5b17e1e396e9cd3101f GIT binary patch literal 286808 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�u)v3D^p9Rk2p%#lY4^hh0)5Bz{RX zSp1(2AnoZwt_GU9ONQfDOi2K%!OI{Oxi#h1R;dDEYORDrSnUxtqV2N~-4L+_zeBg$ z$ld?5m&Y!RPt45D#Q>wsT7Ipw-a4$dkC)bv3)aS`a@cUDbPc>+ZJy;f_ESrnQ}G-X zW~OK7tg$2Q-5qkl+msT2)PR@}blkP7up!!+&~vg0oQ^s?a!-NZ@!9P7RB9@g(()nO zm|3VK$sJq0wy@e+xw2CXUdhp6IXI;p8JYl)OZ`ud;|J8lYCbZ-Z^|gHT8&tBuY_7} z=){D#I5O0-lP5C-4=2(qLdk_A&d-wCqa{153E=2&#=x~g6m~~3Sbw)i1FTURq8t#k$ zFKH~?L?9Pj)$OzU;eyV3TiAlF~#(Kq%V9^r_v2M1wZEEK!Y zKbE(I+Tt=pG03CMN>4Z!>el-cklyA&Y4D&hxC=t&ckWVt0XVImeONwwFIL4VPo{=7 zPzz9io8y_>bg51oh+MFj5B8{19z6P@cJ?8xxUhW(-(0#u)A<4PxP15)eM2VVtZ-Gs zQ)?V?T_86^-O)K(aBKe};N_1YK4*h2UBL0&UM zayzoTavV)KuLe>IXoPjMO(fIf3Cb!8b@6m?x^iX0rwLp;dD=h!`TF*=_Q}tJ-Otts zp9iPETYL5E*8P9F_3nS|J^IJ3xBlDJ@BR1sYk%n7`6}q06N_utOh|j-2;=gGms(`i zrauEuUGuQxn^4zoL9_#leQp{3?u`if$0NMe91YmA$#}2_S8gwOtdBt-n|>2{9$J}P zW*2yiXE{x|#p*7;U0hl+a#2||&;fZcU3_G`PMaH`n0MLGZ+X}3Utr4+aJ=;)U<1lW zN`tYZ^`pv+D4Lfs<#-DsRLis=R|G=4e$U|X7#3R5@*h_h%YQZ^7IxV@*uX;o=GzA{X{%o<&J&Ki7r3s2fSZ!DTz~!zu+_`1Dr~Q8q5|Z4A@e>GFzate1{sR1Tj!stw>rlY?BsmJkk_EF=M+#c}dF!Z-G-5 zp&&51x*%5U6D*6;FTs!t>Y#w(b19!cgb}Q zN|uL+zJyh9&B0y_39!wP$H63?C;N~#BG6WqM<~)W)LNxuZ>+iU#m;mv0Bpb0Y>w4b z)ss*S6kYLLtW*sk&^->5r0vv5YTj1xt&bOXbLgUl{}>>)4XtBLrY)qRUJ$4Bs8zdU7Q+=l&VrN;#zb zmBRYeEsqioSD-k{vx4%snQcb zTBEhLY zNak(MFSpaH{Y>RmqPr!=(*8yt1h>I(HQggbfm#PB3DeN&q{2m*2B5N>(nKORPWrs# zty)y)co*l+WP%pD5RXgLJ0oR-K!{Bm{@(m(t@BR%zmt`E>9WKMoR{p%bd(u???g-(Tp1~a3|=Q0o4 z`DX>lQTt9uUB#K0q%d;V3~!Cug12T8L%g*okwry#Yu06>k~@y=xt@^XKB|}!lGhIL zGcs?LKA<127==Q2fLsWwExIeTeyH}coqaNZgt5>G>rNh~1yMU%RiLXn4&A7TdxX() zJcgC(loEAm*=nV&X|-$IZr0s91{XaEDn}kSi*GC1dWf#2JdeD>V+g`%v$gWR;iu~i z--KKa$Xg+^{TH5eg0l|Gu`*14TcV;hbjURoof|6##r=n+qbJQLU)GM_hnk}CGUH5x zV9Z1f3QKmt;p*-8*-#I_UX+JP0syMr%I>4I+~TC*_395kh2Q4d`$U&bQ(&jw1%5-B z%TX8MD_&p#GS6zN)mXORc@r5TNYH;xb8t-HuOVDSDB*Y3X4Q%5R4hlJRF4LiX>hez zr>HyP2?UGhH| zl4rdY2}7fs|X4RtNyLSHQ0+Nktr!4R%PGXdqm%n#Eq9$gjUrvlnw*% zg0$KSili+W-lp=DKjLGoxs(NI6aC>!o$f@n3D~k_%ht;bA*)bf&w>T$W&+AQq9?$g zmFX7Ztp%t@Y~ zLNaeq#5=fgzOb}Dae0PN2K^{wRA?p>F^Y#M?^Ww}tCFPT9hF>8<7V=Oys=GoLr+i^ zn5nFCZyCRpeoKzj-&>HZ@Y_YgLGwgv3fX{Q9XJ1EfCEIjWCl< zrt%%CK}usjePaasej16iBxOkoN_a=;@TgRq+H7_k8+-ZE_@&92`FuN7*k7r?-rW83 zO6RS`%I(U{ACi)G?fehj@BP!>2mi;Fy~TrtLuIV-i4FlhCf?Ip_O z0=Cc1anTO8Cu>ZLOwdFr*+I9)@0txpyU|jOY$i4Tsf@w-trk8Z+qoEz7e=K~>ioLkJ5 zYIgAifWnm^MVAhbUj0d{7&U3t#+?msWrVBxlcA+sX}8v2*S*yi-C!(XJeE!r2=?ot z=eR`A39#J8%}o?BbeGpvcY<&@&=u50M=Ic5QbPpZ%9yJZ!6BBVwV6>?2?!8ZBF)Ix zzJolQsogVGK}F6H?)WXBt|GyRXGl=US6LP0O1Qj`Di5;dE^|4vF_?+{(3OLU7=1}| zw<<15F#v3NLck&L%X4hZ^aN|_QQex(BT5`j27B?!(L`fstX2bLNg*_<04Q^izLIy4 z(_4Lf3OuJBFjIh{3yk0Dy4m&ff#KxVpNH4e-_>q5p!BGJ2Dx@qjLn8O$QPbGimYl> zI(HIHG7z=_i>KSQ1#T-lXp9?uVtSQR29jwV3bHSA{XkvEF*4+`O|~KU`Sf zUMzPTH{V#_x;M9SYd(K7Tey+0+$?NtQ!N4F6yExayKiOyp;CN;HONyDC-4^N^UYuo z&B5_d=ts*xI#H_mxHu~HXQt`Ho2Adr^2V)vZ7)^mrdE5Y)f=;v2%|9L`oThFe`dZk zwQxnXB0=dSQon^IB+x5#d{byevthO(w|sS6FKQN`D0G60U{N1-ZT<2_*Le)_IySeQ z&QY>cQ&OyQLc+7H|G&ZRd;X!O#1T|G9ebH<_!S?%n^ovvYT5mdiWmWYr0( zVW}#UtDGA6X-f~k@;utRP+aG_derR;X|Vk%*;eGo?y088aL#?sDr6Y8IqHT+^t?sc zy)YL59t27f0kbUAzz5d3@?4Y}sIr1kA8sbz@**NbQ8KT%2mC=)q{`S)MJ664L1?h( zU2uls!xKgjBZU#9tTcM|m9}EV-Iulo@yf|WV>cdbM}b=`4~4Y(TsxO-WipLSrk=~v zQ?f(4nVw`j5e~EGF8;3(%8G8_Qtc?qeSzPO3cueo)G^$~}5O;5r1el$JxpI>7b7cTfO~3{ruz3`@ae9eah7%N&($~xZLXQ;~aTU z6i;J~9PH$&jNLhg))srWtEcbP&OQL6MEqcbnJtUhAz-OTk#Ou*To*I2wU42$-D^#w zT4`R4tUvYqMSGA*Q0R=neMM%{j3U!0QUJ_m?M93l(e8eC>E!BJAY?Zz*Yuu^}TcUxT-7$@-niVE3hFn|4dW+Z;0m zXI|kv-3Zyagdkj`3DiDyo1Nc6P82s*YlF>}T6ceH@%XZRj zOxlHZO4k(<;YeuU)tyxF`uu8lv2u&j^r^L1 zvh~w!^ zCUl_$ddMHf=KeL-9r()xhJ@UhJxJLqT^iyoP>jIK2hkR=ayC#m z+%u~fo*~{^@n_*JBPCm4G2Tx#AA+|pwK|jac7&oJEzsIbqV^CbO}GfD-wAqT*A06c z*=)0rbI6sdU{PK>U^UXN;t&MC-z2&(K<-fK<;k}~?oqRL(yX7=tB08anTZ)%@v;C% zOQ}ElVes$^goR9JAK>l0|Lf+PKjt|}YR!i~CiJVk^RT@0KmlXNPde}XDmeRC@nAdm zO8XCy7m%+>CFYVAI;WL`$K4PAD!BWZV!|mkAPF}M%qFxRx1e;n8)We6t}D)?X3&1S zHM&&`Wpw=#!LK8O?zYdi;rcf+486@;behmFYVPD|NK_zEu9BglMuAYVy5e}{-pAj> z3WhXTWcGFz4onOg#a?I=2HmB34GJm_uhJln2TIV|hxbaeRqBKicvVzE-s&o^qnVI2 zktnq3chB^VK*2>o&5-n}=mM4QlwjLEmeypmGiM-ZRVxP-7-!=Zw=3)uuK_X+xxks= z?nJOX)@V*wQ~;TMI5=xDEx{}vjE|^Wx(andmC+NZogS#(zTqwAF9zcO{uJc;CH282 z89`&s2M(Y;?n{plY_-@F{DK%3ab#oJ!B(C!gVWqZObyLpSvJ@i;~w(~CRnRk2a2im z?0i16c72&(_)2%Fa)Y?9L=Iu9SFCTBsl`_!?(1g0d~3blkIklDdg)Sh$2m8hooyz7 zM0l&QZg(H?S*v@M8}&de$J;PMK()vu?dnC<+NE;fOq!U1`21>ofgHxh>|%Xp@d`@9 z(#9*9jiaUd?aJ2O`K1ktF`9HB$DE_9v;q-k9f~J|H_?$*`NavF zh1+krG(NeIU8!Cr9O5`rxzj%Uaeez)W$=TIy&tZ1Ke+PB&({V&Ub*_t_W7@`+;}*h zSRNan(h89t$BvmHu0}qx>9oy{Qht0AypRqIRBaB``bBq2)1_{!Hg2?O_;$4~^ri4> zn`P+w+jVwwYX%nDnB5sxo9g|*O`v2GHVGu+GKe^_Xpx%y> z8m!6z&w*T@of)3tZ0oejjnnRLILhp%MgV(3Z=zQibN=E4ql4fma;(*v2v9QV0Phkq z5uhq^OVlfvMuqkgAsik2YuP-p3}rE4nsL|$6w~?9W(@+saFAKc9#Zd971RR*TS6T= zfF5Ovsc(!A4oIXnS}Ip^yhTHxx)DiX!dvr#31H2A0Dd~yI^KqjAmvR{tt4Dv{m?#2Bjdiz*hX^+HZIxHgyGSX|j!DWm0f%k9_KuOZk5iPX}iOC~fq#&X_z^3D71uS9P#Q&0oP zTxsFDo`QJ3#)t7HvZ}jfQM)*;E>9<7bMr|m%%rNhLMyYp8DFSUtY)RYKc}_W&DE>7 z$?ct)n|G8p7+3ES$dbPjeuWB_0^mraT%s4w@Z0bfs~-6+mo85(l^TWG>)HCF&dHbM z-h0c}-lGvuef#6?>CbC}A7m=G+pqm<^Y|}PD;+f$qMaFSG>yL6g>`ak4J9Sy8ieZZ zFyBeZu~mkN3A`n)n;tsO*hg+qZJKcH-s}AJr+!Fuo*IVwXUk82qU;s@-;9ixusZ%p zR|nb(tf2P{Z@Z4SXbV&&MF9hEDM?rDf3&5IUd=QDif?T}yMo zxO2aB{8st!F|M>6+0DE6D|bG~_fP6)AMO9@zqX$IwEMwtyB~d3-hT+2&Ebq|ZWEnb z+PP22E`qSpLKP^G<|!&jcNtXw1qgn6E9@+d{~E zRvq5`??B!z#QbQWUD$cJh!fZKsN)LtyC|ornw)v65SQz~BmI%n1jm*;@%q6;(2rMX zdSAt}MjImn9w5e9;&=hHD$xsoE%k5p6QJmXD0B+a{#}HE_*um5(r9~IdD&fObUNxXjx}d1AB6w z*4;rSihb&U)K0(y$N>pgpggeEPk>uE-eUPSI($Ib<8v&RcZZwCN`w*`G5pioPy-M# z0cIQWScwb_VOxyYptjfTP8p%qsOM85x>`sQOborz=Tk|bF|~SJ+dN%vKFV*Nu3dd~ zdHq^CzcHU(&$33yU!7mtq;_|scRMz>G(IuQSzYK$;n<%Tx%&|sT-HE2yzeH03Rt|q_H$G?` z|6--}X0rBhx%X-5=4YF)ei`iks5(1XcU;CSt;P%v9ZfqPC7ay5Lc3HfogR1l# z@RmCQS=Ia~8NqG`W6D-2=C9Pw46$%p#Dy&fC^s&gWTSJ_2@j1#=Hy!hwr)-iw|Xta zTPzU3m1l%L;{?r$##E5PFjP``-C{H8G!}~`1G#eh7AousbC6I*WjuDH5EIn`38A+k zfcLYiLa&h9GROsE zy*xq>(#wm*JbtwO;36Sn6mNMBRIe7QfF zE0c^?Ie4>v=UHjzL3#g8$=zGW_5082=g(AXZ0oT1@!tk-|1{e>-u?N1KK#x9*#Fi4 zUOjw5I$rtcX>gw+_D3kdjr*UXGq6;5r1e5EMs8J~mgWc)n^j{4)LlXsEb~zkXjXr^ zHx1Mc^?%LOa+HUwGqVI6ZkmE^(})wcXwxgg3yNs?(m33QD98+V9~)34SgwSCK-~-$ z`{1O?6qJLppfgSY0D%P7Ee=;2x~>#nN&S3^J{>d@tf`Go-T<~(OIKPn<`B{*GttTD z+j&mH1ydM?fxd)9P+~}16%LFFddhJyGv1Z1C53_X2UWOb%EpI_rBMcrC-lsM%2u#0 z3)5v!@d3FQwwM>}fL5=D0w9R+OcIo=%$1~M%HX*GTn!BnI0&R<_~=B}9)}}H`;A;c zyReKt;Vnr+Vnohbc`gzQBhr0wzT{ABB+3QANxGHchf*YxgY6K0C*murS1_MhZ=cj} zzDLdNYUl3C#y0u0#9UE=Cb_(sTfY@tKhCdhUb;LxcG=viVV0t_eXi}u-S?aR;@#IT z*K3hIa5WqiS@>IJ57z;}+ljfv zSKOSQO-?9r*n$u!QG%Ncu%&yH0uKnYu`6b_r{})D(2I73M@~lXYHHJ_c|`djlE?je zA{3LkyxM*%S$-|sxL-f|W%c-XmHpqXzw%Z6;FqnFudm+u!^SH=q5<)xX{oQKDnw2( z(OT{ZVYdoh^SdTomFA#W-0-eR;qiruM@NTTSLZB3tC<378~!5u0pSVDknEhJS=-EN zIFIWWapkRttTG(oIn>*6i^X)!u(KF;neZSiwiIBo#vJ5{U^liA!-jUKUJZurLx9mY z94U+`A1NdCYKqA+CHIBHIK(A!E2o%RgsLCURJ3WRc`nqW4|szoK(yE)IuYX zA%}*h-fjD-pievl{np7ZLuV+Ty<5HWe(?B{G*qGYMDMJWROgjkX(#hmImZXeYNw^budqvc!)iT#)}Uhje6V1E+oIhv5M;# zDR?2v_4Fml2;2w<+ejF+C29!5EabymCIY6gRr8dYe`kC)_wxA6<*B)Rr89W#z3waD z&z1VIL?y9MCdFWWxtv*Tu3tN*E+YL7aH}~=2s(u1mM`OM(9T&u%uinT+fG<_IlA?{ z_59rz-L;jb@K!Qxa(p&%X=-+kGD25Q3(b?&t0&FvN9&z8R)Ujc;bwYm7vN2;4#>io z0%^fpv{`a1NE}x98De$vTkpP3!M@$zjZQ4YuHiY$PZ9n!o4hnb#g=9l*3xCF-yhU& z{`vLuuiJP3c=gVIY@Ys(VhhdJe@|E6*7+ZT?Z-2yxR;5lwMK8QjjO4#+?RR`7a)qo z)w*LChzlUw?5RmpD-rIakzOOWK(1dgEp6;d>H_o6e@=+Ep$YM_2?=_%AFH2<&B=FQ zwHNTAFgh~w%aelCZI?=_A4v5=L2iM;l_NS+VL~K3bj+|-#Jg1O1TYPXU8OWq zRYU5>1Z9}7i%LGMzV%xYg=#sV>y46MP$c?+ zQf$CRY8eG(dF7bCsla2vuFek1F)uZ$m7w2f7PIV_ZB-N-EP|b*RFcfHL~#$Yn60Ez zow9QjZcL_t<$Brnv;(p>V__?UC;ryhsji7eijNLk`$c$bm(H%9E|;ShqelNU#Ms1n zIF21E1P2?i27o3qILj5?_08Cnyq`cZ>`PD7a+isf6C*4kF+N2eF4?$?OU35;Ch?a2 zZ1MWa`i;d>E3sT%EM3i2u2BZzlIq8*b7F`gvAhNJ3iB26WIrlAXU<$_dvS~XcYW)9 z;VpU3jqU=u6Y&LD>-{?^d++JS^?T{!&0J+KTiKgi>BD=O1W9UB zi3SoDtd*EuC%;zVR}alk*EBq((R1^Q%qy%Kkhu9FmM~)Tkug=7_xKEfZL15byKC*Y zYCE3<$G^RD^0&dsZ+qYU`{vp23;TalKmEJG8(%UdQ7K)4Z3ej>7UENz(O1a`HYWnV zf>y&}dlEvf=&{A?>K2k|J#*o%j1;i6S%Gr|IeIhX@_`#R=|DMvR|`fv z6k}?uRH_|zw%CV}LOwrZiUVp)alm5rJClc? zfN%n~t`8g`x1tGDi+ezEP(5kY?@*=OvV$)`@_EK9l;$HQ|MD$Po(*zG>Nke)ei8OC zlp~Jo!AYrgT-kdwhQ@gMLFc_+Hwazm-o^_SJoq9wBhli0fnx7veGO-~SV3T)Mp9RGep(SwAkQ*6IT`*Nkq@;Yr9)73l3xda2K zMxv^3?ZJU*m`f`?s_W}el6EEPYLnSmsFDWS#c*?*al09g!Qm4qAOGB(pf`AzV3o>b zvCZ0c6zGhsz=jfK;z)DA`?(V@@44)d#UYh0#?oam6F-m!+;hW?@1jI7f-M#2%t90{ zh}*7Tub*_g^(vD%afVU@n7&<4U^ne)5eU>!I_~v$n~L#fv)!Pt1c1qbtF{-`Ap#p? zx1+7CTEz}nBqA|SJVcUI>r4S}g=N7DCpk}DAII3|`E58>La^0fWAkgJpXJYOFdFb$ zX0EMRO{&!pw$1NFn8RZ5Xro(nivcdWWq4b7`Eo*GU<<4C2+OS02)@m%UdwIlUb*>b z^VXBq*6W$-t@P@(*!;>R!n9&bd`jtHuw}~*)1lxkIOSbm5@Zo1=F9VoTfk}mOLt#C zOFK(-nVp}Yt3tZ8vay$4C;Inw0-hJDr)$kO3c*QyX=`qID_J1Ld#BWVtw@)Lh2@E< zIr{H#_uY)XdFwf{zvY+F9*4$hFlz-RA{$ob0vOA*;x1$1Z7h3vdNH2bSSlYbH@-Vx z`EH_guhji``{5sMe(xVj2Yhy^A!Pk8{(b+mzb7;|GdKlf8;`!I-~BYR^I)=0 zt#6f|Me|hc7s|O%L&@reDl$PS18R}LKDff8nkxl$mj8a}Gu4Y3?zxkR_Jn=&XP zkwL`CjY?D@@{iaPcU26H{9+`I41wof#LqhlByZ_w%ec`@G_v;e!0u(4;+0NIG7Avo2>vuD?^GyA`e)DPW%Inm&oy+$Y z*7oAd+u8D7^TzSoMsp?>f0=j*ed)jS6(jH3wRMBxMp$xXxVq;@Y1u2S+whkD?_4@* z0thK|tMw=qLD$ttk(=0t z&z~A8RkhspG3AiUU?kcWUl_^&YASFFzOkZj)=puq-p#=@1i8A{p;Fo@3jg{sBHuUn5|ep zOq1-~KeH&@cPseO*bbje=1Y~^AGF{7RqxsF_W$C4>%RM&!tNtf+{)ow>8_I05-hqU z)$Xg0m{%A`R^tUq5OB>c8%t6HESDC^cfs3K^)4lw#CS;}AgVl7Cgz;*SHM}xTvq5C z>PyHjZZ&z<7}jFK5`^kD&x8~%7PG@{q-m2kN&)8ciSS1S4%$VGa!lr*4F zRmHHDbTI-P8*9d_Ffxr?le~uG3(1HC1Vkh}arnq^go&mSD@#}x@@(f|XhnF(z*|g6 zkKu00wg7%P!o_aZ{wdszEJ$K{U$Buu_czNVL!}8Bko*XstbloJx|yboSC@ za%y^>vfIh!R<^vodE+cc2dGRd7re37e{b!^`&ajWP;Q-2`|FbGhs)h&{8ka#el+ud zWK7a`b;6g)oWKxuxs^U4zIfm523;bX>*evwW0x)i4%BiaL3pF{#`WV*sy80zgR?^W zQE=;n>Wz0c`tKx5NAZ`<|b1xkLAI2OQL zhImV`5D|=G5x7OLSW5zumTP6ih>yA$0@g{2Xh|O_8Z5XlY@{IP4tJ9rVfAeochqcz zCsSS$n~BBqfG0?ZGYg&8TQ+nX_XaJsgQT-0`3N9hG1nzzHYXt}?0UC+@@{bd)Ao~}qBhhHo~F7dMf#)l&&CPnZyl%#cYcR5O)BT2kT94kAWS=Q z$p`>xvV3ICX!cQYV|irTV4Awnq`GGa2{>dQ%674Vx;!WR)pmm$w`sbnp~u8+go^c4 zXi>h{{099H1lzyohlT~fgzuOD6-!cFSBb!wN})E4@6xA2n*`E*oz7A(SUeuK+2cYM!aBf&Y>TJ{sc&GDI2>2(Vi3(S6e4P-59)+zj}9L@criA z2dmfKOqO0Nbsk?o{h~H_r`CJ0TzfU1ZYR@M*Bb}dZr)zMa(y-l3!NROfXvvXp+!A! zU>0={>a-xOK^*6ARYdp|A(hpSqIzT)mLsqg%Ozu?Ha)+-kgILpcy#sF2br~37YYaU zn?J1Ye_g%#MX~e!Yezrp>^+@HEYYk@M+2y#A5zOLw^v`M<8V!c_PRSpXzh{L^_K3e z{$U?nG@k2rYjy~&#b7pC`$VQPg0}{?unrvn%!b^?)TdiOO0_+*cgtixVuzVh4fsV6 zAhZT!hUl8bQXP6A5@Hrx5Ad2Rj7u9J)TikbY7*!eDZJt%g&|;r zrOlXP`1qKr2P(M`i{)sHZUMKXXYSO|2kPhD#v_n+yYqnh23w7DUW9xSz>rLp5>e;$ zA?orvC{OhBD_g70 zP1(9 z9DJRxj@<=szIc(5lEfZF6ssjMRHXH!M8v}V)gRKA@p^|Nce^h!ICtN1rJ}{npLNSLtjaM!)8!0rWiZnNEsPZ)PN$t3=YGX^5MhKOI09g zYSb%Iou>P3+3*&`BY%PLfKz0IPH?{yoVV+=Clh9(AtdPPLg^tAe&e}#QXSTOQ<3vr z2TaCgCKb2wnD%D~xpdfpFe}zeF$qFWb^~ldS{*8u<2YouL9L1S*u)GRL5Jql!D$S8`jV)Gh93f=86^=3S~QNI)p;rYa`nT46&X z8HiP&eYpiK5W_IsT566%j%|r}20|$gDQ;i~Q9Biz%3WuWr5Rw3TG8;ibGgvQM#-un zbM*Si`Wjp{XdS*~3{WNt)j3>rEmm0OyYysBA=SyjJREP)Y^}Po z6~8r|mINH|R(=GF10Uioo>y!U7zUKh(a->IndRAy13KPfZ%|*}CRc)2;+Z^p8bU5w zrHCH`%GQRAn&H1_ER753>UAPc&0`4Hwid7Sn;4X5?*r0YuG`5z0 znZ~{Zh0N#DC^k9TkhRiFYq`=j+8Jaa46psT|LXT+aY7pAZGSDRQ6tS+mZSAp=u2{3 zk_Qd!3QHd8TSN$1CMz5w)G&RG^Nm|ShM1trz?}c(moAOJEMb8wGbNY$_%uniFI~F) z^7z!)r3pRi^{ME`PHE>c*CM7b+4Y3nj$d{mH!>t0&6u`4Q~U}fk)jyB1uYwv3Qm#2 zs4(W#os(jXO*A^NsDFl(s%C^gb^1KHu2+Jh=JR z?0n(n@!9bi`4(-C^MWLP0gKkk4Hq*-Y(%yVZ%s>Q7SIIh|Lo>!E**{wo?rm}qhu9k z8IhS7*+7MAO3Z*cSeL*_oKh+KKot!E%JHAY$2`y zreW-s6)>c!G$~r(hYPM^jmEN_9zO zP&k=N&MNRsnZl|g4S7)EM=dbfJV{NX&n!xS;}+x=r56RHW?^n-W{A=2p}7tJw1a>! z`jmf&YnEq9#TZ!5*ap8O22%0-y-by5rFBcDtzz|NQ3N=M~Ti3^!c` za06^XTB}Ar%?b01{Pa{XM1-8TtfEL!ozt}tfS?v7Am9-;=O8~&c+2xyQd1YRt2+zD zSC_ARH`xDm`}nJ?um8HX_lwryudbi`c&XgK#G+t|xyGlb3(l-dXJHR^eQ<4X%UFXz zaS?w^0nlx|09!L={dqA=-16>S>@sWkdsXc8>@q~S}Cu)Wby>LuXln;7Y z7?^%bG(s4PU;-?SAWz8r%G0zZT_xLBQM;3g>FG>7PJi%HDpSQDQ!eyC>7kxLpaLE= zJ`Q?Uir{S@S__p0TE|E*6lkk2_IJj|wOI`lW^)oju)K@p`io~~kl4^f%mG#mXJk*F z14@81y?|r5lY)L?>$rI5Lux5dK{q)6w7h$N_lJK^y_)X3zZ77K#}fC|*K-k6#d=xH zt#v9-A_&wZFVLhw9Tq6PWv(=W#IzeSFQ3v!Bsi$Na~52+YF%5>AE3<&9_#Tz_o=~_ z`4p>8h9qW;ZM&|eS>C}xKPMb<`f0X>;Hh7xVHnz;8RT$Rhhps?fsY274JGnHxary= zH>(T@RY76B0zei`sy|a#2j0;=`BR%&9rT!u=Z3M!0u-f*438NcR-nZfrO(KDg!)Rb zh2NSYp*hK6IxutgU~mu1-7m#d)* zWwaKhj(;KKnzx;cfSk)fmeh>o z*U$cX>+F|ny^pRQ{%YspAL`prr;`QBDc~ELMg)!`97Hy3CeqQQ@X!TG-eiV=gDo-> z|7@;w=Aetfj{+iW`iRDenM!0H5)997Y zn%U|=iCtE15doo9r!l&EqvHj$mgv+ZKP=MoF70tLQ2iXtWuGp0)5v@*w!mW4MSq2DT|7h+5kF&Z&cPE*x$!&}^%*2&R|K;o(k z#=$)$j@qIGqJ~2)~4p;`kDV2t^{u)fm#h2y8<*($Lcw)Sq^t3}?VwT`R+0V8k>E zg*m}>Bd`_r3Uh3vD-Qp1>eA(zWVX1Fzmh6+HoEtVo9C>KOE*5g^7`*P-~A73z3*Qp zEJ0zqsuZUwQtmJb1)4D(U|Doa-meR(gh-MU443$b2qd2p@LIqaFlCCUasiA$h8)=7 zg-Pe%(oyXjH4BKS>rYMh%m|W9 zH3i6qwV8v=sJl2kpQTK$kzSiqIDbBC?bNv}#D=YGTt8pA_B368cct|~ZRgp>&Zm{_ zp9Qad-8lS$vM^jdO{ScHE&_9ts|tD)&2Y`uv&sC%5xd2G)D1O>$?mT#f1JV;er3!U z%t*{I82dg!%X0jmj-W4v+{P(&i|gtIe(Mz1>8|82V6fiH1hiq*iVVDUev28)+HDB% zx(ID$tF(QGLNtsB{`4WhNMU0)$5O@`&qbu+v^Kfn4>a`P0Ul3hEZE2stre z-QWRD((#n_oA}Ef^_vg7jfd^}xy5DeU6+PJj?rKgh!6T?^X}ks6)6k+3vYM_x02>9iD%owF zrn6kh2gHd!N|k7W`9LfhHN!e( zOEHrTBXeo_84bN~+<_nlBcsDmgN_#sarHXS^@wALjw)&v>Cwdv`oWM?h-Z^TFu(Ow z7YAA?2*!<;RWKc+B&Z`{DW0ZY2UW*KTvXQTB0tD&n%|$ zS63PjvW@STIv*CVy;JIcm~DTY?R;K)<%j9g^~+REC%kzgu8R{EY4l(@PBIKj(2bB= z(_!{vz6g!nZnN&J<83tg0<&fkL$I}BVxuBb66l>>RI}_vCY34XN%Jv2z!GfK4v7t; zfECU4V!(x2tW4cPZ7G+X-#RiZZH0!7{bSfRrc7Rgu@HHyydK7gZ}#yZk*hFLI3Q!n zL0ira%OLjM;6IRIxsTIi$9H?pdwbo-hl8ib+wUCjymL5s`=I}1xBD3Q?F0ZRx-P2h zeodth6dVh#;wBq3-z1)4(0bHsl4W+=6kr#A_fT$A2oW)~-$^KFxIsrTm4E9$5n8Lk z#UPdNi{~yMj~CeziE<)YhIJz;c@#YIUVA>BTmo8q3Qn8e;Uf?Y(0#l?S4~5T^ zzAB0vMl3LoXmCZmWdv`B+(wdu2BM%@*Fl?mUc_xsEKOK&4M8p;0EZ2>78ba6z!{sE zos7*dEaj%>v+-A+vq$r$H+ZkfZ+@!M@mragc0 z?uS3z4TD+639TK?4k$LRud|;IaTPNMEje?YypU6;4aH>#KSM#TMKcOrjh{1HO=nQX zbR2a*fdG@}VG#=^n9L+sD(y3Zgx9v-Ub*&Ow*BWzollmU@2_{?qP^zCYz`>~NVi{F zGK^&|(Cy%CZ8l_Hpa7%pnlW2`g_XM1{RKk9`|AplTZK)>Sb`QlPHufsfY~5KSoGI4 z!M5b>VqlaqAeT0l!iyoig$z)OrW(i&hf_bb6c{Pkp$dO#2#8%sWN7ZPBDSR;4N7F# zxvWM?CFesx)tT50a-tBg2ygX-GGfwu^Wm5>hRjGI+vvG5#Q_O^oLfwfSi7t*X5PVv*>uhp+tSPy2cz- zB!{se?3F_ehDI4}A7}zzZMJ-tH8RAsQY#8+70Je7@%O1PV=k{i7s_Q=6&jWE^0kjv z{k5%JXOB)9)MUUmO0+V|s;^eXdZz)unxKuc7HX7DFmIRH(hCQ~(y%uvR0QY-O=7vl zYzg+Z@B}-NS)A;4NY$8)D zZtP@MT8k^Kjq7h@*E-{qb2x^4Ej*c^d9IWJ!K2VgB0M0k#tL#F0Z?IRu7#r*0!#li zS_qtKErVx2R6#*4*763wmarxyw7>>}23g~nch6Qj_)=YBdhYH=NE<4&wkJxgV9nrE zC#e_!!8_a)ic8@~$hlzO_$`pD&g@bT^by11(3Pe$6uL%xaz2_nq@@UN4Q$1Yed?Kv zE#ymFv8$!_dGq)e#r}_Stq<4QkC)5+iRpz)NL$HuzE_57r@{5tH5BHD>_VA_;Vt9d zA?AzgV&vRbySYA}^7A7DuqV!M?NPHWJ4^Nz-cn(h)P@Y;hJj&+6hkOw^F$$nw`|gH zp%d64tqko?cFUO^vL_|-Oi!R=loooKphwpjC@y#lU@`=Bz#P3ys1FwE2{u?XQicv? z-en(#UO1+Nx8{<@0bSGLk$}nJNMVq&bFo4X$xvcQD?W=Krm`9Hf~E$AOk|qr zT)kSZx8beSG)QI|)NZsm79dw9L@8Q>Q}q=s)|$0|Dm3gy&NzGWF8hF`=m|Nco^2(W zh3WNEYQAtl%9kZ8NM33!9WU*qbDGnUxhnM0uDq%9tVji31T)-%j znV`fEfriD2-Z6Hnur6Oh4k1@yE0`S)x^R>+&>Wvb)lRyl@;B``3}iXJEr4IHnQ);k zdRYcW;I5Zv=4O)%GjplT%Et2A^@aS_Y^ql4oObpfLwhKyFp910q0-TM4eRmBrXWX;XSZHv5QhjFpZ{6CvC=;weX%>_v-`5+|1y;hRBj zgtsA+=lWR0g-2qrCt!<)pn1gdI3!st>hS9hl8 zGGmk33S7=uM41;ehl zYT*GHDGU=KEn`Y$@fb4Z0#m$tlTr*mrYM`>d*+G^J(j(LRGsqFic9B!)$*2)DMkUi zby{~re)}TiK0Docf4}zxmb-1)5Th^~K9}nIkU#|_TxB{~ff@p3ah5R|{j2a6j0IpF zV_l)8+n{RWQ|B{_*cd4W6`&O*8R-CY9Y&_T@Wg-@_^oEL^<2JH9o&xXeSeF+-MUEfK6A$1JeW=(5n1*UUqFU^V9VxcKYBHEfYv@U52uB}0LHkfA zCk!687zt(vPu!sSOR?T=bQ;AXce7s)Dpohf4FfpMSE#zsuNLVWLL6XYtI?zo4U>Jh zD${Z+!WejhumJGpa|+gF&le7e@u&-Ad0U|f)x9*cv{1CyYIFtxMaODeRZu!ywc(Y( z4o%wP>M81m^<tjEHW%UM?%EBA%;SL@oo6ai>M4Se$6BlUsY#EB+)JeYWakPg{*j z{S)nv_!2K7lWL@g4jK)1RV7mL7tx`Ma|g+aOA3JI`}YgG=08)}*V zPGpiMkL+1<;vL>}D+z1#RW7iX#zc4d3Hq7BSQDc4)AYLxZ_#6gxBe~R)R1oae4%re zMJdh}k}24+3e$AzN7(Bj5h^}U}o zZhf3xzmr*iy}ETLQ>deUTT-wJ^>dP(l}Z{iwvl<( z4Zznsw!`ptE83Pa!WqIs zA-N%~$fr|KMUid6pY1Igs4+Il5hkpcFG5U4XHer^&cSFBnjsX>bZ{?S-KJp^r96lyCn`pfy%yQ%K#lcchg5jP z%v7a0Ti_Ko5Lg?&HYp6+V(B~t#gZTlHhs8_DhVO{8szd^J2>##3RFYYT=PbFR2awO zIW6ibLR~qMK*F)h3otjb$>#IHe7;fKxUu!hlWWJHulGN``pUE1+Sd5x7~%S+b4ttv zEd`;5v3d@HbWfSIcL!l0C|rgEN@Efeim+d)yWFoZk3f!5fmO1?p+c6Z=|C_jD3kk4 z4nCvhaR65&VH zA=~~#G>MSflWuZ`_CfQYA%Jk6(ysOM?YAhnOFJ9kC&&5nOuA6rEw+D9-Tm3xjgLxO z@0YHzk)zzW;*cJ6bw$7yTk2PK%k~bn?xLMT|$vc5Z>Y!?z@|W zZaw6difWpp0b7iR+D+>5ZGB5IKMaozudOC@I*%ZBq6enPK6`K+zPjdC!l zr;z7>-iW990^Xu0+}?e5w)-J?ixX|P`{tj5Ts&?={nq&{E;AGWq*uuT&r1rLvREU0 zhmE&TcU2`)5goAv^^;j1(9gpNZAnV(g-(lrARsj?ZDq3!=&NhC*-VpUVE~r!2_>dI z*Qi1%!|B?605e?OOQhXK%LN0KmMfOqnN}yS|B=IM|?P$ zR(Ubj)W^x{9nc%7U{Qy&^Aey_^vK_<)k>Uv73y|!Vfq|*1F7Na``sp-%%c* zxTZp*j8QAh+D6-D{;oL%h;o$xa~NAu+B$kE4a2Wwon{kB_+t!yUulO2c2rPzm`s}JScQcGsQRw zM;=)rKCFe6j%j%AjF%lU#pY_~!=>v#Nj0AZM_=#1^`9!ePd9G7v%KEDOdd4l*=>#H z*ThaT?L1bJfq`wrQT-0Ovuwz3%>s1So#op7H?Wn=8!cy;rfF#btg$X5krp$SCEJF@ zVqIonE%27qa<@arTeHI*2m`k2`-LT>VmM-JO((*bSgRJqN&LyF>f zs{_^tv`VA_B`KMdYfu!BMhYHk>NvH4TpYzVQu+(_j`{eDUA5Y^t?@!0`Upt^S)_OySU7VWKi!0TxOIYo0v`#N;itPT*g=|OE#Gz zn#O4XK)WS+g5-!dAjSB3nkxSnSUO~?!cr@DQ!ex?#X(scl_ZtOW<4%j&sV~^D9#{6 z1x_;!BeC=r-?i!oqL)M(DEo|v0wTBo&n#i9@K{%LiC?`VA=e_rSSF}|n3{bPZ=j?J zhs}5qN0{p2C<-D=>K3sIG?IXnl9i@dUwxMxWEnUx5UpUd486`-zZ3C$?9gfuO zbSh4dH5OE`w_(z;Be~)nbgJapWo=dN*jO868+!y};9<jG_+8TeM)HQxg^f$yC%9 zCX}m^P@@Ugf)9Pw&)rX}n{!?JfQ^RO9D(`?1U3M+#&4N-;J1fz;1cEN{8kC(s00 zLaB(?c zgk?@xN(dXfVMUy?*_fPY+D9KjPXN`$oH-^7sOV?nJ><-dfybBUl-v7eeEq$J#wU%# zuXZ2(v3&hmw*D};u`@BdNTjY!843W?oWeZ9uaIX;_a`E^;;0s6;*;zUY?(=ibL{Z$ zYl+=p!yN2U{Lx?X`jUt>^E6x@r=!6^ zuojJ`zLVN4O(Uv}Lpqz#)p58A4i`pC+$ggQUl;&rq||zgTZLQx1T$rIO86zlfVU(R zu%Yn+uwt;v;g$Yis=_JIt%Nd_2qP!UvKx>Q@_oRTqrrZKmRj{IqYdR21fC$5nVb=x zEBp*%thVL|5rD0;T>iwi@#PV6#s`JZ2DUsm_6u%H?BzMH1GcfW+Jv!yaxN-mzPd*{ zQFRmz!?p)0@V3~Lc!WfN$$_-sZ9xdhUDo=@*7%05Jr+Ww{Iaj(EiXbr)7Cbc6_BRm z+F7!C2IOKq^nK0$f0=OZDf&2ov}NaV;G}4({6zVQ7_|i;lgfG!W@;blv;sGA zS9qzAla&ZN7>^w;PcQgEgcr96p~8>08}}k0h*9dI4^*OmYZKpV8}9G z_$*)-w!0|Gr`S#Ja&RGPg0HjaZa#v8KxprJlp3KrAlvtv%3*T{yTM@f)ixanxA{2| zq8)w%F=Qj>2Go)}CT3S=61n=;cXN%mOTCYRy&n`?kLU6ynf1HH+WzEhW_)&q->8{R zqKEP?#Azi2gi?SlNu<4Ny3|r-ctcGwaJ(JbfSG|=fK&+M{P@TciCityq&0x}CvXb$ z)TY>&2AVCeU|lSxDEIWd9TJCd2sr^B({&iB+Qka`07+T~`bZJp5@Muy1{*0bD5+r# z3Ro`Ki)0aw6nl{o$5`NitoW?#9zNxJjFe1$mzZ9Tz~+S3R+I`8@&kgmkPxERdW}P( za6wuka$QE)`39}Ucc$Rm<|6`ezfo@-$UP!nmtU&UY!pBB&f_Q`cZUr`sCo#zVR* z>6MZ)QeT0ZqgcpqnYoIAV8Oz zx^`Hl3AfQG&>z?Vc*n(t$UvPOlY-SYB2Ghd^K-#EsB4<8-PJcL?7_mi$l4II6>Sz= zi)r&I4~l4e${U)4XfwyhoTT$3K=o49vutTAZfPvB2EBOpRCZ#w8o2QKmL&;S$$CGSk8DSDs?v2Z{cY>q;%M(cA~02-kh zryfeg{=QjMr*@T8sI{j;t;DjHE)lJCd3G@$RNE(o`mOwWKVQ9>&RtZtNUyX7M`_1f zVV%%S60Q(cWYr-Zo3Vmps+%fVSa=xmTXqvTv%kGH9utt-afG_2$AXFkq*ZjDiVdb| zlxR5zaa`5883{K8MgwW_L4Q}@rPE+_kku8?q$43$aIK3Y@=QL+bfU0+?R4$hlT77c zwXwfQVZGemTKh@0_1YArCxo}lFNvHJo|h1@Rpb`;L}+Qz2$B&(zACWQbDKUEp(!OZ*6wlf8VZtNE&tTyRZ!uDI1Yt4* z3Iy&H>sxkM{plk`ds=$0o#6nzj;0=3a+aIhoi}$nBDBglYu#7Unc~47bsJ7Y}O*sEXa|eULGOZ%^MyMtLh`ym_J=C=Ee&{N(n;*c0seVH!M?`Do8sj;@YpfM! zD=hV#3ro8Ic$Hh>NDJ@fMK*)kJ{cT*%9{&Yts61e2}Nz;H#~Gm6wCs)0?$^wgwOqs zqGwqJRF0ArNwvaN16vF0Qe`j$XJ{?->|Fa-Zi96w4-VrTL|~YqV!$y;!IE={`yv)7 z>`jS?fp(#A2t_+cRZ!BIdZ;l%RVN34C0PuqLBg-z#n;9TY;wAJ*|9QzCd=K(eg@2> z;MjP*JKZ`=)sL8Jxp#KcWkPKEio#doc}$VyTqxx}AF-baMB}}p^PLz%^eH9qvOnf3 zJGAN?(OVrXobJBG?K@gzSug|hHG9f9Ege{ZS2-@{uXf&GLEd-8KZJ!^a*uC{xf_sq(k;(2)Ryvko9bUGrSq&40&mua)d2S zOePnWoB8@-4tLMSpite4r;2!gUcN*HKhsDJPrw!cO4w-ftk@lRC{hX!H29KoYlJWr zjQJAV_${|a1|zen>vh4JFv<{;>KwpVQ!)h@s{)U5LV;#FK1=ur%^dgav&4FF@+|Em zm6&6Ky0QFpN)T$SI1JX(afIH)8@TLDceA3-#3H*4P7RaAtHs9kbNC2n;xyRLoF529 zhg}o!pdDoY2IeLvfWwg6M0t8)b8@bnTy7ScZzQr;7gw&N0kPsiwfDhh|KSY1<7bdK zRGv}JKITC=wk%ebh@)XFip`JFogGc7GnmyKA6?*x7#rAHOEO$Lm3o$RFeOd`o;{c? zdIA>Z#w;#M18XX470|L|Y+6iJ&k{`Z`Q~(E+eV6(S3ZugVL-K7lfNUL18m*?30X&- zlc^7fzzZWqtVXU7q*|@`7%#pjuP{<_wGOHUANRq+ix*=GNiAQG;iW2sRr+(4U1gT3 zFr#QB?HjCAx@J zS}Vae6TE4#3A5F1hzyboD8FE#Ws^zx4|Qy;0;F&id4Z0=+gPR;Yz}=u+?B;ChV3pe z)zT3-6WbtJhx~%bB_Vp0 zl%)Sfcx#QVO*+80f}lrcfyyA5LK~pv3KG@Kw5rEqXlY2P$?8F@C_5bMx*bwvCLBtb zG;7B(r1nm7QtU4vYLY(4Nm z6c-3JMOXD0*-X?`5}AS%vNQ^>rn2&~xhTQwUgu$${@`I_uu7pBv9d*TS5Zz}t8&)G zN5}$r!4l;f>+=ke9jJeRlv{!G=N;-~pSi$H`ywYpuecghM{ zU^!$Hv@*glTC4(7;e#ktsZvV}nR(xW7EJK(X*y;FlrCi|*1G{cAxG1YKFcmD-h1o~ zOoNj&*w-0O7n(11x-Sh5Q{`=0AR-1`Oo^A^3@hC#-G@p3l|SMzp5J1rs4x}D0-&pg z+7M&cAMHIyn!6H*%VU;Q{?r>x>sopYS6Yi?zJOVH9$i22DymHM9ri7dl zDA-4k$cyN!7(>gJ?WWU;=pxC|AsUp^GG8AAQORN>tP3SXHEF$dTDXH9TtYEutO?yX zDscM$GWPagZXMT|u0rvv)oeBaf*?Q;0tf;G8$t`}R=2uMnlvTKk}O+xVq11HwpU{3 z^TsR5%u43oxtTk&?#!B>?q7YM=iTR^o0gI_^bvgepirmIsdvA%YwumV{CW70rpEe8 zte4E6mQ>?e_bnQ|mm#~FIDCrO9Dpk;C@o-!0>n;$2POp+=^Ap~6i3n;A#?BE2TfhE%Jk+NBL)+V-o= zXc{dy7>J1>jLnGL>kn0B$7^xen}YU(75g=~RJJ?C5&S7fa45hi8BRl3&cWgJ)#;UI zm;qk}hw>p-2;3Hkz`^opL9!8e+Z8=O8%0u(5hR5J5kMkJ1Q0!Fxg>=exZW8q@gO59 z*l#I`xKSaJf{~j>vReduMi8HXq~NV^%6alxiQcxti1V|(*~xhRs&v$rKTBoZer{*< z%=ABHvX60qU@%Cvj0R}79Ayfq8YEs#thE`X8}9Iv3+*>4b75CVbxXM+SRH4@v=HeZ ztZw+<`IA5|_!G?*hZKi|X%K?GFeII?c+apaS3EdLxEID-4!Ac8?dP32gzSP`{v_s> z-|miF%b*hLIp*0D)!HbciFt@}%XKtWN)npOjM5me&-lp=vacJ@5VGax#7-pkK(QTC zjD$HXW+5@J=_29b{m}+vQR$OV6MVZjJ!ZV_9{!Bsd$~M0S+1B6!Itzm#fYgMC-7U} z!Q%C3dJ3F2i`BE`(*1cC?1)Z56a%c&Y{WpcLzdwXOvsMUI>NL*Iqs9Sp7o3x`8RC9 zM_wR~`BH>aA&`S_leX?WLAYrl1NV^O%obi>o^;ng-J_$I$H%mAz9K#czNJ;1yY>Nn zcuJPM=cCCB& zIB44CPX}YZ%p*@yg*)s5TSIXq`3yU!fzyqr1c9*%!Z`f9J2K@Bhi8!!K_?IAdqw z+2QwZ+`9Yr^;_uP8Sk1=FE-nmEY3hA2qU zxI8`s*az%n9Z7+25rIgGCGmrlq%fg_b^R6gx9~07NFh^5iqk_{*d5YHH|Vj2jigW# zzJ0SoT8QplE!^fIFBP}tNlmHvq?-M6TZ6!M?;BzRvMGbx@@hsPl`dI!i4$W}v)Elx ziLH=I-1fKGHL`wHrdOS4$v?wtvL?v3bXV5%?sujnF#q47*=-rf5Q8mo0#KZR0gE3K zjldO261Nntw5(|8F29U<0qg5)V{s`kK4&Rz@vUKC6@m+4I^T!GE5?kf44@?isH&`M zcwt%>-ooAn-xiUYWCoipsmS5vDF~;qm{%|Iyi9*lfQf2gzVjva1UznN)bK5DL;M(a zwQxr>IDhlmjScA&&(>2cFf;ORz<{LS7+S#iZ5B4N#S(h2p@8x#dy}y*^ORylhzhrYM?mnPS@ZSs+G*!>OwkNTWnX_n^^RyQ_{)KS4c^gJ8+#Ag76!g z*PW?*JrI_|y7k#;YzxP88i}Gyf*lkQg=L`~m=>~Ps3_OfL$Sn$V9UMIkZ@=g!K{Bu zC}+mNG<+M;R!L@)N=<)nBegqs$u2(o;OD)^U%q?z;}2f_=Dk;cfAIZ(efr&B;ZkQc z#5T-T3Uz8f(SEC@hqH_nE^u$WPMMxJ{1fH2)I~MPSVyHJ=I`{W6er_Zm5U$}b6CDD zRZtjAg;u_mNHts-9RUNwrIH)*Y}#)_i7{fJUKSP0xBSp0V_`onS4Hemr>%+_f-cuz z$hs=Ahbj`I7qo zqW~2mQ*{?)ikvpztPsORWcgF#+sD%lTjUfyZuL@ll3gJ#@npN-joad|(oH*Rxw^6y z4&R1~vA8zQGF4o-Hx>r!c_Vg9SJ&|P@(z_{)MdXXL+N^?T$|L=v;F-Ee{Mm44EdpwllU+(i^cP_a zkS$&LSxxR74%p5TQ#Rd4g1B@sbD}=p)j6RE&Th!_MivfI9?_MoA7|$d`j;V|bVLN! zlIm6nO<$15fK+uTtH6@<8s-9RD@0Azn4jh0RLC|Bur`S`QsIaS>%QDuriCn=92zgNZQK4#fNhl_D?|~f zg4TKIz+41oMc1@}$Dv7kLwp2e7iUQYiEwS$*1!v|awA5Ty}@Z7+||vh2kPX+-)XjusWzVue~y4^ zwq;ld-(D!X>a*&-{sg*CdIZq zbb+Y>VQD2r9FB)%4^&c01dtRCa)z-vFH(SK4SuFrm+i45DRU|uj2cNndZMDV!lI;5 zp~=D83b%YqjuDC#-Ytvj9<7J;aYymc=cF zqR_&wb?ohpIrdrY+i|lA%DlOx_ghjcpiiQ-qj9)((-4yVgQ)m`YR2~Fly9b{*3X#&;|4g6q0klVlN@=)Z{fHy(a^=QzXU$C-}!p z5`3LIF&|Ax=}9^xig6@>@SrozOb2Jy@+)Ekz~^dC?^q0422Mt^I7OmD2jx1bkQ352 zl1kJHYth;G01(=Mwpc-qTUUh_Ed-Dfe$zqNuEz;`0XiQij^n-_)rCg4!)Wf%&-@W(n$>FCTy!`F* z$hV*+Eh6aQku7+?o< zYxGqWORm$8mdAw(x$Tb$OF+GZ8?R?y(fqK@bC}f!@*(tP1T2M z(XNXQnntD#s-W6kZJxIt65?{=sF4^0$RA7=Evsf*66-W}4Aoc4Cqf4Gn*<$NYptiW zWyhMHCIyWW+`Ta%d-BeGQj0%6`s&g7?;m{dTQWf{&j0@5`+wGZ_r$F>ueEWuPBHAS z?V!mjT>h}XT7^~>x4oir+mNmOn_uB&!{fP6P8t9vY{2Ri8X;ewj9Lf4p3e@@MS&{^ z#h}~U230l)S%+-F3?ibJAj=f~u(*;aTVDHU3INdypw)46GK zw=z`~A}K87yeuql2x-=PmXM}QwQ#*yx*nevLY0kWU_xB0M@1CCkdP{i8pwEHYH?CY zCxJijZD+T;i(?nK?qQarNfS1SfJo!^y2x)3`gLo__`=qdWaHpYui2Hd;ahCuBnR7{ z6w_YjTP6{ZEk3f=z+0&m-mvlRb;(x8>UB~g@bYzsabP;odT{VH76X#pvQD8#dPelv z&ge#OHduW6KfEM=soSEeF*~vL+JxGqUp+W+&obTX5<=YFg1)L1Z z&!}+3R;DA&!rKa|p&*3IRlX(5(dOA|ig~A6C~k4*vDBh%p~?eIg>uiySaZ?BHL*G= zNybQ=eb4r_mhi*lqs7V@5@r(a(`~C-aC*M1G{ zw&7u8#=L^Lz-TVB;1&s^F3NuKRl%R|EsVXduB)*W;^K-LW0`hk#VnMFS(v+M3Wzlz zq{>U!uU~nKXvNYUT6B)8O}lGYQFJk~+f*0F(J)+KHcT6c4md8>pAx&Qj>}Awg5Rb9 z55)tb%~CVpssrP^i%Fz;aNC9{40m}st&+rf-jaxb3GR)g)5=8AQJ3^ z3^V|&lf-wcNJ;_hG7dQhho7Ah&IA!Ph^4~dkSSZ{j00%=Qxx6f%{iHEx?R$UO&SqM z^y5}iO5Z?IK07jP;O0f+hNFNPK39V-5xt6+?%rH8MaoKlf}F`J9c)MBw_=>)kTa}*%=7vLf19Z z7n?!1E-=Cj_!F{)MYo!5ophkU9?zuf|(e)UpTy zong7(U+k*DFr6oWVZ&;LeJl@H8~Rwxretv>Nsb#(A_b5wqYs-)VpzZjmo0rsm4I|~ zvbI+lN!(_1jAn*ds>rj=$)~u&l2c3YWbKR-C{q{1gkiJ!;qm4KAiX?ndX0{z`=(5b zrkh=zYq(`!vgGz)GX4DQ?6cF;<)ZNvR7vdog$+Jy2GmrzagM`L#dOQI%nZmmdh-qN z_^fGRQ_|$O<5{(kVS*Emqr>CRPR~fDM4Pt{qFr~2M-p=fDScirw_DIr7culGh9jWBHp=C<)tE<ZoLer8N4myvGJ%=#X-t`f8@_gB`tN(y5B2S|t`;-Bp~hUc=h>7G<@uBybn4 z5R}YMlK9d3UHhgw9X}m+|tbf9da-ttF3yra3 zXSGG{X!DFxBOk@R`?K#1Klq#e;a@y?@efbF`wtJ^|I_a1kj;V_+8Tl_WtEp7BM;rB z`r1u+vNOoHjiZx677U;_f`=Dta@Yp#=&M?y+}yly#iux&k{APu-IqqZiAAVjHK3gB78kvAuDQ5ov1L^Sbip zXP1rChwh&9#z79T;XWkKL4sWKiH$Msvhy!nTe8WHiQk!J60?WJyVK*?;V%2V?tZtk z-`U;o>hkRNdz~)xmHlqN-|4Uq8ji*N{qEjgXMc~03}x6UxZB-lUODXXgMFBj&4oE- zZL-C%H16$p_>+T?rL(ukuh`dk7oKNRWA~&WN5mfQfh$RUwvTCYhaaN7kloi1eXUiT zbC9jx36$B7*p!Vd-Y}u~N%RQ0AF&d+SOAQ1Q3n<#P;(&R7&YFTp&7Jv=g*%Vo($&1 zrJVLxpLP$7slcjGi96_1dX{3E4vb8|S4%94dqj$pL^I|yrdpCT&cnCk11|Ct%HV;G ze_`!%$#C`M3R&+nVD(vANNZ_fK5bz|r)#sCou41FbLFe(~I{fORul}F)_x@q^{C6LI z@y{QA{(s+}oU*I9JP=9GXRAN+yRuzycfW0^pjE*13Pt&j`t5MQNhn&g^Q8m*oPopb z;HyA;?sM^UbUpRJQSM%yhfOFlTU7g14LY7wCB|8081l{J4y6-+O#x zYrJjWSl%I;t^E?RrLV%Z8iN`GLSB2!M7FBlWE#KQ-H*){XUEu}bhbL>H^xAq zA`$wEg$>sSOwfp#gqcUs@*+MpV_*u0JvK%+KGr#%GPO8euU`&U9~0KqTfXS8*=s<% z;#N|kRA7eH$i@V-L;y+Q=OqF(jGU-wuvR!X4Jz(OhuqdQYidw72;D<53%y; zijrhUM^YfG?eN4&USQ$8Y-n%T!1GpH@T-Qjvk3*EIky-7@Ytd~@NV26oTobq^UZMi zhxiX3s#t^ez?HOPObO9XSaC^6;bea>-NWYy_iA-f0fuRzP(OR4J@z*0PxiWly)I(} z(dOA1t<&4M z95^7DtD=^mz~FjDFY5CX)o+9jLWYe!bQQ_HodFr&LZoVvK!_em;Few1U+I|zFyc)% zPKqQ}5HOdSA3xt5laI4E11FyiHedDEzjRsI>=_u4pA(D?gs5T5w@@yY1P%M4cZyLn zS_H*3BP3wV(3kjIlS;JFRIN}&S4;|Q!&?{o(5C`N^;Mx|8eIZ(e#u z`FXm7k1TDtObEQ@8s?fe&!2f+d2mJz0>Jt>qX=b5G>a>DSPHsksW>nz$bnTL3YWG6 zy7sP;6eD1RWR@{f9xx*;TmfBpkXZ{1ToIP#f^@jYy(v!H=Y!2phev--u)4;#MCXP@ zU2fJ&ikL4Eh@=!rs`Jnc#DtPGKw&W|40oO+Yzr^RRP1$Dm=;pQA$DWRvw-NLg=8;T zVdy(&wPsN+C=b+yyQxJ?D`8KG+YDqmDOt$4)^?UyQ+5xcIzI3Y>_B=*!?WJ4&scPjC6~0A`LPY+f61NqA%7i4`dLG z!B!xJ@tzTYeZo#4>lZ`=x|n7C=ILqAMYL~^S(UwbL7C(oqUpxM{T1bV*0~;XQ3<{Zx@Sy5c|cTm=ko=bXD%cKxMFCS9KRw#B3NbP zlJ3Ee`-i{i%ukUN)(bQA7urh%3iH%Ze7pT~D=8oriQqasiKG|_tOKsGSCmYZkfOg* z39V8mAvNDI>9v*R`SK{q(rskP6fG)#X%iIilIB?)I9CDspJK7$5Y`PX_F+G$(+hYe@En1qHnWz5E>f={bv} zR1VK;qC{c(h;Jc7K;rOCVi|UaUyzi8183Rk=8tLek0&4e{EJ`zkIl=!AWZC!us1gU#EYyVEZf7Hn{zA5zxMyzTSQ^-rny&& z6qWf|ZQGtyWB60XYUr^F(^}iJKIJwIIJl0Psg%+)c7AV;i8{AY4h|C`pO1Py>R=$|-nQSvEMQT8LY%Z6RX^-}2Nj zHaR23k!Q z)4#$JOf{(6q6=`a>O)Ccl(8PyT^O1uAOc02+*4p4lD^;Q~zXrH_9zN z&Y#7%tSw_-(ItD9IgOGtsiY9H9logtdf)ObgYR~Lrm#^5tVD}Rf$bZBccEy#ax5m< za@jg)BnV-=20VL{BbN49f1+)h7S2o>NrnB@v*aKJ;o$t^akX%M0N;XYj^bNPKxjKL zW5$FViKe4lfxVFE@U5G^@l{K_$@o_U!v17;2M@^GGkY=r@TV_+^bf1EulMi1i zq1C>`WF0N)T0)?VN4_nJNXZM8+pp^91-zynVX5XO`M5je?ps)lTZmGI!j>;}SDKY} zvP6sL%_DDZ*M1vK)$$>z%S2jNEMUVf+K_u)x>EIDw1>uURBMr*Itf)a^v?N}>ov2e z&mA_FfB5v{)%X9$!?S;Sz(&2BU-llIU%R9%mEKaNf-y54Hw z>KhKnmQ~!(BGvF}*_~~af6cli`oX+hPPF8`!F!x zH7aKw%^V68Nw9;tV|2)tt({dS9r#}AT3UVq-_kYAVp!5kU=`PUE3@vvv>e?9+AN!f zIZ(1YISIa8X_%=>VS|gQu+eX0Xz~g@4stFZY_>aDaz%p!$AqM~(SbE73>U+rR{)Hf ztA#9bRGqMeU!q#mLLqd~!k=tgNF*3dqJ@+naf<`|fa6-)Ah_}!m6G#B zg_dr;;1fF=NjTaeFZ#3_yI0Ugkl(8GIMN+WEm2%7UP)SKdDEYgd zk>#ec-}5UbjJ^5ceC6zqdiWOI0Kh9gOGK~HZ_AkWt&+mUgEeh##HW-Q_*SkqTJi+P z+#4-aVWx#j3iac%ag12869Fw`D;ZnJAhJ7{^KLydrZ?N2XJXa9b8y<=a4QQ9=wX^Pq1hI1|3xu?{Ros8N}%Fs!Nd;Jmp$bq*@uUUVL zz6uZTb^2HaAXrXNU-gAywrw=qA!@1&n$QBzDT(5`uM;hLax~jSGQh{u@-86?`AJN; zQCZoGO~!V6L=M&~QAWdpv`qP|VB%tTXJ-$)2Ry@}@zyE-5nFZO|0?nUYyb>&WsoJw zEyj6L9MicZnL%rf-a99k4gqf`!^!b*%AkxL!0YrHpAO~g7n3uRn@MN^jLDOMV#Z}K zxf!qM<~WTG7C8wC2O+a{MsHDA%z6wntv_Wz*KRjl3oB)*J6_q z{(I-vqt&y+XFp$_{$h6gix)rskDK!^=oc}()pDsebirp~ThL|%_j*mrF1X0MTms~_ zC0xAt*TTNQEVWYMTQ}HA>c*AEPykA0n}lJwtwRnev{c+0Vwz?Ea(Q^G=!$T);#_IV zcqIl0n$gNgdvdu9=Xskprfp9>g-!CP#NdufjzpB_^ZGk`!}SlQ-}`^3=l^B#(cg`q ze%if1)mfHT-M)5SR|YSMo%6ht<{egl<<7pT=J6E`LN^VmRRqd%3p+(u)LB*{kn0Zp zlmuF(MUQXn9O;NLf$TH_7@(G<5brIL6VC$<6Lr&w3D-lm=SYgGZzP4E zGoz!zO!1)Qrot4~`NfGxM4(y~nbL-QSyI3`-&PBo3TH>#7MjDqZK1kKWEoR4EiAqb zIP-#|1~i+P`+hIBz^K<=s1u**GTuKgy2WaSQCI(o$>w5EB#^w4&xU^g5I>?(i4Yz& z;fiI;ZPAGSpzovL=m{-E(TQC|E> zq*>{=*CADn35Fcp(40$zm z#jZiu`gn0bdJXzZFYR#J$AL8(k4^AG*nsXciV?X-1od*MnajbEuQ0c=Zi@jrAy`GW zfzTNxPgd*UA>p{>ESgpJ7|t`4XRWt7a7O3kSL7B@D4UTHV1Sxh#b{*RnoldVg+%5s zy|Y4sZ)M};CJh=@QNFc>HcxZh1=;fKJnzZDnsEUiACC;YfL-6YKYIG!`JZgQ_g9Zk{^IP1|8n;FmwWqn-@bNDFvsUx{27ia z+L3jww&<5n>I~SpZi)P>`*Lbwo52y52G2CKn%YkDw+KhkEzrhjSq$l~q{;^KTU0mU zf?-iEl3F%pl#cwQMsvusy;qgA9?Rsj;ZNfe^lnhHjteoYV%BMsnr8U;JQ|;k$W!&L zJC8p2$>cl#GWqZy7e~J)k^8N^{j1m70=#j``>xvY$W~cJDZQz%q}a>e$Q9hoAc+z^ zy(|JChk%4yO{O+Gm|YS94Y?KweGy>`a*WT(LP!ytiB(BTaHz0c#v!vjcu(UMID~tX z%oc=Gj6cb+grtm5FwmU=>=FSY)iIZqKp|_5q)cceI)?r-k~uXpH9aU1*h)&tDQvHK ztt$LCT1X>Hmh)-QS|8nGyz~_|sIJ!=jkk~)y_eT602&0+ahx_YwKOqbNkPgpm>3E>J&1On!P{kYF?ijhwbqe0{Ul1^pdts~61 zFE7SrmJ@>2i8kl6v}L##CmIpH14t5kY$!-99nBW3-C!&rhRvnnEDWEnz#Bk4w3$2bkLL<#DN_%4qbyONy(r$FH#JbkNmChH2-zjTCGDtstN{(A zeNk4c!c3WZt~ALvc2VKB*^CbL{8hMpy5{}7v;Xe;%SWewH#`2T@%)R<-3fPj`|Y=V zhj~-JtGv3D&wHaWR~r@DPRXOCA0b9PwWu65#U=yz&wX4 z02jsP287Qk#sS|dDWfI(_o*SUO#{GYOb-sb{b?g9W?(o;h3n~o(Y#g|B>`a>FHa7p ztRNsLw9iU0#(hKpwI?b^DojZwg%&bjretq49Jo;+GDQmqBw%POq!^My3rYUjR`~5L zB>lcEG#=G8?@saZ$b{}t+g^WG(FhIfT5$5JdCz&(>Hq4u`j%JS96=@s;UAC)ngxr% z76A4eXaP&1+>Ew{hHoXNYnre;TTtgExPOp*w@c2~+Z5^}<5h8;&Rhzgbb*)bl$6hB@D?4W#Yw3(788m>S5g&;0a9bv@~Z$Qe2dqr zXI`~Yf6(m{^d;-=lvSbI=S05E7|MGX_WQ&b@P^?=6=36UJL<7erBrN)0%+hb+TfGB`7(oXh5h-~Wc{&cd5{l+vYEReq#sspy#vh7Bl)WC9 z1kH?N8Sx18DZLM=G8V(P8uPPKnERH+fMUd?4On803pf>C6r-e33YH|1@;58QeoFvD zRS3@y56;gHR^Qsf&S-&;Lys+%>V%+Arm1kBJw)3_X5--SZDs7Qa0N}B_PE#(2AV^Q z$C`n@B4--TZ0!kLWNXOf$qx?B|ExdzM*;Fjx-@;0MDTj;gCSAxK_&2Q6Mt^@K0^DU$;9BpA+rXZc`WylrV%0k1LjZrt! zQD1F|RIQ`TQ>iV2kovc`$m{Y~?NRSAZQeG?L80YdXPOs;$@$wi-nlb){K2RH^5pry zJbM4v!^wB=5a!XmL&-MQ8&3S^i)~)ub&Sek5w+E&yb!DdR&gxnhKfPCSm_Dn zf&ih^5G-mfHd~e3)-?wA@+E2&@Gz>O!n)K~)o-sGXREUe+pMe1RN8kaCfVjltb$CN zwfO`q?5TlAw8&0OQbXMOL`{GbGje1;#R_gRb@1}(@zvBlb{Q5a;6g=Hbvd7cZ(oro zY)oRfsU13|h6OVzi^W_()Hfd3Q9@qH4>lVN7*MDXmNo&7+mXzfD-DNk8y&vY$%W;L zG;~DJnMBuMGmG&_8*pTl2@9NKG$T_7#fW>^R_O9ZsJ?08Iq~FQJbO;+1`f3AH(NM^ zMQP#q?DMqn1r^R*S8WR~KXNLZp!V~~Qi?NBJGvzeo&Jb(Ms=`PB46^Z@s^-)&9hfr z+ut9ro}PZyn|w5!KRf*HpWc1=UL5PC21o0QRv?(A8Zj2~$-UyHZy2LtQ46$`LIXU{ zSl=MrbAg(Agllsmj7!;5hj3wzUa;_LJroZ}ww9c?fd~B7GF)fnuV3Xou)tbewsWX(@=pj<8_lneP$E>XOPY;@%8GKY0-G1&JHc7@aPiTHKl-2Z@BQoa z__y~Ty?E!=y|=G2W;tL<1vxH=H$S%qUeu)r^p25G)RF==y{xG=y$lp#-REnT{|`$9 zP)Hb{DalbHAT1|)ko;hWizS8va@($v6z2Y}=$T`7utFt8hcY-MeL>-nO&5S7Y9}R8 zPT(pDkFhq%4~^vVCOcdQK-%vrkDL`{>uowk9ko5Tr;q~v zagxuBn{6jyou;V9tac3E9Q(HFmq2Of@#HG02u-f^}rhqi7;c#q$o?YMx~w2DVW6XC9Z? zbal4!SkIR%$Z}L=WG7R%d`oT|xK{_+fSg+M`4=Z-{#u_d42IdC5j?;!yTFje;tpmd zr9-lqi=1>vNv&*!OyRZgQxX{Kk^sF_$S0MM7m+wE?p}#Ls+jp0$@h*pG_ero=y^hnX#rgc?`R3@$(^E>4P9!ddriCc#OzSw@ZH=&;)j2rdkRw#1M^x@N z9vO$V{zS${xy6@U(`4B!e9ORH7!z%>?Iq1tzQu5G{l@U&{MqZDvxV9H$@}vUe$=0S zB-mQS*8B_f3c>)g;1od8cWm?B5puG9O~4!YQJyO)W_v7CwAS#Oh;4poP)Z0>dk7R- z529XLn5h98oMhcM<23;-Dz_eZT9bAopzYOfgU8PnpZvG+%l|q)`OD73v#U35Z56H1tZYCR zqz@weoH7To@(8TWFl~rWgn~k}?H1T1o6=ujBCy_&=xA|px;!WmpqM31x2OoDn6U&D zgB}k_xj3B-T_V)#z;QZ+mW?R5j6=W=6bsm>5Ki7FtHj29!E!U!`BEWbKqf~-;6hSx z-u0VIASEf}$w4_mQc47x3Xzn^6!=G`(!yhmeo!vvLGtHRg-%qP7W&Av@O*QEEPuS& zoRD}YMwRA~u}V?&4_Zu}HNAXTzMlf7wzb2)~$Q zGvg3TNwy#TFfapP7I0*56dn;3eKPt_faj7fG7zHK?he?rlq^gmV#BoJvW6GdjYZcT zIy7bXH1MMI#>0iJfR$)mOk@Jr$2%SD493=~$C?I#WYjpzhFAAlWyY#rXEYiUPlU!~1l~v}mq-)L|E9n`19^py%cDIU7yc z{swH6u1gzEhNWA%h$=B1;P z7-w6O-~)6QlAXyOd)AA_7kR83{13{eW2_kwZg`f6w=run^wi`JFIW{Hfn8= zt%~l|YrOw=AHVDj#phYwdj8Z18{Q2)xc3lpwf0oAB2tJ(?0hI8P?8uZ)rY;vCh&jQOPoXCQ!AL&C+t%3uvQC65u_MvZ5O&3m(tXD|Ny z{Pq8wp8a+A;SrH`dErhgI8ndNS^ko5`8k$^E3J&DFe# zFhGJNqmiwSGG>Ygr+AYqizP7z6b3>fty!Dk`FQG*b4u=Zh_OU>ZE=V{OS#~{vZ{BZ za)?pDz)Rf628kWJyog&6tSC4^>CsjMutH?U2SX?!u&-Yh_V!0zRb2KW z8S!ll3wq6nTVQr9{ld&@wu$&6*G&{%Ro^{qu$pQy+lFuPsm%zZg>tWxJ2#zuI?lRkXwGTtQjU}4L6s#^g7U_RpLO@%bwM{hEwL!pHY24&{&O!oP+4vJNQ zEO@CUZ1OE+dv&wfnY*D0C5`)9oTHi&X<+?x_V;_~Jjl`{CEuZtlysQE~YM#1e(Tl_%V!EA~F2A6en5bUD;sSHqlTTn@XU4jfP<^o0t zxg-Z{H^nZ<)@>_e5R-4yDsvM1e>>A!FB#L|D=TkzwrW__eKk?AB`uy4D^a`nMYsl zf6^)H|x*lNNS}fq(35eAfVa70UC=|_=Cl1-^RkXWk!X*;W*JT_!(AeZ*4YjEf%}H?fJn1GnB9T z1itO9Uhhv?_xfzGVYM~O&Dd(01!b(QKG*gRR%3kva`Nrb$4t**Lc5iv2N@`{DDove z2)O|UN&+g%fCOk3zO|UXGc)9H#j&1Ip4#R|piX8^&V;v)j^0`>_u$FJiWQVxr$Qjq zTh+p0)`qiT*$Xx&CCefQ%Vel+TOlB~&bEa#9-{|XLKe2mHc^!U9!)j=mYu42yvQIR zMBHHVu94^NJOznKWi=ZrqEI7k{sB2Sw&B~YmdoF7zkU6k{o#`r;}3pu_~n0{KmY69 zJEK3s{1|Q4pNC-}ix#vfd-5usSo*CjRj}MD*bQO@E!^m!9OV;T+F48v8Pcz!8`Sdc zOp#D)H4aczBh#(}G|)mxunbu^$caSIOCK!Ze+|(`5HgM8A`>p1w#>7_x7}K*UrZ$q@QDGwjp=Ip1 zfDjQtQaC_3lCl+nKadnG1DT^40)$Kz-%{aVmKM%dd#s6TTd3#yTU&U*s*1LSny)qM zap2lOSgzwvV~^J(`dd0LKtW*{EvhL;c6@fh8dTONUCzvLA*dZOK!v+IbK7y99P)#gDBj- zx*YE|_5_xOu|WHCz%$@glYavqW}UCg!H#Qu4>Da%#zCJFu-7wH#tb$?b)=)U{J1tv z2-%gHVQu-A@mEBJegi+F6VY8|LLwOB>K#uukSzzJ_TFUDALwSazyTQ>&brHwS(eCF zn`A{G6(qAQxA!GU0^3H5XY3nd@^TANyE$kfPns5gHL>DdS>9~1IWwxbUZMlsr=lacC!^O+Rv%fp|?7zMD`X2|6j;`HAJ$@%T zn6wkPa-uT8pN{phDrnIn!8l#W8X7#X1ff8K5C|Hna82qA2V$3dYgwYZJGcNwV3VH| zAmtnw8w}un6{yWr2#p<%HStldROsOK&hScac%6izcy-D49OtYdi_~Yz4#O9{i$nYr zbP>jlD*~S=Q8bzQF&9IHHu6xl8D`efr9KlY1U4?X*P(<~so5&OJaJxvDt&8n=1SBj zUR3wNa`NF{_m_Y1X!EE2>Cv^FTmH&->l@}j-+7I6`ALzs1kO#PXjPZ7tUd-bSag8b0C<16EF1#( zROs&2!J$)oBxSr-F5p{gfYL!bl2Um@krZ!@lo6vI5kMPh)Q{-Z0GmH4P)`%v}irZ~();WFJVAyfL<9sR_tdlGc__lwAY%l-`2Fq{{bIP=?N+4w-A<$@^ zED9sQ$=$oW#Eu%>K1pd3#04L^-WCOw0a+6+dv}he_y>oBA&x>m;a+xpU{{6R0p=Pu zS(sUE-wiyejX)H<`Tc~DY41hLEe*N2m$Z%jA^8@DJ@#lMg?Uz@l|IZJV~DWXNi4=d zfX$Ys^QUveP9K1&>7kkumN0p73P=r$>K0JNoMGgQwT7-MVu9rfCguXzG@QXIkAL zOeN(?O6^P^Wik^PdQ)}OX%1Hmz-|cE;aKQ8IqESMr+^C>U63g7G*}UQVn$_uVq78{ zF;Iy?+RmZ!^K8SkkaY*+t3%{VCvW=|A)5Fd0Dnc%SX*XWZUF7hP$6eql_fc8XJWZL<4}5eJa2nB#7i&J*YvWec4l4r-exd4+BrDC zF<;%7pD@+x5iNy@jCe&hqE1O@bFg|jW}{noDi zHtYtgY!z1v$MA*CbFip^>jmSnutcXFu-ZiX10+cfu6;NSrzBPd()Dmq6$hIs_lBdM z+wX9g?<)pgq+^frM8qX&xvB`u!8(SSWyM*inpAdRG-Mi<@LlzsXhB&bgsRTS(qoo{ z(?{iYXGjLE7dMvAc4x1yADmsC&+(Vh9{3jXLTSHonVrtojIe}nu^Qr2^U`GOL)RT` zUe-v*oQe}V$w_x*W=8W2HlolPu+5+R5OPD6rQh)a@Kq*jN1zL?<4-Wgp#qR~!8@aq zz1hp1)yuuv>+7p$R~P628duRMinr4ef^CkcYu4SMu9MY)8IVDY9FRQ86#-=0Mhj(i zhwtXr8vnUs3yo3N4n~DMg?#H^gwwF`mC$~OnLhz7hYA3J95Z$~oMqr{2K3e*P^zpN zSM;trsf#zRT)TelhUvmav-g)rpWc7>1AIVlU%wUaxlVj{;v)_Ll}|LnKM=)MJ;;?k ztxWKwBv!--mwGh0HB>ueiJ}<8Ygwgs*uxHvg<5qP0A_ZYj#jXB5IB>{VjLx+qchi4 zIYce8J1{x(@%E0d>x1A=sxlLZZd~bI`E%Ey1x7`u< zjqgxX3@M(Xse;w&Wz+`wB+j7fWv(v^S;zgFeuU6bEc&hWI+agMQ0CfTW;i`z@y9 zm=`#w21EdDnfrogvXJeLpI3nW4?rn<)Wl-qP$CDkhL)6eAmaTLy$i#ig_0)eLZk4w^l{)Bzlq zd=X!L7X?M`VcH$vKrwK7#XvtrBi+OFs(lsJw^c2;I9$T9>I}vq zuyk(DpU`QCMI|V@myo-{OdcZ#nkopWRrVzXgQm#|_`= z6lyHz1SH_QpAaE1#+O7Q+@BQRf(N>%)XOg>nBni ze>z?l-%f}|yx?1{xZzv0R`_<8{oPhSzOj1o)|xm6A`lp-tZi$Z0CGTj?A8qE3CxUs zf>i;srIOT>_=IpQlQnLw%38N(-SO<`qJ#RG6CUbBuDU6~eVMYOP`2RuEWy6XlklYiy(P zD6wVeC^lBLF8y3ZmqVRA+Ak&u4Zk7YgiP%0UE8^RmppDC|9-gn>xb(z1$z!(cRTg;M=#>hr3HRM5y>ll;q$< z%mW^i&-g=~Y8&Uw#4~Yd>_TDD>N`j6jHEShit`A3Iy3{DvPALepK6SvwNMu)O%2rWxFh#?U10=uK6y;ajdCTsBFv zrA&Ui=^wB$B|J$i>*qI?r&pG%o#~>J$#M)e^`2qiQ{FIRnZp@{(Qn-&SgN6yIrgV7 z!mg{V_j2@c6KpKS&Ev1GHt0cqjPCIQX-Uf*gDsqY5S2&X}EHHMADphG0wG(v}OmBJFyu zD4>~3P57Ed%G<-oA3b>Q^N)V;cke&{$vd~ZH?cFAp;%u)=2>7>?}0|nJ@RtuuG02J zLit`Fs}P4OrA7dTT?mbIb7t6J+5`QvtdWTl!SKDVQ7-BXU3Zpbvt~DVQiW(%kuy{IFX#BumGWNUN~KhYG%pmPg#@8c)m{Xg!^e%2YE z@lGx|WqkiJ5{7|wKJvEt=XmEhSRI5r2D7c1w4I{?-RfmNtCzPO4dCr)0<<)pxiGf3 z`r+R6<(19R&J0MX7#G^BnEGeb49P7X3e0XHL-pIRZj*<+a0sK82&i4OB2e%Ss!w!7 zBqfv=)laC_k|4H(rN#wr0nSTOxZ}>^#g)x5EyPXs%@%gjNCB^ik*)eUZQjbV4W8m0 zRL4;I7&s6CvPQHb05cRt@W{{V|kb7#~=K1X3=tSWR9*10CD|i`LJzY(RstwadqTMMIdhvE4&_sV z!Rlr5R^b^e3bJwdHm}!ZHR0PebE~~Ep)5qbidYUFkbHD(+yGqV+aW6-F;!0poAJ*$ zAW#Ka(0!S2DF)>ROOkEiC#lihfT2)ITn#q-8*-_wD(n@FGxy)}Z4gd!MH17M&P;}9 zl8Un?T{h-m!Ucp_>DKUVd+VyI1gB|X!?(b7Ru4jx@)Y&|Iu!Ck8izt>`f@Uw=`h-c z@k^>IS}Il&u|72wfSg0Udf{*0!j^UC!E*oI?@W(>e)REgI``j&POSun^SsvZTU~iRSS)V0Ofkb?S+4qg*IRt<38Lhb2`Cc;^Q=p22%+??{_s!Y3lb+ zpzgTrUQU^{fqdp}@Fc8ju`s_R370lzTj`f?5tHyD4h2{D&{|z)7tJ%4Ce4#+xm_y3 ziI?%E6+p^lue||3&r7fp10HsE*^ua++jl3MA3WUrS@+QoZrz<--{Bo{WO5Nlm@m9| z)j>_Wx}VZ5W%##?Y*sH{=39E1)wR{TTfVJcmX4xVz(ve(FxOvM954q&Mz(AwGl#xf zS->6U^j`*M;KcIOVTe`CL;Qw5@|JHgSi=mL z`4$W09tdQyl^TK_?}WPI{2fn$C|ZGYEZ~G+%2#6G+f!^<1CfzT3rg0Bu5~W7P6x-;>3FXW=*5f@ zF5xOR%nk{1pkb`V9GGkk+FxU>vS;E;I`YrW}UD;%@LwvT;-I;jVTLUwo1B*ky3kYblBB+3^kig_b# zEcS0ysL1di6{3?gEliYn)51KmEzBUoWD1QP>7W@L-+W}8l!$aV6@G{j01}XE*%dBf z0MKj`mCc}!=7vf;>`gwrfAE73UjKIb^mO;uot-=P0Hje{&BO`|yfmfK3W{T{2dOb$ zWsa6_GkHSB~Z{E6hbLW)LS7^Z-wZ2(ZQHP(n_R0%Kw2h0uzQt zOn%rCISk_i(cs)M!Q1b#Z6q)-kG0_=mpw=o**+c3~Oz?xd~bf~rbS*1Y2 zV{vlLBv=ab$+`xtwVd}MK=eto&v+e*bBBvHyMm$6_8~VETEYs{kVix>z;cw?!$6Av z5v`I=8SqYK9lY>yCCAt+X_uuJ?;EcL#}?5GXt}!HFe6YB)&)PYIY9nCofeNNPl2Wl z-!ioELz7_O`9xcWnPD|rHJX|ABIcSRTjCb{JKvG7142fhm$4;S{PM)1EP346gQMp9V@4d#y%8}qP%*;^j2%8iLFI&R1)El1mT%jeRw!G~ zSbj#JgV@No6sDxNw!-n{3Mom$ArSEPZ&g?=Y{7QX!nVR~3w>nn&Y@lrABtm*V+4tw z-gso};jOQWZs-2Zy}OMc zp?puFCN$3&Ipf^-x*Iw>Rj)%f8>mr0q)|J$o^v#Z=(Md7HQZ?M%=SP7fupF9p&9xu zl{MyBLcbtbHXPARksE~!5gBa@DJgqPw#Bq{(HgwF!WCszZCQ22>>mypw$S!ahI31{ z#iCco9^&=r+fGR1u$LD}Unyjj>SYjHz1;NpU|hY72mowoil0zajt#J_Fa|(QR9UDn zGv7u8STNq=5X1`dB-0B`<<=t>0HbzHm}eER-)x~WiwGbo)jTS3W)?}YLhKgE`;EhF|@^j>27Sxn7KGjCRzYhy_;%Q+Oadk%WxZ-5ivmN$R>h8u|&8j>#n^ z0%A*m6p-e53m!DAhOowNFvgIJndp#A0_be$Dp>Zw(h$01C>~AFkfD8+)}jeu*BY_o z5{^`@iKZ38(!`AzwKLBmVBnZF1=^iv>|b`k!@E(j3772Osu05z-}bRrxHZEDj{|`w zj)2`h`U7|54UnG9x5VrTr`yy(GQzND^FypB+;`ODS(*y5W2hc5L113ss!1w5X61~p zf)=JiT8OO&OfrG8LR+X+WQN}XgA(C%q`^&vps6aZSwD59;1n+fw*b2~T z`G=>BDL*Qg!FlM1Wrig%FWOk>w?pjc^_#b^-+DB7^7-MjpYh9fUGLChNnYIzL zYPscKke5{XP%*KiGR4B68BrYOd}tn;FU zh0Ea_miSW^oIG7HS7ZGnSGR14L!oEqRHD4eoR2UHu z*wj3?LS@PpvZEChPN@(Ppcq*fu&iEcAqk~rwrz#lI-?Y|EmWr1p>@S06J^@8&__lD zd}Mq>?CquD!e?iCLv4@ybOpjfd5rHc|TCV(qvg^)qEPm%v*v)nc!0fzZfrJyn<|* zk8B7>W!};2!_U}tDQ0R%ViBRdoD`R2sb zL$VEH2Q&+G;b+ugW>Qo49W&aBV6c+|#z*}!#IYQ(zn<$XXr9UIl6b*@TUE!|!6}*T z>7yR`!RCX>5{p?=q3K9@-X#h)1jt~;;DSwuuD8NzQ=vr4oC0N@ffx#19FfpNecl#Y zAsk*6g4?ErV0cP$9+iKnjBnimkZ+q7;^$4!1++{W(ea#T$2xE+s73lT#exi?15FjXMtcMVNp47>o05ibr8{i-`)Xh24sEaN+4 zz#Ne!!@g!j<|mBghom^}bctzR&df4I{i#qhb)K3CZJ!-H=vM3X&}vviN`*ACDx58w z7!}?aHJ+|k$~CZQE961Y|E(}}0!7+D0=lV^H~@Cl!onc}>aadqIQttPJbJVMe)mT2 zJy^cJKm7>#9(3;x?m421gh-0jj@>#$A;SGfU(-6QaL|Sm;&FdYdMgLt-gLd5FUamP z>~y$Y;n3$|%Ee9f7WuFsmR^3j*;FrsSOnckmQya6at5BcDY}-5?t+aQ^cm61EwFvt zXn)p*vj#u76SvK)&5?-eBFl<^6$%^I-OxfMMRnqUBvHr|uZC||jigwiN@f%Tz>oA1 z(Ee((VRp*E#Z(`}QX!pQEd=K{YakpRYPMLPE|)ZZ+d}$|qllDuNRQAws(oRF%5q7) zlA_zlRsZ;-d1RkuyyRX-EN6z7LL+^oKJF;s3a~RD_&QulAvU!Co9xo zx*HbdPXIvPq1VU9Y!nJgSt0{ZBDSidm)Hz7{(QCi^yCD2WRk@}F?zo$L^)?{;_ghW z0PSa|r<7dGp(El|tdNpX1J-nnc|TG!8Ju39oV+kQgvaFy)53Tq=&1>-(W-?8mc!d9 z*x;N|o=2{uEZAoU2R!n#Z$5I2y&##iV~iuTkmmWwZ?sSo9KuBl_Xm$Lt>2%W!M9I7 z`2KYAgl_FTTEl7lmM21!CkymGR!8;?oGvG`B`@cTv$G>NJ=sjAOB5jn;!^lgjX2Q5 zmy^lM!^1Dn&&l<4z_uFEmmpqhU`N6wd8Y}hBd~pTK-$UAPENi&JEQyHgy|G1nldyH z%STBa3Ub9U$82@-`STZ4I9lR4-OQ(RT0?uNygOVHfXYFITv;C+{_y-9_M<`qpKRfT z79Ljf_~a+tg5-pti>$DROZ*ob%J9@M56{8|w6qno3ADDFKAw{2bN1c)^Ov2`6XuWj z6@USwIm%voSqCfcvp-*dc5?c1yE-2o3A&ESexx6N7Q{xs zz3Al?vJ6g;6iOljR00@cu+?Y5ujpk=F4fC)3cXAMx-GE9A(CPok)}VDle7>#fWyKA z^>f%l17eNx;-GmVd45n8@;3056=IoDUPubM2aAL!lUGMa@Pi?>-`+yEoS-pB2P+bk zozC@ow2zE_E3lC!s0OfT!jiLI{`{LJmV1 z2Hn6ToWoY%^$zLl;w5;G!?7{}1JEz}EnEr(k!g@uy^-h^5Lyu(S|wfVL2TRD`971= zGx`qZ#Dh6%m=i)|?vE&8LFIAK_T}NIsd$Z1lqGGA1LHa|#vrk{j29eScOnMmCM1l= z0&13rb8DIk-_leLn(D!0j+n&{F%H+@lILAzqC{8%qxY=d0Oxhc!1ZRry1cO(@_2A= zk9V7=<3Pcxm)yMSC^nEJ;~k26HoBRBdl2wgH1=r8i2Dv|~DbN>|d$K*g?CXFH@*=wkFe zI#IxoGz`FH_-16cSbJ_--|=FbXGtS3w~+Ff@u3Q)Z`=r!*3 zS-$jhC?({e&Q?sq2^<2wK+rAUPK#|QT#8?@6LeboFrTQYM7BU^Fc>B)-&J#{Z5GS% zsrL=a9W9FniP~x?G0cgpD|2?VMa{7AEsm-(y<+{2H=(!3va$>=P%ibru6$CSm3@#d zT)}*bMnbmu+Gs=Fs53d_pkXL)G`m`;P!O(w1%~B;jY7+Krz=*~m(M&eUm1rsngZjmTz4RL`i2%vqSLDU)3>qv*185RI?#Q?B7$H3&Jxh|L zotQneAl9Cuf_h8^1Mp@p$tt|wf`Cl68-eh?MfGUQ~!7ip5>rooxu@+lva( zX=$hWb{({tjSjbb+rOxgoGLz1TWmQX_eJv{w2%#$c;w1nZ_;bd_wT*SZVuD;K7IJ~ zlRLwwyZ5KJ4VQX`Ux0T=RF4W2!>FrxvN4l+HHo~cxw%;odC9CRyZ~5w*{&=cZo7}{ z0sl@f2d<{Zbs>PcKIjOr4VmM`c9keHdtkWu7Kb1fC=?pEI3ya4-cJifECE{Jffi!B zxZFa_HPk;?zX9x2IKlsdq(oSRD>d^fwq#2SseCX!V64D-fnrP}@wuDl8SPGcT^KbX z?hcn)2^wHi0EuRq1AymHLLG_dQ)F2@!w;}T*Z@sz38nOxX00r;EgFGci*2@qW7rim z-b}Hj^zL*6!^mJ^r;wOyxHwq%!J7=<@+;`eeDA;yHiiZ%KqK3l)pgZTM>K{xppGrT zTztzAtPx{$(8u&0hgUe(5eK4H#iiHAYxjspX?3!U_C7<=jkb#>!rc$Uw_0mCSM$X7 zMa%;)mLOhCE-*Y%9LAfe;#zEaRF6g`dGrt-*#cVWW1eEp8)in_48~))#2m*OJ+c#I zuEZ^v1i5cftGL3qWPb&#hMFv(eT{h47p&|9ip9)X&%XcLNAJD9J$Tf4#7-z@ z*v1DarMP332Lp`ZlNrZsx)`or@Iw_s9wd9ZsZwITULH+INu;sJ!J=>}sY@tH7tEOTuTQ5dDpVy#JSVd8OYUgNr4+r6%@(m4)8jA;guqHGmI;)30qec#Ul@^5=Sk#+@h1Qi z3}^`QVcbB8o~8RhFKDS=F2vIB)ywo_5R0!W31p@#W)4g9@H?r2G59T#;(FNNun>z( zaVINWGytPQGLo^+c!k31{7MUH&zmj8_~tHwnQ95_s;~zRBPrmpM1Tf31hk7E+X~T{ zZQ)|+fDT+~Kksd@I=4bulptYjL?`-CXyIZrnxoSyq_j|YCzGDy9A+*pi=l0?bnOpH zY~mDne|QSU@U3-{Sp}O(To3pMhcgISNUn>}gwo zet8@Sx$F#F3|(h&S*#G4g{c|(bpiEs!#PKcx3gX%5$2nIp7GWBt-+?*-%uE65MyQA|Kw8)+piJnM+!!a2ZVlUAwx{8 z95xcPyL5nq#{%73F|TC zr5HIYX$Z82mdoQXUh~MW59q9p~|r3hLjzUXhx9;A=o;Oxz!MeO{UNwE?YboR)0&Q$9Z>ZFRf-4=0X|z!o^vm#T z5zDu56p38WYAl%}id+!uekjHqa!?^}8@emJaci1cghumlbb=@@!hv+3X+2ui0vnJx zjOIzECI(`PRfVMlrBu-4sEp7H$&~i(rs)c!wVbb(5YHKG+ zF`8753~abHe2WbheHf*S?n?`;jl-Gplo>IR_Ig^23NUYTBghtVzzJA1!po6ELQR+! zbZO!CodEa~NTEoHi)FZwR|lGBUCsf|X}LOvvY;~lETWTgAyp3DR;0p|5^XSu;yuB8 zETZi7xRpM2yg}8%C0&X zas4-Z3*mEM$K;@qJZA2Tjt#rcc&_5xD8MW$mTwu0c|8nRa+k3U$U0XVzU9nu$3qW3 zP=Rj&6(<~9zD1>v=|;XS{T4fhBBp@|X>jC1%jFgff6PHZF9*DYtZ^|y*DN0>zNI`R z3ca|hffjZQ*HNZ0J`}F-hT$mAa3fJ$E)q4dB5jWEr&*7{lq8cN6bU^1R!dH33cFn? zI472%k6A81r-jHh027Z1@#Pa!2^VQ3Yf?CPKxaUxkv_f;%aycn<{lHIRO02tdtwWN zbL&E}Z=ae+KoVt!tm(i-Oa1U|1Vr-YX&EC14?(~yiGe5d_e|&fT zA$$wfa%iYiZ^!e}IG$)Ktjo4+#kZ{JpF@dL+_#h798J$%2;p1E5YHD^wtS1lkBXwS zN|MN6@okx8xl()^qQ;{{;0qP%Wg8s6gm2M@Q<5eB4d0e|LK{Vn=-!$pn)_n72;ZV< zb8A`%-_joVcH6>w77PduF$*3U)#%|JQgF;a?vB61u9}_4n>#w?wcPSPif^$m;r-$r za)oyY-?CcPm9Uv&lU^WvtB$<|Slcg+uYtY;Ire+Yx1gaATOkuoFKdOMq=wew+izA_ zd`owOz(TBq8J(HJ+@h8t(4n*t#e+LC%G0mKw^-Yluu;B%4V(}S*mc`Nt~lF@MhXto zX0=maauS0#Eo}ML7G^zZ^T=ulu5r68q{X-O$kxe#ppdd}&T|;sl9Br2+eYehB^2Rs zqjF0GX-gx;w7^J4HXktK$je|C-Ge{9l4|M2?E%>8RRabNyF2PA(5eBt zAuBI779_6FSm1N{ey+KX(ZLo16&gcH z=mOsmEWtqw@4WjIwR7 zuO*u|@rv$DSNHBu?mztS;nOd>gZK9DKf3b>lPu-KW||Z zt<^AHCs}m>8#t2($no10WTOyz=uZgWYJ23d+cxY;3Y9{q3VpkA@9jI&bAbV7 zfcgJF%x^uLQc{gE4hWh$JUnN=ti7J~ylnio#M@)MLBO!^wy^Y=`Q;Nw3LWHC&;kM+ zCU%q>DqO+&!P1ALsBgd)do+0b*9oQKRvnwvz$sP1%}2zDp^=u!gM{cNXdzFRrt=!r zx>$GK*|3{gC0|&1nC+PK$c%nji&HX@sF}ubQq#X6~x#5Ai948)wSb0Dd?# z0=I8V2_phegx1W9W!`~@BKmDOwd#ho6 zd2pb*zOkY3VE3Zh;eqRxkQ*|VV1N)yJ};OVS)jnV7A$@)VFp1z-m&tgp}zSfdPS3H#>4V3+`rUZI?g9;92%T~)7Hxd`NKF&FNYQeB5If!pD^4tb$1&! z#zW-L-+K9BG^W8dW{n>gtZ|q-bTbcEt2@jvei#gOhena#b<}BbF6Z!zxmw0yUXOQ} z+ipPm@F2&j=Nw1P%E-K?!102=J#wBXqdJFns4#D;;-X3;z!vZoBKi=K)quAlDh%{r z0F~jV_`?HiHslO=4j1__{=o*b4RzryTrD7K(r)EAJbud?BCuEFHf?JO(}U!lij((? zZYBVGJi>ladgmDG+T4FFCI0$=x5Z|smq2(>&zqrD@LMa6)@Va6ZGyo64c=~r69jMZ z+cfpD76B7TzihdQCnteoE_sfE~dh#x3=^zWnC!%kuh{;bPw%fA{g%-vhv+f=c~g_P2KmKD&Qp z&yjh01Y6o{FxJhJ2%s5k99_N+oCeJjQDFLe4bTlXbz|So;cvHW&2k+vo6>9Mmot^ll(uKW*0Mg0nSOpx+%I-noBD zLQ&SMPrmu#ldr!2^vmzQ`tBe5Umear|GM`T&!9!8Sbg@ijXF`_oExxsksxw2xuv-9 zvY&!*kz%l!mA_-8Y559Q$cnJFWl0-gv3H7d>bUf>>v$DF1yL;@1&_#HQmYE^^)kG5 za#=JrY#zR4p8oAPteIPX6-tq9&OClyFhu&dVUrany5#j*W-VS2S&s6Ca=l};U`}>`l6BiJZDAHs zH*#+A*m{Mrspp`qVyf*W(ZkQV8HW->DZL(QeS8G*W0g>uv@&9{8)%{~fu(WXJh+F& zv6a#l-`l0GM!O~#q;Oe1opX-u(2J1r@k zDNu5}plTsPp)Oy-VNVfOQ)A2pla{D959uk^C5IRL!gU^hy7;g=WZL9{oN<{2rcdZx zV_!i+B=agQ(3O5Z__+I}?(2T}!`DB)|L*$d`H%mLYkvH7PAh1=O!|W|Ac~j}-orc( zLyoZ3_4xYT`0zH(0>`W@+Pn%WU)X>k+MTV1$OUv2*Ev$tKp(g!e7PA8ilHiOE0Eq! z>n)F`0nAV%K*U{=G)fFwz@pIZu*-ll6q6Z5 zoT6jg^uPXo^u<@7e)+A+zyq}b2lJ1={O;nLA5)OO##nDKC1S%{zPf(0zk`#m=GB7) z77Q@?n_a@8CzYwa3Z~&I>EgVm`}DGDTfM9k%VV`IQD_BchP(8#k(pN{t&NAST+?x- zoJZKthx>AM+jPTLmX<$TE!+>PNkOm{L)TB$<0b3*}bP#k+ zd{^VN`D^jmU~eEXb#Yy`iKros!NcOHFjKEJcB-0a63Hdx4g!F9spK-N6&r14yBsyR zc*s&u#(t4U;O)>glDsDOLGCAM7vxIp0taLhS7=9|-k{{W>!};r4V_NBS!pKO&CSMb zbmKrSPakoEhf(S=;Pn(9%|lT;2h&Hq&1n)Z;{L15j-v4~vdAq`MXlh!wN-(q1Qxju z8ecOOp$KlfY!t=Oq%gtznMiUYR|V6V1;%W1SJNq^b50uoy2xsXKr{C1jY zXr9IiC;6f~fX@J@GrN*h&)GEIQ9>~DfWL+X>%I>ubhIH9^oaR+JvzJ=G!;VSOo1!r zQe99gW!f;)1mvo@zx>@#XC+FkFdyF_{z_2nf=KCHHH=k(Kto+jcql$B`DnS|7vCfg zV({JI+gFFz|Hpj)PoGRyyhVV;0s-t~9VC`1J%Wue=dT7EP5oi^{EsCdRDA4^r)@#* zOf?S^7NHfFmE8jugWnL+CiT?CsJKz``-#!=jA-g=E@k02yal;B*&S+};{~Jf-a1p@ zR{ysPUNR5mFi3TLykL>rD|~Wt`;)`1`Xm@WTDY39vlO@kgWvqY$oXV2|9tX?FBaFI z4CjCM<>HfX=!CUK{`8fZZ3$8F6?QF7SlA85JjN?pHo^hY8 zU<2}gm&Zy?hZdk^2@cu>M$j#z_z^=w^DI@-a@9{(c?K>)<{i8ZE~)49AR2%>G{ck^ zBya?}$fT(}Fqy@5^$3Z!nCAlH`fs_qKG*(mQu|ob-6y;~twb}Bt0*pdiQGz#b|}yR zb#o^c`nbIcdPQFacOTXi(1J*s%+mS9#X3wNLjYbJLOHZ6}p@juJ8|?B}NzO ziW~7B;AtfsrE0vWAR(jNdRhPr#_75(4!k@LmIDi-^Z9`FQR_Q5AfC_&Id)|#JxT&k zg(7bd1}&MD*BZ?Sy%e$(uaoz>Om`qEE+`}d$8d#U`*b^5ZY5z2Ls>WIE~HJuc7Gt) zW}rcK_vhn7_O|FlzRhILH&&VoU)t3i?$C(v z2=%++$w{25XbKaDX;^x)v@9_t zAYg_bWU)-PX8J`EyinMHys}rqYo^^e3+Mn4`!HA@*6Xcku~J-je%dfF8D-saxjtUd zMb?`ge5O2jFV7dq^YUhalW1&ffF=bn`B&E?sB*;Hr1ZKyH)%aW+CM?a$+nZjC!-%f z;|TuZ%g?pEpld-70uL-m<_{OP0HxyRtqoN#5v82K#k64%&w`asNv27VSuem+s3N>W z3V;qW9>79|jpQabkiAo*4?Og8%GLTWVk{O#XQXb@!+1C{2Zr8q9amrt8^M8ou??G4 zGe|GHV8$WCVUh7*vP8!{!d^B)Ea#Z6Rj?Zy3l~e|g$>{f$?3 z8&pkk)x_ASvvk%;i3ZtfwKH#YhQio(W$S*D_vF!}5`JJx(VLPoO2BAWRLsKx0Rka86V9c1=UT&viZDG0*ta`dYCvaxJEUzijtL3(0ldg1;a^n~2tHHsoL!5)#wQrCUuo9HJwQcj*+yc#eO9M0U?Zq0$w_D4RVKm&TgCc7t@=* zk3Hb*YQNrq6ia+~n|u({|EupiUwk+I?tlGQDAAg2Y0R+-jxd`V@5PH%jDzqw3_l>|q+AVUK! zkHVZgbQ<)Q_oS5&WAVRog2W$8CZCQMpVBD4+6}+?dvS4J48Q#JYi*v>7E3`Fd1QF& zr#1d4jumZq-(BkET?K?$*f#3q7!NM!%;cs;J&1np5DgndE#sYaW~p0`rUaoPNboF5db{mHT*ek@%1^TnA zR_3T(u!fD(;?J$Gm|Qh%guzTzVp=-Qv@!+!oFmVYap-rGFW{&B_qHlKIn&Zmb4m)B z(_Z+|uB}hX05tVx)14G+vrp+3Q{Z^PBPlv6w73)fHsxh%)|;fJGo&pD4aYOty}BmE z;0Dq_V7aj@>u^qMQfJNyX)k=+9Cty8d)5!B$bnQa z84|8gp$qlq5w4Nj`78ydJetQBtl`S-9uhD{rLn0{Le5gZ#cen&#G1WqRfGkCrN%AE*SlOX?k<;W;!M*Kbsc42g)|y!c`K#{Yxt)10hA|s^lg)Us_luXy zl^PfLaVGxuxrOfZVrHXH13s#q4cyTlCiHTN|7pn#>8J!-q&L_OD{w7Zu294I#tD8} zw37>(EKYNdBX=lcF7e5VXd#Fjw!dk6P$$G4#`1k$K=ES0@iaZ4vVH5q@?g2#E!V2$ zY?oC$A&#Ey;LBO}%k|ga-+lXscVB(~Lb2R$r?VgBeJ$5oGMHIVR^BT=B3(-YQDxK5 zcPbZ|Vo4IK$~MJX;|{wJnXs}4_tJvm3OBpGS|YpE=5D=Fhz5$zxJjKBX(mg{T-k)Z2gyVERw+N*R$&0#w zIn7`IJL%=)c!+y6=g+U@OB$~(XxJDJTH9-+w&16|X)nOR13o`(WKqs(O~o-2tY!FYYHGmMy#2VN6t*a5P&VS`rZ+O z9R9OcK}h+jRJD+el1bVaQDn&nQ?xwY24Y>!T+SqYfY3JUXBCWxiutd#64Y!dHBu1F z*>+}FE9RVSRv;)-(SNPE4j7V!BP7r{*JmSiUDU_5Kv_^`rBc8L&;>!@9Jr=77uYt$ zd*q*ZsY#c4C+<;dTdBJ~q#K+ma_eEiFMdn77#_|C99z6y(}G+INtMdA8*ffd3&ZCw>PbsvNScO&!ho)m7aZW!@`Q;x zcmpr82ibMF>-^2dRItz$?81AsAy~r!oR(fIyp0J~#qKO#{uD!_7T<^0qpnLqa`=kx z`f`!p7y-g46pL&!qVuH&z|RF+Wi%>bLf&gM!JgJr3g!LsS#Oa>a(F{r&( zz3I-LcbD%jX52Bx+Y2)yi9D&BWYT4)^#q+07S>mK;p}{Pda6uZJQu{g`5vCva7Blj zZ>7ksAN5=2l*)(hP-C<^Y_GVj<-=dYpqOlx859yYU`JFfzC;U8Gw3{Wh^SqsKe)Y% z`Au*Ao)jT@ghtd45r&^0+Dq`V>BDVl- z2Q&bkD+G7y>yLkG^}fIzAVn`Ff64apL#)P!qBmk<7o+tpg<-DW*Y~~kyX-0N-gbYc zPK@`j7jv-$?9*)uCDh@+4;ReV-MRiKxeNu@2`qu?khUG}4Mzsi1K07pyaygR%zP)R zR=W+y-+i(C$Dy#RFTR-$WPN;TDmhb+wL(2?DD+h}2jbUX+Su-A4XBBFD_U#Z{gFq+ zcqHW^E#N2gxPA;666q`Q88I`Q3k+*%7V6M6*mQKlYmr;MjB*>a!H|c6?IJPEYp7=+ zJ&f4QzLpW35Z0Ccb;mUh1$$&18Wr7z;I!lej+X5DzZr)aHpN$6#K0s3@IJJA}Xd(UDVW++x5Q109($ySS7Ejzj{-}#Vz*Igt|gC=bDxs>TeJb}`l4k>c@ zACo!%)iO4kfO2g*Gm3MmFxz&d-SAr>{XH4=4>hs^CV>cDRi_15Om!wX2*U1^TZA?o z@hVSpPdgKTJRgZBx{r&0qCm9UR(G6607{xBA85U@4wn%~)19J-i+ovN^RU2B)LDgCznxWvLte%9^D|g~lrycQDKt5N|_604J zm1=Edfflt8a!`B*)#UBsr{<-qgY!!)&^g1WJ3l+Kul@3@JC)&n*hRl}OSHQtQpE%= z0nk@qjAt>((FMK3Z|+GihP*Iwi`1FuXc94!F~px@R2Sa*(?DRYyf$w(cNTf|SBVL{ zbw*uXU)h1|SC#kyKdl+#0;8aEZ(YS*BRJvnxvhK$Uw!|@{O{+Ro6$GB-sJmFzuA5I zZ4wQDwz<4fbWu4GE2R;dYVZ`8tr7tW6bQ97q$9UF6RLAR_(@3?Rb&j;mFXdL`5}{~b`>kX0?C zhq2I5mUT248bx9WG#3SiF4SM#*uK_LYjhM;{Vt(T8|o~RA{f<-5lww`PL*$qnIKhU z&SYNF?G3O@L%ocIAYhp+IZYS4rv7z`SEqSx!-meqopF0*?T5VcOY9H5lHd#41Ght9l5mbw@YO zuVQyFnI&6gXGAO{Gq>=T`S0)uVUJA~DCE>4{BgnC9!Vh>c)Y`G^_bo)qy@j(5(4BF zmPYE#R%p>_qf4ZS&C&06DCwAYjQcWhmq;X7E4D#Y1|+u?6ek@GjUOtEmyD2V4>e{g zB%>5v3rf}$YMXex6$E3a@D$*;rkh-GngMyFU zgHdgsef`5|{)ge$LM6ZZc=Y3^bMDAES&V9wRbnd7Nx(J|_p)Nx?y1}{=Nt3^B?zW# zjC1b`8^z6zuijN{gjZ>|)&0f%1NuF_dJ8$l+>&A7tu!=L+zCV;{I*gR?o$B4q%Qu9 z+|~u}q4)IeXDx|^b{B8@DaDY*3(O+$76s)XKKWwt$rs;#_SNpQ=~eH`?Z>0#C%jAX z{fRNY>Wx;;NgGx>R8!oiH{~*9ZKBV=zL+H#xcKc$w}f5}RXfQ(wmUg}2&Xq~c$mU` zSOJi9N~C}a=XkGqNr;5jV=o(=!>s$v|BObUH%Ko#Ev&WZsB0Q~aeh6F=QeEIRn~or z*YCz55zMo@cs`HY@tO>dD)zLnb(PlF}u#@#43B*Ew;Inyv0F z{P1C>Xpl^nTihw+Cqe8H6Uc+bZ|x%)ycH*p;+mU{-dlh;s>JPTLk11PC=sU16xG2;bGFmV6ssm6t)!F2EU=Kv;j!k?P9iPz2IK$ z2a!F_5*Lxp&a!8E{+l=9w`tPy(3Kp~bYPE=hYDE@(r(X&g}0o#Db!%MAiGE?WtLrf z-LnVum=*~Cr6-t%xP7fP*-*fdHi@~>8Y=Z3J5z#B1a^2^1l4cFDb`jl%~ic`t?`NE zrdxE{oT1^A5n*XVXm5-to!)xK@@n-YtTkV!#t;5D3b75a*mTWu$(Y%*aU75KQEm?| ztx`Xbl@#b8bU0>rTo}%*O*8Wp=7Q-7xXdpzA_%$sa4~yLOhC-^Cb-k2nRoFQXRcX- z2m7~2yzNY$+9I5Tu|h*b45o?vZvbAqQEQfXqj zWPF9*WOlc6$i+kta7uFQt$ymx6Ge~&F~g=1##1;mCwrn26W|PZ0sGX6I96ES-~90L zSKoa+Tz@L(_p8n4LMVrekB8REA1}VyyF+ye+0kICfvt=C6{zUqx;s}^GbDu;<3G!t z=fga&b08$%2$>_rtpC(q!lGBns<8M{7~&Umt4SiO3#Qq<8E#(=H!nQ0YnERu@ngiF z{yJrCU>daP6ELkWP$kx}q|w>M=XlZLlh3~qWc$TTVuA#R2NQ0zq zvOqYX<8D?=1(e z+=3y~xmr6=e|4nF`C`87{`EKu+5ijm!O|?OemaY_uheNd+2f$E|7oUZG3}-kmA|7# zbf$cWrhrvgf|z1QIea&v&PfZctGRwTS^PBgAT2%4<(R8BwoVIc(jaYTd>dnVxWt;m zY`Y2k4zUd5a@kZ22;h`Z=@ZxsZCtTF^m$`_YIHEll+t3b3&6N9Rly8RY*lDsfkWX8 z2U%hU8s2IIyFUOrLTmdlxH=R8TVCwI`}%BfnPA%C((XvW7Jk~w2W4$5LQ3W)4z0GT zjQEhE3hjK2e0tt{@SXV(B}V6R11@_ylOuL{maMcea4?t~2+WcZA|@2hOXRG`7VQ>E zp|Xq%V;k67pnzrJ@V2y+!0!XA*LtafNLWZbgEma#$EI+OSAW%II!GJ(ulOi_s%Q;iTKCBL~a~#MgYFs)IjID|w;(C4B*HfELM~Fh&v$wdP z&#y=3oo@;Hk}DTIKdVwG--6_uS&*ZCG(3NCj~)cIa^+aB;H&O1_vv>@a7w25oXeXz znX4tBT@=>N=0fhUtx)|G9gX>)5#FW`YgaWbQ@%ef6xx@J`4SS^&-Y_?_wbwH^m|dR zpHFw6%Ep@g*!xzKelPa*2)32aHQc|Gtt`(gpyVk`?F!BE8ZIgnp>`Z-)Hk^pA*h}x z^%LgXo51N-q21?btuxh90DVC}NAgx(F&pDxSM^pP?dB2kgy?bq{*;J0CBVa1?_mxgwGHrkvm`A4Mli_=ql7=MU? zthgk9tG)-;b8}OD?l9zVWgs zjT;EIyOSbOR|NmuBsH%-#HIO_Qe)8XhMSdds8)nPZuG#*;BCbZxJW6A*-^#g$QuA( z@`=E;KLyIH{>5+0QZD^AP{#W6l}1FlvHsMbU!N@xAAkS+Q+E1z{l#pzx%uBN|MAcE z7W;Iv`D#)jtRw9f*c34}-2F7%y-Cy-W43z4YXM_2VI7=M?Q@Wruhf}{>wI%Ln(rzd zj9qC|98`C7f|EJaoB(e*$eOn4f_cn^w2@y%v+Wr}kD0%I)eD*(IL>@)_#+AB`m3)& z$~T{mmY+|5`0T6ACtv-cze0om2}#fnP6(K*Gauy7;uTgb{ExigPq9{#k6ib^9||E^ zZnCPb5`JuW&`b=NG9#$Gz8Y>kc)xOh|JaN{P^%SL?Pc8h3X~A9 zp5<87UZBQI3CM?3DB^MN0oxRCjwAQ>FjJz1R_KL$tKU7IU~*-qj5k>(DiR(nTZNC4 zrSiqR2ThS-kE&q6makdl&&fjkp1JG>@F<@L_q4w^MCJyzbq^Sq#mg+aI^yjE*g};C zEWjs_o6kiVL8rW_WLPd%h{}@^N(0$)em#56JUXh@_B)929zxqJePkQ|96u8+Nuc(v z0?*>cQ3kw8m&(d<7O-`QSa8q~Kx_RqTS->xSs)kZJR2^a^%qZ;n`d*% zt>rJ-5ba=(*Yy*bc0Szo28$AGtqan7iH#}4o8vKe;{jJ`3m&bh3Sr3AGOc|)zGkd; z7RxcMfVyO*mB{e0v=!-XeH5q9WOFjyJlS2HK(Nvf@~4UuD++WhUvn|J9_amA+>N3x zS5YmpkAvrN2pKs|t@4SEXn6a0nn!*(Gy9V|+&~Ssc$bc+@rJ~;5j-h#ESbeQE$o-v zdON)QS2u9prQxhkhpeHy^TFn9d^uV1m|Z{HP_$AnqApldPnO~~`yE(=a!V5mFdsL} zH*w;6{%tz9NgW0r9!o!DS^`){!_xNNs|Tsc&IAa8B~P<(*aQi!1vPE#0ScL_{tJpX zKl{bg`Sp{#*Jtaup`fwFzLgQM{fGDe@K68cyZxKb#@}Cj`RymuyO||szUAZ+;@e-b z=u-fp!BoSm5L)b-Zd}2!KFohBrmLYb&r57=35**C`;`C&s~AwFfrQqkHS(B+ilrgs z4u9&dUZ1XSp1gQ{wtX)$_O}au6IafsUoJl#&A{x%=!fAK-weL~@$=b_R%AH{(Kn75 z+pd{c*y~40H0@7;+)&wYylUat=GDtqmOVA8^oOm1m-P|YYD3VJ(5ws+M|bs(&2lom z{AhoDQc1fxEhi*S50muB3ABjucr8>@4~868FXswJtb2UZ#)A+N@=+ULWgO+bsib|# z+Eq9riUcd{Xf3*V+DJef@oqPnVH``pXKGAjhqVzKts}^M{M{qc`fpmkQs$3;3f_`X zenaD^2N{ISuFQ*?dWqi5dOAOZ&4$jkx-p?o3e1>ncng)mO<&;RHsS;G+8Pi1gZ>y%dhkyLzyrkbRLjW{rzbyuNF(H2ppnl zj1Am;Bsdgkvc5w9_--)U(f+^BUj6sQ_DX0vG2wi4bKbRqDU)+OS-m_wf8BZY>u~pB zu=(R~`=Z3ylu)pvgp?`vpoD;n`P=>^`=odTn*%z8S4sGa*DP{wsFVQEDay;*zWzbz>9?B~-|p^b-|a8HI(#;JIb%G=9d@h_2GHU)%f2>IGg|x@ z)Xj(0hWusY^^KTD2bt7qK?5{zB#L)8USA8i8t?^Nz8T-VUn~WN*|bbe_~!+xIA`RS zlO?cyd$xIx1E(lDCs8U%j>Yfw248(X7=QK!d0FV%t54^&)8`4CNR%4!Iq?!u9lg)g z7HU$ZCOziJDro@AQQh80d=@t>uCquiw_xb2l&F=+;e-0(+7KZmp-eWnT3hH8-#s9T zz9F7rx<8rkpX_g+9bR^4H+*~rgDU8zml+`IY?>e$Q||NIi`gq+1te2fp-LaqSB=aR zASy&P4g;Z7Q+c~`8!4O{&ntw0Q!^I~RJL&_>|dy!NIKqU+ItG%Jl7++V4WH8oK_8) zsg>eQUz*5hqzT#pb2YzZ3YaX$Khd}-1k|iT12j|6Fj3NkJe9A09d{ib|ThW=r~`7;4yd`n6*oMiw8?^_?@H>a47A_41alf zxkyeb#EqN;|48(eO6LCbKSvMld-t z4w-$l9j~8nuI{f7xA6zv{bhXp|4i=xZMJ`Dl*%ki%0q8;){U7kJbaiw|G&p~|1rM) zzvlbD9u7S3FU6P{D(iXnvT@lAhUpDp7*3bh^SM1t?awQDU*22jht8N7i%Y7@kY(0==bn=1Nd*o7y0Ee>yun+rQ{;|HSVM zB@BKw4+3TM;jgz}eUqZuz45oh>38m7tO{JK4^~bqxGLGIyk;dbbIXFb)lJiH8!W@y zED9;?z$35Uw+ahnBWYwnjI{hRN^gQ0o)0hIkU_-L>QC2klb}o-!uj<2+2Ovk`MJA( zwO#MGt8IQ)gwmH2wMu%Q4LYBH^~w0#-Zxj>Z{N%q*Yhp!QcCr5FzRJx86wN%r_1=w zc0%G8u0_GhF-(N0LXjJZVG9fFJ>$B^&tqZivej5-9+f8Zc^3DN=*zsSbs7O zkGZSiJz zH~f8YK;)Vg;bVY>2qoPq8dt+xL&%&eH+1cY*Xf^jdcc+oz(n&GJLznV(+T0m}f>6i8QYEYsPWkXVjIG6F1+R-^v1oSJO&ouJc)94ne| zAUE{Y;7OW*ZzZCDjBLxB3ao`oz0t{e7yq>BD+ip~0-^dev^WsuDNMM?;`9e`oKwNW z<+IWJ*<4Mq)N7)c^UJ~8ixAqx8(4b0QVjg}#BRLj>VREPBxt!O7XydZ=yViNxbWIJ zzYw}0I#(qS(Ya@X{mJa|*$m4~qW5`cpr%dA+FT4eDtlA~2Duob(P->v!_pa~%2_(P zQXLW@#z|MoLj(;AN_*tALvdXXh$UM=6ex=jQA-k6T8S<3vKz17KJaW>(TO8lg`*4w^W25+DDcgoEE zGTQ%2Cl${F|2xy&**KMRK!mI#j3q3+z}BnTChRt_T${476hMTd6i$)A){)2yfNr)B zzm%F|>bG28E9CO?%DzFzWvwH-TxfC{?qXJe+)1GZFKX` zFnPQ_B&|=S7m-B(KU*+-4f8*p{qT2RtUk7qBEah#7guJ7lsa0!hdHC`_oK_V)5Blp zFaGV_n_m{M{$+Ca%k1T^clU3%_dm^T1ZLs{^e)94D-l*0o9G3fKtHV=3{?F90p7is z-2HTIExUd-yZ`6&n?HZ_^4-PFe;?ocdG_K@>+9Dy`|J7Pwavu;{>Q7~kN4y6539-7 zgRfEIyYA{mZ^PX9Z=?OcDQGr*{>VriDtL+5l@RQ~vW!Q&~$?n(j)z6*FU!U&oItwLVtRS^y zCz$Yh$cc~B)?zIs+#ASX#GcdT?8=(#klOu0rr`E^dHrg0^I?7aW_I(_=;j^iI71Fk z2%7E1s%^K|+2H-=Y zvHWEzQLzEdPg9^!)LI}#Y=UOQn^uZkW=a*JNzPZBQ_(;er)^GAHA`m;&ty-HLmExw zi!h=x`IEwMKE66z-JPstm26A#y+pPD-$Oc3y0Teeqz)_HdE(&mxehWrm z$Rmt^*^nqO5`R!LgDlC&ILKQ zKLWY%_MCcv-VZDM0K6yB4Boj~?j)hP0e>GzatE?_Hg0xYZKAlV%BH6EM!;t z$^_<78xU4qX?QdTE08Rl)Z_b#ZN7riEgTmt>ql}zctYH}6)Z~jEPiXWSh!mtnc?Ar z7g2SxDT5wNtWq;>Bd<>|W~?4a(i{oOkt+26b!AO2-`_hJ9ykK?;vpfSk3zrLOCU#NkAVT$mi zVJ5s*kw!2JD++H(sRU9&0oqS1m>lls`{(=J_44p?a{p`R?w`+}|JvLBMGEln@Ornu zU0>eqwuigTW`21${KG$e`MvPnD&Vku-rv6MZ~olh{Fnab=fUo+XPjNWSYO`GE}zrT zH|rgC>J8wszzytSH(y00RaFAbUTlXe0YzLzMqGA`jf_)xYYa=%O6i!KjGoozfLNd6 z-jl;A$yA`4|Ekv{39O*o${4DQ#i@r-YbZRlK4QY>33S=o_-1yv-)s)E{k0!NM&%E_o#jO}E9v zuM@|vk-12U8@rRZf#U2iN|VumnIxCfoXSjz3@g;x8(@3HTayCj;>my%Qv{yJEcieEq;-~dwah~E|uOc^df|ob zcx%YRi+Q-9kfQ(4Nk;>ZS1+AX-UDpYeK4 zcp)Glbt&@JQ%MZ#cGS9-U<}JE+p{wh_x_xvu;AaU)AYDO!pt!|q7&Al++G2lHyCf$ zxK2v+II@VNUMYVR1F9Wdd%<2o5lr|Jhezu_4tMXS8yT|kFj})DH9Ql9kc==QmH3uh z!FxVD8*I>VX5+JLHp2(+u?UB*})eX;Rgs_?eWl;S5V)lC(vVJx>fWw-`NW#!R81eWm&k#2?GkU5%Tvq<=tUk^xi@KaH9RuB&nS?__GodnS`l7hBPpYWig}8n>n*CmqLUD{ z<$~6l`e2qPW=j^Mie57yTSGOl^{T)Wtb>pg1Maz~CAQC~qK<@xgf8TDxnAvBeK2Xx z5IBuoi5n5gp_Akk`gR5K?Ke9^T`@Wtoh?+%K&^;~7(tE#TQccEO%I_Iq>Sw>HWxUJ zXAJ?);7Lik=|Y4FGHIV0L-fO7c8eEP919aqY5G@ZBZ0&`iFaq+)zgcK)ZO#*sI}*6 z)C>f=+?{r0Sg(`_dsZoC%Bpp`R@)l~d*N(&=*Utz8=Vd|ryWbJC8km#uHGlJRgOmZ z&{0Xq9ae5y;c7EuQ}izqZdtWBSd`D(pR&u$@>bFcRp0vg?5y+TWY-x`x@@fTAG7;^l^WKwd&TDGikFaIkf1N%7LcqO zGPCXNZk4>tCuiqR&dwTW`>oD!6?jB!vN4(1_+7&1sGtHT0=9`g0Jbp`!2#GCL ziu*yf9=PSCi1{`_``P$!EK(<$YqUS@jx7#GJ202PD9C|~kaz{6soL{xJ1Pd1W_$o)6!{W^&YVo*lIeqk4jVUmSp6M z*qvb$F^8Kq5s9llR+*Z#*)SH*d5Ur1cBV)2bFo`llgM5Zj6~CG5k0M64M?k@^D1ncPQh7k+ML|dYWnofQTB?cyXCt#L7Z#_=R!j@ z12{~)=(n+>Aao~QsU_R4)g zp)Cv#)v!m6*gH#v!r2TZ&!x5U>7tbIxV#~k9*caW=JqU>lHXOci6X7Q z@O-Jdl#!Q}%VHFnCAPrt7N)Fp-SHgc-q;PBfm8V-TE-il1#AW5Rc)~>VTuLaDdJ>= z)QXmtkF~;PImTQGu;C9iBnWzU+rcx5EV1>Dw*N!-ond$sowe4_>$!%~_p+#WZTX#D1&c%eS!B?vn&N~xeb$($;AhAk> zO;67(sdVgNeLe{YpAEt6dDl{MN1U(M-6>2~K5lkB-Mzd$T#pr$}qR}nRso`G6*1Hf+;Sina*;)VOq*D|4nV@U9iq;CEfJ-VKKo7LdZ0gSr z?7i1vA^e z-z?XsqZzzCRi?*)q40<#dAV zg}0f8(U-0u#UFawiXd6Fvc19cZDuEMJh zcpCz_NqR+8*2`BQH(q`Qu_&WL)KJ`{>;-ipFl&N&tlpZG-lp8f3Q*HvI6moI7~8XT zwwp}!SDXbqfg(q|E%O9Ehj4PXj#1pd_P2jc^{T$_o;^K1)l<(-EsuQ!W3^bPj#))M z0NWa|W#DiECac%VB2si^?n_^?o__QZQmjeLFCw8_*W~ga@wNst(Ku5;9mVl;hs0Yq zX7HOV3g6X$Kf-Jx93COJ^f#`z7nge{i|)vTDo$(am6Ih{>Zk~})q1sgzS}8KmZ?{U zyw~_#fM?bCX(x9li#C@H;Kx~S${R3vT_pvG4cqECRljaF8+`Z(BLyb0og2R`-X7{c znyHiNWR~?KE&(O-XTvD3Y%bhVUEcv^Z^z%o=Dk3%gHxoWe|k_th>4eTebjDy_~->xLJghs^eDCVIv z+^VP87k<{$bd*eTik;35Mz?!wkQmA20dl=*hlgz%wZ9sKG*1nMM&`;O{p39hRK*M zH2|`M4+Qq!SG+OCEN}))IDBEX5!fsyqFi0MV#cN^gMfqa6vJNLUiR;FekU%pzub2Q zp|7ET7mU*+j*)6lJ3}TO-R7f@J_1$V$3cnB!rmd-;XpUwKm=m`L}pJPnN}D2A`*n? zmq2cR8z@$ve8v-(xj&RPo_dA}UpG&MvNyct1rsw5X`?fsRc>_w5mQT^nCNNcW;41$Bwg5FG*mx?9!MiZ>k^TJ$(4dvU)Yk;&+Lco>#PfbJN0b9m`=86I0Vc7y09n}s{_hv8F zi``%*mGxDv1wYFO1CJ-Y#YX`1$rH_`{^?4&(`7Pt1x}>XYaDuWloTph(NddWu*#=! zSKQy09v4B4IcgGDiR@h{Yr7XxN5C;`5GwWGI-^T+aTPOBN>pvqfx%N2U#5n+X=3sh zi<-!Pg&kr+HGS|a^D(qGf_6f@N|?>GB2d?C5_veWu$je9$R~(Okz06sk!=lGcBXS? zG{=(xR16xvW+@Y`5!L*0hAG0OUr@ZoZDX%IgIV?(OdNT{1fL37VyR;I?CH(HE* z#P*>Gy|DD~pg9_=*H&3Oim|sR_22gF?Tz;?sAck7=md(J@Hx6Psvn}8HY_JvNot$?3)xTJdPoLooT0x9=V%t zC42>JL8~LJ6qjFe;!J;`K_R-z*O<|YF>XXmg?v)ltp#*rvOtsp3(Zymy(CYmVP*C) z(|7=rUePRKj`(b^#+DSOyBjXNNlb4UP{P=F02il&b+_0oztwR6m)`o9{zd_Wglr`M zxMeN`%u|(gu)0zVjhY?MM)*Z;JM-pGgY6%2U=?)$k)O8dxeNt(GMAhSllT^`#R5MG!7QeP(cTI9R!+3A0giPoFn zj6`i2IgB_WgDKzR9TuRwI1@-;*{nm`^x&>?@l*@rR6_go1A?l6 zMD|>8&P+&&b!2(>>|&giRE5>m&bpI+aX~9lo=)|))IY!7UQX6GBlesfptc_vP3L{C z@C}m|sYPo^7Bpln1N4sLkc<#NR|GETgrkB@_mIKh6H_%QUFF*qYSkY_VJHnAbQ49X z_ZBke zLBbH)Z0wReeIT4b(1?D4S)uYt;m>IS;j&(j=@Kanh&3%Pmju0pXi_}L%hq?2opuoW zR9GQsp>k;hBMGexkt_Zd2ny_^u9wh9KYElm{}z`*bjy|pUqH`S8o(w-w?5arh^_#D zhKE2I#`=l8vJIg&iI|c=sYn2Vk}~9r9utX9_pBfn>Yif1f-o5u;yvJMlwOMkPL;LB zf1`3(9h$134M!_bAMpw_0b7O-PCI!)_@ct8_+&>EuKaXdmX#w{PeMekEbZAFzXjS3 z&z}E=z9!73c0lGsPtuuYbO@_+Kw5C>s7!~2l450Y8VNws)&P1F@~6##AuB^(qJ3DB z{*ZJ?bz|PEzl0Ju)|UYw&NJgA!@$Fa(3Z+JP)-@+PenD%R0o24%v>5gtGevrWru~{l9`= zQx!PJg5V+Ln(Qrv{Au&i=EdCBY;u;dqd@CXOn|qg24r4`0wG!)E{m2S7?G2dk<9BP zJJ_92Xy}WF{IZQL(TSq=vI+_}R9llC{6+H8_w>TAFq4M^S z)_T+5{$+Ca|3X^ycyf6!_EqEfiGeMBBgO*E>=&seMUh!gOn~bVzbx4S2@*zDck9cWgDZ1`BL8OVHAx}lwiM=o?YUh9ZpW*e zRH5JQCkLd_KFII7D**}rrMG^mR_DQfG}{~YJMoqdOiA!Y+=vw|?VMb;dw8pPvr^Qr z4;QwH%zv2xEP~1H2k{lv+6iyAv{fk>H|eLZCVT3K$Wokn3hT@xjX7CeiL-@oTEJ-p z4YssGk!n$*xL3QoaVn1yMs5?hl2rXF5HS&vdM64u*jOuRlWhZr6)Keh911E zf>X@dWg$sQ3c$LfXh1uqDm&A+m^?vLmOiAaEg;oQ$dcg-FgfLD=C(tn^Cr9mSv8WC z`YBK?<*-})cECf%YK6Bng+Oi!mj%XU`-bbvO{fidaZbNzPgn5|jw8;i`sgv?ZOT7x zDYtcGF-@#^%0l9t3Te`xk5Lwun_RHStxA%K0juT4nUFTZg$JyhWvh~=a|lHsBLHpU z1-!Kg8WI}T`8krmuyxP5z1qk)QbRg4(Yf%@%;LB824b+p>qylL^nm6Wiel=?ev0@I zfDPI=wwxW2m^}#&%;KJ4#a#jzs+N%p<`Df=4&{V5Wb=1cYGqPms#YIfu)&T(j-@uT zdaktvjYL*YP>owkbdV8?N+pPT7s%~o<&EtxRmXGnr>ylx(jL(_U|vX$Jf9%CDz*vN zm(Mk4?cBgR08-Gf?Nn(dgHTxucLxBdMu&fCpi(kavUer0kbV}IOjy=K(q5I0gWe1f|%B>Vfhpj>+h{riA#56zVM=E z2a|;H2!RXx^+kwHktmNwn+U(3DRRVst@)xH4d4nUXEw#@407{2y(C{aYF2@5o-cDv z|C*S=VMpEvVA~bQv-4D3%uJ7Fn6z|~K384BY;MR1VGHmuF2dxXna)up0M6(!B>Mt%AJH=S zYzOl=w&X*#$cm!4y%SLibfmNMatQ5r>v zE<+$y8uZcc@m6+)oH$fAv>(xp4in{}gQh<0?^8>L-4%~`%kqVIN4%{Ke?!j2AVqtz zUP0U_Wp=~?s$t#ks_-^F%Xa1t7{(sa+VGb0;2d{_80gUSR8=W?z}rg!OZIu>$*@)? zsaz;m1ft&vt*&Pl$$TliU638heWNgVR(3y{-^~~Z!7y?>vLf3`CKkiLg`Bbe`kT{> zQJ5{MmbtE#FN`)j42mab3U9}EKP~P)gc3)wSw~9cb?Qt}pwa4XGP|iTtyEP~yyB!Y zfVvHG&DXMS)~DU&lm7B)e=fkp9WJilg0+UXVY60;<}6DpnK^jGTb}n|$iR;0*48Sz zTX@UuqURE{KV3;$z) zw9u@gPhURbt!;}od_g-m25+zGu={!OTkA*?$>j!KGyfm))&g}Gl_z?6jvw& z`q1)0cB6*34$^n2C^rf53fN{gc~dw*l1=Sj26Dq&b6lt`Wy8HWC(_4+pxy9xF`L_a zGY%a;Q4{%yw~gP1krokc)Gl}{n;3U`2(<-bLCEC2Mt7ykqIa_J$nTy}YbVwB!LEmp z%z0pVYE*EFbq5V^F_u%29zBxaGzA!G7p^JKD{gVGT}!MZkz+{3dD0*70agYOcK*P2 zoTb*v&zSNxx-k{T>{wxi4RpJ=$_}eX4&FjtBh7z_ zB;mTD^ii;Xcf>bZJFp)EIk?h%3*Ls!+6i-c$P%E};;*cOf{}W;&x7ibd8diMOg(U> zbi7Me!z_qXvDO$0flK`>0r?rC`VJs_1aD-;I>FKYdlZ^#2>EM{0$ZfE*^<+Ze)0PLB|TfZ+@cY{&L%C?gu8IgdH#vx+QsWiO$Y5xA-uYdmcH}|i{*B>g6ERM6q_U7)@yXQas*V~`|$BTEr z&Q(#H-KM0;{B3uwiq5Ot0M5|qY59(T9yQ4~KWRoyg)qJb56uAlJ@gZY)bul1fvZKx@l@fIJ*+ z&$qkl{Z0JHqy0&DPTx4Wn08lg<`>x2;`F);5yc+iHHjnfX$8Jy?R#T1$=tw#S*$=1XQ%!0_?Ic)l>1 zQf@;&&ASBXF6_##u)32gywl7zm&0dLw>EK!FA4HRwqKxIIIvg1lENTWT2ORw7+0jo z7^-L+0MQyH-o|rOOfMULH38vwXcGt$4cfrUYjoX$)>!c(2N>O|xJc=;LZxH@1mmGd zk(^VCI+l`3Ul42uX_fe^(&7on;w+O&24>+cL=|QXW}$%LU0_SRt$(3WyE* z+-eB}mS{%1aB(iP=(pykBY-dJrmEtIwxiZsE+cxQyCJ>Ed@8FaBNeRWzg65Ofz8pe zO)hs;`OA?A@<}-;y@9}OVbXf-D8WbH88aye>}cdx^g^Yf;m-(a7A$L=*Ra;`URcq} zIV#m|i_%=7DMgL+x=x>s89nn@(%iahFa&j5@NITH$+&_!#*C*k9|N#@GmCrqCXQ|h zJD%^cmriGPCLjUW_Gq@DqaauEiaC#cVyhK-G&2E(!Mji_tYoNj6V`F9tH3T|5A6XB20fU8}%+rx@Clfxmfv z))Sx4#lTo|4}jFKY(^XE=yMyF*WTqXXrvyKk^l92%#kQ6WkF8C-g zPoG}Mq`rJHEM9%F;C)L$8!=sDySiA9;)9ESusm_phUb(3aSZ470~JNDO_UrV>ngXLT!S%jn`M#`|HikYw5rZHicl3sh_$l>AIVD z*uJMDvARO`ElMpQ_I`>2RX@HmR+Fq6m^HRB)oVSK0w(hm#NZK&CePv9*8K<<{1mD7 zsb!2e<5qfF-aG^<7`l)-+5$OO<%dNyaDbZ~m{VQ@0`NJr5}(QYkbx3Iq7@YB4H{?u!puzG z%=$XHzE%7-{&Ypc!RfKGVgp{d4G_F?s_K!3Eik0HhYD?yt>%-ue)wJ#$bubQSMC&~ z1xM{n??ofPx7=s+fdpbXAg~=Cg(ZaVnK2?<5XW2+-W9}% zvBQYSImtb2KbgtAz7M^%#Q9n5wqEbY?Al`J|M=LYl4WXG8(#= zWr(CKMr*U&-I|XOCi7ZIB)sh{JN(o;xb#PpdJz(sAoltpTM8!BmKh>;OALd4KS}KC z4*5AT6Zs}=!2ohC3RBgkvQ;_+h}R7Dk`+Ze6}33Lx=`@n>Y%$X#8j`4y10-~be3Q_ zv;3&yA0m5$Ayey)T;OD_n&}`b{3Vg8UaI-D&^0>5y7cQ;vIZ`KFiJ(v$^(dqc<;IKs`d(sIH%f2(3*M`ED zTly+Yi>xiaak$1Y?6Y8fN$DOJ@zitx_YA}=YH4J~EPE$!_yIj^cO&xQesTAHd40cx zV|tvCNP6vD09&&U8OC4>nIpCXb2}1)*}PAyUJG$i0UiKK&*vt)K=!mo;t5S05WTjO zV|MpY-HTmT!cmsgj1vJ}VcHqJCZj4Gb`3)t%+RVc1L14zrT%TABQ`f;Xpt^>D|D7+ znvK_^0rP!CJ#YY9kZW_C$Px&Qg0Gsq>g}x zEheAn-}IeU!cT(ySb>3LY@2#la{>ZiKj~UvZ}qrNBv(2It#vfi&Cn$#$2#aaKdZ2t z_lYQ)snUg0v8m?Z`DCBaf(S3`(^D1Ll0G1Ghr>$%B$-a6qA~1=x zKM7nvABh?BdVbD^T@H6Y&F=nVc6h_((P&KS+8M^~D%Jn4L3H38(Uq+!1Gm5YsJHA6 z5z&JQ8@1Ecgi0vPJvfq#tloeEWKwb6v+mLJ-tCSq1kFk%R<()D7!OV>x=40N-W&u# z-UR#&_;XG3DOq>TVO@|Lx(@wj%lifSk<~*!C8ELvnsD;w_;+UTc69wtCCa|Jkp0bb zK<_T6o84a2otiC$mIe1v-0l6d9uX!9s!DAkb^Y0XeEr_faR~B}&1My`5Jgnsg|~9A zvTqk|FS{YKtwnqj@8m}x8K1=Gs1Q|aH??KP_MOj9Xq@pzK{cD8UBxfI3YI4Om=j7L zrDsP^r1wU#k&e+l8LS0qytulV+q`m}-Pz(v)al_K8Yh8LHd24FUN5fS%oHn`+`-y?hOCwe&Q zUY<=RC%NZ#DY!0qxXDUWwLtW*B!$2%l#aZh_YJvZG{9;zx1f*wE3nq*8H6dFH&Wig zX0<8%u#r`f?I(a<>Lnt&A+8y&YE~$?H?^BU0HhZ#MC459k@`rkAoi>|#o`eQfs|bZ zTP$`0s$-Hbh-m?bFq~`_;J}&`qG|KgEY6vOq@q)61$_x0GHn5A5|MH>R(aB6gTTs? zOa4+W5;ekU3mMoc>H{l~b?!9yfS~d*C5d=Jtp&ejw1(p~$OTz~Fx?~wg)^bAOsalp zZSS~m<0^^!1XXngAehC)nSPqHvI^Bgv|^#*nZZMW^ruykhB$CmeldVqVnU+p6MqXZ zBPNg(a)94cNiXNPFaKF=I!dV^vFrqa-!_+-ko%FuI{rI{bBggsWZ*I>FmSuesGGOZKN?9@z&QNKYca9vjgLGN{ zC;heK*>DGM`Qy%6C9C}q=QN~w@e%`o+%j5K6qG3tQ89%dZNDzJ2=E^B*Jc$AmSBk- zz7@KaB82mDpAF$QmJ4iA9p*s6rq|fcS8qvbS%X9-EI$arwM7Mp2ue&2G5@zOL2A*< z)K7@FLMDqUzEnHAiu0poPlRk)E~AZ*_*CZUsRe(CS^$B`;Wd1Vh69uBaY@8j?!_21 zycKX8`j@=U1L7#g#xhjomd{-ud0D{oHl`Qi!;j-`Z? zCbF|hRmdD&$_0kE#NOqrzs|Yv>@v2xv+hV}6e)3ym?~&VJF?!(Q^=FPvTPBy$% zli~V&nihz%N5;=BWnnz+7+*Vy8!d46AtvD#dSlc?<9wp2*N8MFJa8RHDsIgD@kW!{ z^K`jaxNN#pu=iRxnM#RS0ohq`cvWUuqz=j)D;%l`gX47va`#L+=Y+T>Y#>#?{5qxx zLc?qe=o;R-e$X#rkaX8h_H6{4A`mb=9H!-wbq8=ZX}$?a;4Cv+Im-~;R0$ImmcXzC z-=CjbQJi_v3&j;A#_DwC#9YngF!;I)a{C4rG`>iN+G#>R!nCp!M2M|M$dldDpk!B2 znyQS+gEQCSakHQt`K{>OsV0)7>_ObN)2%X{LJ)5Y&q9Rjc$y@1+lEpkRl{2(GkIazyCF#K;_Bq$-bPDelM-ZWw@zD8a3}d`Y||Wn`@v*uYE>lknt8 z?6Pp?(v52abR`#>Zon9K1Be{31=_uhTEqn5&|r)-nhzm*D8-C$DnwzCeBRVG4V@cZ ze^`9@_m|IKtuH0c*n;_fefR$E`Rm!6|2BE?M~g+8H%6;j@S>9}iC1!M2><+r9ZF3i|^s*T-T&wDD)~_lifxn}wK%}%$;1~90M^X9FFMhpw z@$UZlo6X(ZfpWwKb~f5bwYrLRJoLx=#yu?hv@Zibp-rWdWo-A8zwaO^WWQj9LIhFp zmPMu(*>iVD(?)S|jf{L%cVj#c5w11`j-_?5;=p($xR$VH0s^!+S4zA!q0GTxV~KcX z0Z2CK)H;BNd80sLCS9Vxa#}oJLNB(<>B5vpGQFDe?B6EIGA%PHtnw`Dh=I0Ro+-14 zNxG(*3@9A1_70GHE*A9w?M0UcHb zro09Zg~$SUq^pB0okgVuv+S~pJ-~&;jQIozAW>nq@b&cUh_{`fv@xDxUWIPVcR&sP zV0hbbCqDw?)&^)A0;f%T?zM1{9ZB#eWl?oipZSSXpaTQ%&F2G z62U^kYI2;0dWtumDxMa+jZz2dIsNfNr=?P;0%eG9G_j$?g#F8`p`DI1@v*=8hYC>& z_%wU{tIGtUQzYaYTW~BB3^A1}OsfG83$Rtg?PC7K1{_@20$gZP0K3 zI(RF3Dw2quqsa&ye-glPts5*f!2t6e<=q7v-l`PY)AdQ$U1EB*zeDg=*2evI^n zDy8Z`-{e5!p2)&TjR@hsHdMO9sJY(yTiFVK?Jj>#A^;%53Q`N}iChvP^utTl$b+|y z-&z_P-o|zwsdi|UnaXli?N+4=$mz0C0F>*jy{H1VNzYeVRKc<5(%4PjblmRshnH`! z-u&9OKBr2Jw)Ypy7cwTWAsUFowta1rj)Vk{gaLQpt=E{hySrh?d?oy5qou;zXgD?{ zxt)(^z%CVE*D}z#5>hHh%x%M4YBr*a+axpv5wZ%1Uy8YLGmsgfoEiS)|Rih=06E3q8e9(N{r8Qy}Fiz+IRd^c_STH?=(;fIN z?8R903jjgh3UvWa@OCtebYKiRv+y=R7rR?FCEgd*4c=;17lF5A0Vxc?BvD>8inH^u zSv^IF2;TO~8qFt7Rd7xCY5MmO*Hpyy)&)}8CP!*1q+FQA$fgzgQu1>cwRK-f*c@1H zGSn>G=D0N!^gAG?ArwOUxQJL9u+1>iu=nH&QT&ytNJYeW30s(43ZS`d47Qw-K9?WG zvcU0_^YTRoEHu?nZmhJOi0U%X$-K`u8}%sC_0ba)&(XJ0Xv6<$A*<}PZsIFAkiyY} zp)k;h3@yjdLQKI!=1Yb4YLG~3Cv#oet3m<%IA@`nGRXWj$p?W*hNXu(=?tGVB0MyLApY{jVTt8XS(WqK_Q&e0!lacN6Noyirxn=E#`_G6PV zk!F{&_Nok+Ds8+Ese}-%yEo%9JL|2VqC;|PXY(G%6MI>rSw!{tZGo*TqM66xO*qW%RZ_niZ2OEki9!d)vRcw%nFPNcxIWM9v2pe}^2uV~ ze!3aUIMVp$og@g0Q3TA22fIl69u@SJFf+316KR;I=aAeYh}guKjYmweUxmveq@0~n z(VvL1CWENIhk~*_-5!ZR)WkEio1M$sq{@>eK1NwqYF~%9)FJLj)rl#gTv}y}T<_=E zZ-{3T(u#xS+)S0TNE|b+ZAH~$oT56)QW?_e;>23e5G<_7ZF_|V8P#N1{)qB1brU<9 zi2bOtR4D`?f11YkSH>F1&3~I`JOjHKFME?T$ZU(C5l#{&+@^qM*V?%tVYX(9vhzuv zH~XqIU%b!d8DWo`Q*oxmp|)5q>}E9-paT8X`onD7BxV1idC(&!?RdRg+7M-<-OOd@ z&=ZP4)vT|%TntJxGQn&O0|y6Ise%z=0@@X*i47Q$zg$J?%Bo*1WrlJ@9(({LIk|q< z5mh$Ol&luqk2V6qkXRUtI42;%vK~B)y$^Qem8dK2Qci|`;53AmhK%J#u!Xnn^K7Yu z-zu6E$UX0oaM|<>F$-u;>yDLLAV>IC)>GHdhC71Fh!3(M0$hc+Oi}gBVQ(VS+<%ZN zL1K6p`W+<9;q&OXEuTWg8`gQ2NJkpP(KM5KrM0G^T!GTk@1N+7go-V?F?Lp%oBvh= zt|$dbkswW5YqE64Pp4?J+TbBTG5xyNf0r%XFD8d?t3OXi7>ts>|7dQ#_nr6O|4uwRlo`hy5_+I;=m#tK&w zJCFQ-ecb_TBT2R;U}KDpDU6X3!bS)Qp(K%z5E2qHHdRznO?A^vzhUO_W*25*_y7Nj z{mu=^-Ea5xtI1JIaw?U|j5u-P+;eZx97;n7h9?`2Eh@Ykn6rfO-&#Wf(?)$Ga{6g7 z8B1Tj(_)QcvTB|eUmh3V_#15EW!Gkctda7XofubG>=vn4qf2seD;P+fHnvvm66)Ua z|Eaof9K1zdP*6d-_usSFW$LrZ|4mM=d5Tkt$P-&s+)62v8^u*P;2Sfr6BFvXA5M9Q zuWJ(kGQPVYTAF49)+Xz>6+?Bz{DZ7O!LODwnFbcZaJGmW&d{(bUMI_5o1fg0cc_2D z87U-UWMO$V)0`UXNAa2Cfeqw;>@m&qYX56mh&LIagn(6MzqG{qb`r)osPl&7m^x zYas#5^m?|&!Wp1Z7*aB$;8$QoR8Iavh==|QE?R)B7@&^>tHPy_F=pBaf=0NUmYh0W z(W%Ox;Je5#1#~HYk+04-COa$=L7`&M5&=M%v0QASxow}k8I2m_y&ep1qt=ED2Unem zgTy)J2s5ndmN%yIBRFy;L43%$6b9c2Z~f}}fqBlH=H!uZnRB45U4f_~G44hlX}`;5 zZxRX_!Pey5dW=l%o%6s1pGTu>PG)mMvH~5(&#xlGT%e`)nDK2?fQ*>Xk|ye=)N?)% z>+F;lmsP3EBpN{GK@sq!teL!YvRAxmdZc+oKv2x7@D|dN7f4lJw#^QiHOh&6^>_j3bp36qb>btK5}z`xd8|EbjaMx>KPy3mdfw9k8O8+MyERB_AnN zzIMP&>k42qE6lt*bq~z`aJJAP{!jd>>MKqaX<;EyQzc7ts4zCcq;!X|+Wy=Hg||M7 zl`2^*zGI2NV7Rc_Q2i@Wv*}~7>Mr!x&<#5xtr&_^jM{* zKVTDT*^p1Q1xMId3<)UNmP-Mce|icxUTj|3U+D%uMYC;^LKXm}qgIJUf@&6tiPeu& zL4}8nS>$q;oI9l&RqDZfu+Z`H)olCj^hzm3ZmFF?EupvA3DO0~GPE%5pB;`i0?DDG zkeqYy)x1x!UQm;E3KnIt31@;sR*A@2RUVT@#h#rttq7;r56=PH2Lw__qXRnS{bF_C z&p`eiP<9NWTWauPr#!OE+|gX9GfM59+B>2jtSKr?T1ls`g@k@r2KjORg=xVgg|EQi z3t&TT4a#cT18tE_H5)C9Ec@8nSlk7i68uG`u^~J?G}HAAd`elGDM(>(e~r$LfSAT6 zmHAI=V9iM@;@nF<@|QE-PUqLF)!i(@;L2FD{$KKFhO5tHJ!->Xnsri=+m)pjvev52 z6N&+LaW>o{w~e)mV(@GIe?3LPLp?>$s{WGV|AFPmeKUBA$LN6h6NnCHcr6c-tia^R zz*`D!NL2M@9W^uD*qQKKdD>VU%J0)$ZO3egD;yaD?G#~#n+JKh; zY0=vA<4DObJTQf4AI9VBi3K3C98Q2M6NC(cUh+&PT{N{#CKTP4e(RCIQZO42SmIp# z2~~Qrz_x5)DZoh7eYhD6u84>6MGOMS4R2LWc(S0RDJuI`CaQOjZZye4zQc^#>9C=r znQ^p&Hf9Gse*!roZ)U42W5lVk!y{%(e1@og7h@Te^=97BR+31Kp80jM5>kO!z2Imy zS6z2CncTbDiaK+bQDZ8p)0itz3!r%KYxNlerQmF2^XTel<8I^y=ccRb9XK-qzm2&X z3D^-b%N<8_t1YFrSmAAi+_aVi&NA|j7vA|8?h|F>fdR-=uYhxMXY@NF5{Vl3NXSgm z)){YOC$QV|bb8hIceDNz2vtt4(v5MO#HZ#`)Z+rOPFdv2vD9^Wsh>^iBjpKj2oqOP zQ?p$FNGPyGI~4>b>ypkNW+wAUVX;R^Rim6?mM~reYkdmp#^aPtX$2VyT(VnJUAbVg z5^}bdauz!qkMEAJPgc}|LS0HI;8zWA5yGlrOWyohT>=)Y@jv&NFC0Say_qyOmn)=H@zsZg56 zjuQ#e7BQBazy}h2o+XUEY-|*mpBl@p;ctQ3TX}8hy_5tHSW(B+TpZcoer<__35X&@CyboPt2AIutXDDiO&OWYB@z@CbRa$QH zG6u6#(PPuAqsp#X1XAv8X}>B6LE5xr6EwCl5%b1f69~(Sz&X{B>Ue9xNH|-;NEF&X z&?YN?LF2{}@mRP7uiz3Vl`e2Ko!-2NdQXg4Fb$<_czZwEN(-vVvaW3|@4{l#CUh@| z4)awe`@nW^t~o;=$ckmQ#Lz^svPjv@!^4#=kjp%lzY6{P2s6yxU>c;2g;J3vh0Wu6 zbHFIZz!{P!REN*F2wCmRM4;A3i-=8LaFTw$K_S1iE{JP_nSbEzh3*=GvJ@I9j`vu! zJ(t3SPRR(kxd65{BhEd1~c*bw+4YLMz+6 z%W}77{UH*n1e~G@DmL!3lf~V7`?!0%?iFPAW&Lkl=x`$P6`(KC4pJ}K3Kf%x4 zPta!4ShpS%}??3(e>pv!^znTAjn!fSe!duOis!CeD7U7-IVE@i% zJKlX)f4~=Yvn&u#@NtHIi;!9Bz#M;A94!PpsH>DN)7lSbsIE>JRAqH#2+JZznX23n zo#rdW&{Ur@*|6cv0Nmyxpv~PhL~~@sT>ZE!|8PhywN5-lnzMNUiGKI5m)-wy4HLy9 zm2bW%*h_~QizHTlfv*k&udwEeMUEEIH$IYiqqHX;htGiPYQ4rU(J_)ZfMq<$Jc!>W z;pc234vC0WuDTFyt~7__WOF@VUR66BEVovC(>|0pGo)QEu6M}Xd+Q|xOdsh7*2bDI9;=+V*Fvg5ba*GT{r%jlw!3a_Z zVTe*51HoXlC@%DdX(b&*PoUJ^y)3Rk?#uXErxUv>LqdRSjMEBP?m}tC_6CPO|X}JxMqcg-VJ28^dB4QPj^i;|% zmg{Kvb4*}(t~qSkR*kJ-78;j3H{eN50eu-V1pdO!S-etMEb!Z8mMUCE-p(&AdBMdI zKJ(cqC#+2i%MH)2=5t%DvlTmQ?gcOP;=y!38mo?rtr3*k;3#+O$RCd1QqE&C$xTUM zZrs~5wz>!1HddCoHNJ&=G!^o!!56?rVKC*%ET*KVXVzS;7Oq-x(j3wYF%EgbfS1qq z^?J3wn_5M82|R(SV&)bPxOE*BxlQz{i+5)BdcSzTSz6qAb+uaET6R)(kqVo}C{LV@ zHFy6!Ke7Fz7Fmk7lc}mBvx&Yzc=I^41YM~aX#dg?Il1C9oY_Q;>2);ZTS2<#wLt2F z@U1J4g3ghFruwFQG%i%yd1svMj~1R=4FPYetSd&Brp}q)zyGR7 z6FI30)-4jQf=}Ht60ymek;R|@7;P941cqJIgE`aJ<~x#h1Gg-D)USr$|33Zx&q4R| zQ0-!!RIpF#Zg~=1cnK7v%`d~X9EYDqDJ=PIwE2Pm`{51PD@?|^e6R>+zLzX8TchY> zDao%G_-C~ghJCCW{9s~;l4oy}ihY{j2kiihaAk;C<_3J!cei(1#4SyJFczZvI?uw6{}^r*bKo3%^NqRDVAd-1^om#sGB_HQ zCP)4>G!lmB=_<4whw_whyg0@u2F)nmEGx5GQ6eof7E>j1G)1$gYBpoZI0Vu%()6F^ zuebgBj?u2)MAz~o*z;V0@+-*nHlG^J_G9*j)WLht=*eMK#b=U*heS_0a2j-tm?rxn zT&qFWpL$9RmXRHz{U#Afd&tt>(}mS+b%B96`#2d==S~`7fhxlE%S9vqi+?zF2)LRV ztJJemqF}8rx9%)%>$C$Sq*}a%=abb|HT4iAp{-iGw$NB9>;O(;LkewW+6$4OX!EHe zcupR_6}h;b@b+M~3utqV*{Wb*o~X2zY+FV!KD30qg)gUgRI+%8sDZ>tsjwHtwVFhleB0nT)oDb{g12Bdf0kH?;xaO*f>*}d7{LOzm5&ztlfuZRs6(|EM8{$Yi0B=D zOQ;<%;|Z{(!g&=XQ^D9!5>89iui6LzHd=HmDOSVT2j0fpR^B&%MR5%~II1gV*PZQ)L>7VFd%Ywq&+3ENT-{beI%f1;M01ktJ%*83L}dWXE3UX z42)_N*R2Gb_Do2t)FhvvOcvcuAxB}!EJd10lSbx4=%~n!lp=tcT0g5{IY#DYLq#%~}a0 z(kHdeIg6e;NNa)MyR@9u-OK!TYc1D<5rOUvQaA^m6>e44WcyWom_GT`eO6Fqm{n|G z1$w5K>gQ0z1uX4H@dWCiA~oy5pc|mLa#Mz*)mm=CcU}vjB_~j@56D*rj*?i7GK_g0 z9Jc7WMG*XrC>Z|j;iXnjaJTY;Q@4U7$8h&n#p;REb8L#gv+M#ga?x)@t%vkx#SNo7M5t>~KFn-7ff{{8bg1q^H4KQ;L~v;{KR0M5@p@pt3NB z78DLyt(aGPH26c;m#mc&(Lhf(G`F6j2eqD}xPid5m(tts=7+oa{(f=-wz_lBmDRRt z{c#jvzi~ux5@F*8(Dc(x8R8iWIp10>(av##WvT5j*uXNRt<9zIj+eaRS{fK^sZziq z>kcI5Ma#_-e{FN>3K=;8nx{ZNWuU-zva-%y16v3N*?=sh1-U+(rzV@~*D0o_P69C@ zcnc2`MhADeFpA4|TX;*jA0>mV@Yb8fZ$oA=TQi>ca>1`zn+%9DFu+^wBN=A_TPmMk znIa4sDN>Cg{sekO z_fc_6oQV}-*xNo$UNag7PUF}0r2$*?_;Q`iAi_~2R_x4x+TxE5axeL47CxRO6FhOr z6cdXA&$yo1&5M^c8m0z9?rcqYv;%$Tm|uGR%?&7myaXtRdJ-QsZ7 ztNyVwnq$TB;iqm}O5LJb?9VDOj&?sk_TO%n`x}#5Gro*O$;t^kP3*W585UU=RU?1u zetDcpq>>htk)3)#^st+gBpOuLj;kS?K=x!M14zxTNB*u!>d%-^b1M-;7Bg8wBF@zl zP0g6qt6bFxl!=#7U6ST7XOz9Sv2VHH8L6osZ)mpeiDD(AA(FCgD0cr@RW&3;eXZf@ z-xaF?6hsDq78?K{1y(}#BJxRgP|)>jRXIDtL(O|+x$T9**9B0^cNCYgtU^xv#%~#M z!I$Hh_1n#t2Fjr2Y)v$H?0&v|Ik>8z)eP%lrsAc%U8tT#CD2-KTcHPM{=EJVXE<8_ zlQQGu5kg}Li(+hx%U62cN3f4SAqHR6b5wU1T=FVhEHtAT`_K-IwmW>}Szf27T^)58vqtXy6j@}@LlO566@EKoL+Jo$j zq;A36p=Fd6bFk>7))gnr!7K`IN$s8a_nVa#s}Ox>@HiSlmzGjWXG9md86y+1gi+zF zl`#KlFxkm*2%=VWOd}+wWip5{R0>1;6aHx&X+6bXT6t=HN-&x;@eVXCev)x{)%Ev8 z?_#!kA6Rx}V6{FQ8q64D9vW4ULYR6=-n9ABAY1i%4c@G_DF(%C>DZb1w!a2!OOS-3 z5F?;bE`>bG9#lR20eI#U~{JXLo*n@@Gd7tVN?d345fP7V6$h z6taTAkfh*A^C!T@G5Z0*HgYR*fN#8I?8@qmMk|eXfXK!k=4I%ZH%Vj-Y@h8MX`xai zqUAnL=wks}t_-IaQI}C6Cm(;plO$XP??9poEpdpcchkJMf&Ii2nd&nHz}up}P&z-M zjWvFJ<^_efu5B(|Oe}BcJ(1_mO)2dK*xGXGN(uK^rEf~BNnv4;O?NF$usVn^P0&>< z3SODDOLI|PM(wg_$SJ1@S`EJLxcy_qjY%x_KYt3eR*bCni8Z$xMl6dak3}X$cD~;( z_95Z&(}n$u24f5gdf@+!ZYAAhxOnQn->whW3$g=0*u;RI$AmV3ZJ8vK^23mj;6mCt zNg>0!!XvD$N=(BRAwQ^_iuY!lYzY<1&iM*%jEc5hc`9G)s}hWAsixOC?fx=K)SX+U%x(g5HE#v7{eH7;hR`I;Hr9zL~Ijq zzWvx0Tw!~{TY~CS=_=3bf7~v%e627mVi)s&m8{etvB#JJ?(a=7Cd+uzMoZ^YO9L0= z0$w(T#-d>h}Oa4ZdWheZAvnxg2buoQfhz@ zkzt6UA{TEbx-?q;e!V^2thkg_Us;>*x?(&DBAd?#3kQGIVsn~S#RLn_%a`@P#)rRI zmLi6_PMP$iaR~zvKr+Zypi_#jQzF$;3m>dE(VTmPg^~DdtaNUZsFR5gNh+(S#XuW! zdj{Lo2ipj+29Q;#K3H-E<_};CyG^|3Vt&Q zO|(TXM&><$B%@HR28#LKq8@it>hN}pY>8)Jho@mUNHEC+bS z*C@9JeL?onPTE4@EwF7DKdWv9V66=?jIaQBDKL2{{+JM0?6{Pl54^RTzg_?tCI^9= z{-E9FZc0xW^CwJh6DDi;9FLjy7HO*&OapPKQbjuVrR!?vUH67$7o^uwmN3R$^w0 zk)^a(@OGIvIQ^mc?E~T=o@GIH6gQcIqMa{1R1I&z(Ffk@IE~KLnzE| zU~5yUl^MYDf+-gu(UK3p@&(|nS;=m-SrM-LBUtkhn{!AXm%tJcVFqR!-inl=xD9VJ z(O!P#gIyr%JD!Ij9_t65@m6aeJmd2&HT#N6;LDYeePt`F@uK?iLVfQ5Y@MN&@Cv|R z_TK<3g|xmJ>W0%cyrnjb#qTz<7;5GE@kV&|`f+r_#*QhBBA9;L?b!Ia5gOjsh@+t5 zJ4>w~qj@&f2Fy0RZ85b(niwf%zUh^qbJt$DWQBu3VPWl;&3{mZ)oZ_|oQmnKJP=r_v3FA_FY z+%m<_*YA-BpG-wlEmv+rq6r!FZSoD54MicUi$z!fp=LU*x)nmCq(^>0?^pZS`dnO>uTf*I9p$VX+MSrC(NH5=#-T(7x1KAQoqRT06(|0 z2%7(=90U%Wg+9Yeo9>WF2kAqO#)Fk>>L7!`W84jdpy$*Rd)89(kqoj#8jhy1hi{lA`Vl$0H2EU^dG+Sqv09YBLNBS;MrG9;LlGJyv5`TA#PO{dylT1h$q(=QN7|yAaAW zxfWf}4fIF+p#sDb1Y(Aat&6o1_@v;~(?IYteLY>kUl9rI(^(+BuB?8YC{q$t9ZV^z z^r=Q&Xn^>SF*v=?p(zS|ZWtoz%ICl*$y98jg4k^&p+fUlltu@0gV z4*0HmWl}Aqk|mMfW3VWDrq+Ya@1-QP=b2)&0bFn?yHQ^=tb(ozLZz0ApP8_i3~~4= znwlOCZ9;O&VVDsUgz~!IdHN0(71JuG`t6oijwIw_FkNp$zxi2V= zW1)lv+HYW%W!DKfxUUE$a+X2JEclDzqPWf(_s*%7NMdR!LAZX6vy3L3UlhASX(_Sn zVz3ETdg3nRuQG@gxjD1nSRD*8z}A44E9Q0V4kL^j2>V_aFhd?0hq7U2Ay`>bHsIA@ zT(VZ)!9F&3IX#|#o z@9NL1@&VMc<{gn=7jwF&7#9 z>$~W6<-BE`RTR#7CMgCf0x4lK3grng$e4^}=v6v^FEU$E7B6dB#h#6^E8me|H)O6r z_Np7RZOs*yq53jTB>j!~mLA1$k^ra(fr{*h+1LN!AmU1Po^mEAmK#Unw;zZ z_S^LID_My|AZY?o6y!6nhpf5I6dNdItsm=`X&SY(aq2%Cs;0)2&JNle8bQm&K(?#H z?w|rByIra$k$se$jqyW0B@=cv()kB0w({v*XwFY=+nrJlLT{vIs&Bji)21Y3G_U7w z8TlO}HNF|MCz{Ik?d|mSZM&0JqGkZnqBAD>bP$nHnu9oCx&zw}=4cM6F-KVIwQ!qx zmVT-)_?r%b+yd3s1!4q^M3A21k6N$4b0g_iT2x@LDs;i&04yfpKSC<%S6AV$u<=k0 z;rDc8W1MaXVD06Ld|_f?h)_Dd=zMxR;*^h2z$(Sb`?k1At-ov_GyD{c1PsB5P*;J8 zus*Et+z$ayaUF#I0SNWz`)Ne3md2Iy*ofe0;LSeNl7EEco| zY#}C{HvHBN;cuFVKysWD(x-|MgEU>{g014C&n(REQ)1G6`CZc0{FNijvFYvuRm zOkQHJP}e2xA#@BCaii5W2f3UjGTp-D-_b1Hy4X`O8r0{jRjRD|oT~S@ zI5OIn>t9YMHEcB%)4TR7{``oa;GgP)1p;4g;ADEB~pGQCph{ zSiS!(%f=aHkkV>YvDzl?wq9)CkB9f=>Fd}1esU1Xlq$ZC{3u)_FSu5RKmW93`E@6-9j2U zugcHnd)$Ytww5p%4J4_i5*qz*5E@vEX#p=~$q0}-LRfu8=&U#39qRFE4^_b-y3EaNEYDJ+);`B}veig9wK zg-5F~Q)RW}_`ytP%}M3AyH`L`Pt9s6nz7?Yj_^n#Fy)+Yz7C(}x+1nSn4YF{ z%V#Gv#sIG*0-a6&WrPIjdOZ-3!vB2uNr}IkDp&abbm23Asm^NL?{?O^iNu-!`T-?g zZ4Z=+#Z-|ZWGAsR$YZvf$^QD+7^t4k%e4KMhlRSX&)4Hg$q|Ux626+rmMH3gNu)~P zDIjJ8fHlFNO-R10lUXpx;<($bwnSj$rC|jsFy!poB{|o}^LNaWQsE3!_%RNR(r&ASFvX(OxDIS~V@c-GzF&Mh$OL@XE*HOy9m8PrF4=S#@Wf^LV*`+ivw5Bk5nB z%*~B)`M5o7W;2QbItsqhJe&+NzuIl*bKgREx#RcaPyTNXr3zgwbRIsSBc>p&Ihg-V znZ6o@Kwmct1u++TI@Fc)q4%{epu-1{GY3oriUUD)KHUWILsDlkW`@!uDVPIw0`7&6 zWx(xCD^js#Fwh8eMhv*^8P=o}3Aa_{BC&bs$N*0Vbd|%e36f?U>3vBq3+g_Hx+oM9 z2KYGe)u?P>Splw^O(*OXF_u`AMi_*ocK~pEW_p{+xq{odal@b-&DJR)?L-847(N_U zNp18m)x3-1o{6hn5zAU_B|<=C+rnE^mj2UxxquYXdY{sO(vltQ2c!Ia9|6S;Z=)~- zZ`EF?vNlu*zf+w!32%gGFlg40^oIn^A}kX|Qpd)s5J~!WV-h$Zs7lWbZ#N&0K{t3? zo9B*WpRM5UBy_joZ5yFHcS;VOz?>E^8iCw>C)OXv+wj)M+k$AmxAgXCMBTiX)}+WgGjS3_+GOucxxZ; z&=72zlb1SWH{H$N{w}r^1fXA5Ih09vtWb`Kzq04aS%bHjMv{5KqvQ^LPA>7sED7h#IBP#UM#@vAUR;8@wfCWVRmey=DY@Uh&`l{b{_`HlW8}9@bz#$dUwm2@936 z3v%hoeoV6pAcWxYvZWMNGQuoR)9*M22)voGo2oAlsxnHWMh+DypeK*FukooSW_QNh zwr4w(Yk0=nGb;KCvD!AgbwCspwF?yQzNvzXwEcGw7nHxbeR_5pqn;p~I%AIJHc?%C zZ>9iQ9VSx)i~{(O7c}WG>RN&m9{7_z4_&udEB>%R{s#&f9i(-zV{I&@M}EiH`BgC6 zzr0Vm(AO+*{I^QhsFFaTs^(O9i}aerJwBH9a+9-m$N%c4`x{!t%dIe4rfI=jZ^8wWI)~nXdEPA94#{#dSf?zIqS9n>MGfaG6yS?%aCdbh*_dM)>2Xk zzN&uZWpw018}r}Vpbd0&1f9i=z`DKjV)YCEEYNa_vB5Ft%ztA+#+8xJuj@0gcWEZjdWdK@f0*+;@;GG|Y0)xF6#5 zemHHc3xHRf=A<%43xtsuIB?>{4V)%k7HG}+C>+X03v%h4g}2Bm z2Z~Eo2cs^baYLdt#j3azh=zZ8$lIq!Y1bM{-#XWl2@zmsaF8y0$h9MF@* z%PsQ8M|P8MVzdgi6BomPWIM)5*rccPfKF$CsPSyej{uv=_Dyc17LCwmW9DZROdI~g zaEr%k*!51)iE8c87}&P<@6q#W|G{T1)^_PBCV$n2FMTRVTY)f-n2)KvUI42ZDq_m5 z4jV3%{&@Bt6oxc~Fgp+&&V9K6R%h4i{{#g=28e+nHx88sWsSaVjp^q(QC| z_b2f6@w+M`!=mla=G1<;_uEF+W>348)#!-e3`{BZZ zY>G(^3f_9IU+6eh@=m=+U#dMXC~}e))C7aNqi%0ynMtqWf$_)OHsut;HiNEKA6}$p z4u3-7Ep`oIbYTdY*iE;#B$n-EwH;d@bFEU=(Xxi&b*csOAoUxocgD=TrA0~UHXVJ~aloHOs`yb_^9gkF-`_Cpx47g0BYNHbi0 z0hMSoSav{rRwCQRVI9ydbHEoM=2TN$H@?uEcK_y0gbk$>9JGjr)5h@@%dM3qRTW^D zYClA=1vz&!KWDk|bH;0HI>f~5A{5l0(c6_V7XXjmhq#`23_rxNmBHMoM`RF`{}{~o zy-2&8!t`Zai${X5PszKweQph6&m1EEi;ZDLYOu~)*34OryN$WLwT#1u86*^7cZ0f< zW@DDD<**Azu9s|8VY_^tNeYcRH3w+ItGqv7qINE(0%b0sAt{rrl)s32kU3Y%(MWGk z-g>gM%-4#$W`4Om>MvSmbpdhSEH8)^`%?p0`SPCYYr2dLfk8Y(OcH0)r}VXYqA!P! zA!#YBddAyy(kfTwOhQ8AG7A4x#4ln+>&sPYCcVB&h!Y2b3L*}x8w@|ma6p|xc z-ZPIWMXqiGxwLJ$P!-bU$xV%&KPmm2g z&Te=#9>=50oZz|kqYLOJO|aF-HTz^xmJb0V^%YQ8R}xbuY3fQyh*=t3O~nSn<67#$ zYeQGvR+7RLOu+$*nI>KnK|?PFH9ENIyDm@ea1M}%<{3c1n$j6xd9DBjbJtwTZ4U~p zMv?kF_P);FK%|}$^4tzRZ3szOPpBCkqfeLqt(I zn*5O9kFPet_tndsVb=e3z;RGFJ2=C(r?o2D86vAME@qu!eww2x!|MXJ1Lh1Yj-Z>@A_wf$BFHt&O%$!8sb*!V0WAT;*sk4V#xHV*N~&Zkij5LJQkWa`% z?ov(t?3s!&D(YvF2(A%hodm^=G0b06z<-C&kg62g6Nyo^6{k{K3TW$hf-mNwz`PKq zW|w9GQXVQa$zcTn3|k+Q-y{nIVblmA9EYCS6YrYrQrC;BVEWu-1Sk|Bg6c%P`5II5 zC!v2vg30RD^XwTv?FKjpesii@rmqq!6pP4$J}g*XHW`8bV9!{aEGWiSN`(*|%StZ4 zPz;(ffQp!%{?&*8PH5Z=>jIK*{&gEF1&53 zLS%%DcQxe)>2AujbEj;m?0EkZYf}jSuqt92q#@Pq2B`=wSXR$Lldv)C zdP!jbmEj&!t3akcm}Y>b$Aew1i+~U#x7ko@+t!RW{*yd-5|mapqLsf-bmyZ-1Q7F%n#`GOLO;eu;r(-2@{W}vJT$Y)WwXt33t5o3FzMx`94;!0-9t=Cua@CFV*6+WPCqV(iNpb-=e zj09-`4j@7V6T=T^tJV?&LkS2^`O;9?thNBeLU2XLta8hE1F#C3w7h~YAc{+ zI$-ji1$0=Rg127sYj|FS9OS}VGlHfq)bxR$?J0OGW&4se=jYQ`y!7*<66CKg7u>Cd z8{$_KW(;%orvC@M-J>93Zm}!h@U{>*(v5dY*GY{s_vqXbjFJ%(k{bwl@nH_99TWWD=wA!lH8`Fa01YOfC zwcggAJ;xA85KvcVhqu+6dSLs3w@NkI;4RYv%X((SYY7G1KA9lvXaXf4c&pDfycHZT zg)lX*;w-{>E_jR6ruPMtlP3iktormJ2|@r&65cjU02Jdan;QUEau(h;EwSFo8oQQm z1Vs5%f@tx(`naVM(L(e377=TB8(FxjufSVa>aoSP{35%V+hU##Z^OWAAGi4J z9I#lZ`;w6&lZAXXVC#V8sznQZh0V^;ER?l`R?2O|TL{l@<4U@W84#S0>S~dFqQ^Gh zZ^K)cP+}M5HBOS$>RG|tP~6JGb~hW|IzzibQFt3EccN|*F;?n2%StvZy5TLyMFw$u z!s_H9%7{rmxF)KNaeFts)uMo^=BE+bFb4}l{glW6*I_|fq{&7Ou1of^9aEr z)-M}es`Rnca))4W45&4$ZGmt&WPmQ~i=FZIkLon%1YYl_(s1N3qu5&0vtx`6Ht|}^Aw(wh=+z#|cx-Q<{ z_^n4|K7&g(*9tXF^>SAx7cl0HwzU9R&^CZ;V1k)t?Qm_wit{p43~x5bb$4vFh%_@GbD{=bk z%VurtJyvHxu)}g|w=9uUd+Lwge=U~(Nb=&;UBhJWbIh9O(lN|=^H<+xX9!d30l-ncXFBVa%Z;i6&Z?g) zyl96Yl?@0GoE^~d;j{NYZxnk8XJ4vOmfdV(Ltlr=8Z5r@y!h*sp>FlggX&sIdipqE zh-l#+2Ix8Hc7*Ron&gu8RhdLD8%Wj}ZYNaJ^BGb;w(rVz)frCvXcYC;u_ep48#_-C zNpp_H_ORYkHVlaE3E8}~hSFY9n+{3^-C89MmbspcIT z@9J&0*9=_4xQ=7kiz(N6;tZ74XG)O~ncmy4Hw!LSwJ1BbG`EjF5a4xRE_az@(K!2g zyPal1tq|{wzsV_kwJ2w{9X{;UG3I_mV&z#tX059=FsAOb!w%SbhdD=1 z1nS7N=2RnsX|c7l=M^SKWh+=*N?LlX+yJ+_bM2OpjXv(t%Z9f>=0b+{=u^mZrn&_$4MPfV zm8MA^R@*>s10pu61e;Plpo$@ILVi_AaG?L14^V zUeDpGY5iIZt8kBU>$ii}@FD~zPvo^F2yWZ1cZU@?4Y1JJEZw3)_~Tp%$prb`l0A&R zDfc()PZr=?tusBH^$|(%)uf?$nP0)X?$Ng29(J3mBi80+Ng_#Sb3l|hx7Bb{2Q(P%w#Q`;ipiMKKkeWg&SzK}hCLndust4E z8%42*z~PXl?VPbxlgQC(f1&h2?0&HXq%4OK77|=jp7CdRtK{$V`diMBUn}9l)n>gf z!{Nd;3B9bJY`mBNUKpq*L0ufG_;#I(bmb zu76AiLSUrhy36i3bXBC`uw3@tR!xj*3@+o3$7#gmVgFrTgGoX3Tj#Od#KFjbF@emR z2PRv7fLbLda4L{db?QhIh79_NHv_h5v2ogDAF@EAT?rExXUKA6wvYB-y`Z#QpAD`; z)HHIPE6+n*|L9QF^%C|fv`l9dE6D*V642n%Lp`ZDSCvhu?%a-MsL~xiy1XaV>%(#z z!qhwYIuH>^iQV*UKWGfCy_t!&xO^}tj{&92R)|!xWU3%$?J#rphCFAW* bae@U53lc+s1@u*7Jj)0TLL1}`uCD$sO9uKC literal 0 HcmV?d00001 diff --git a/engine/code/quake.ico b/engine/code/quake.ico new file mode 100644 index 0000000000000000000000000000000000000000..7f26d2c140b6e4c40e7e79501dcb48a52490a5f5 GIT binary patch literal 56715 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 +#include +#include +#include +#include +#include + +// jkrige - pack naming convention +#include +// jkrige - pack naming convention + +#if defined(_WIN32) && !defined(WINDED) + +#if defined(_M_IX86) +#define __i386__ 1 +#endif + +void VID_LockBuffer (void); +void VID_UnlockBuffer (void); + +#else + +#define VID_LockBuffer() +#define VID_UnlockBuffer() + +#endif + +#if defined __i386__ // && !defined __sun__ +#define id386 0 // jkrige - assembly removal (was 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 // jkrige - memory increase: 5 570 560 bytes +#define MINIMUM_MEMORY 0xAA0000 // jkrige - memory increase: 11 141 120 bytes +#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 + +// jkrige - pk3 file support +#define MAX_ZPATH 256 // max length of a filesystem pathname, which must include a terminating zero +// jkrige - pk3 file support + + +#define ON_EPSILON 0.1 // point on plane side epsilon + +#define MAX_MSGLEN 8000 // max length of a reliable message +#define MAX_DATAGRAM 1024 // max length of unreliable message + +// +// per-level limits +// +#define MAX_EDICTS 600 // FIXME: ouch! ouch! ouch! +#define MAX_LIGHTSTYLES 64 +#define MAX_MODELS 256 // these are sent over the net as bytes +#define MAX_SOUNDS 256 // so they cannot be blindly increased + +#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<origin[0]; + org[1] = ent->origin[1]; + org[2] = ent->origin[2]; + for (i=-16 ; i<16 ; i+=8) + for (j=-16 ; j<16 ; j+=8) + for (k=0 ; k<32 ; k+=8) + { + 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 = 150 + rand()%6; + 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); + } +} +#endif + + +/* +=============== +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); + } +} + +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); + } +} + + +/* +=============== +R_DrawParticles +=============== +*/ +extern cvar_t sv_gravity; + +void R_DrawParticles (void) +{ + particle_t *p, *kill; + float grav; + int i; + float time2, time3; + float time1; + float dvel; + float frametime; + +#ifdef GLQUAKE + vec3_t up, right; + float scale; +#endif + + // jkrige - wireframe + if (gl_wireframe.value) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + // jkrige - wireframe + +#ifdef GLQUAKE + + // jkrige - texture mode + //GL_Bind(particletexture); + if(gl_texturemode.value == 0.0f) + GL_Bind(particletexture_point); + else + GL_Bind(particletexture_linear); + // jkrige - texture mode + + glEnable (GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBegin (GL_TRIANGLES); + + VectorScale (vup, 1.5, up); + VectorScale (vright, 1.5, right); +#else + D_StartParticles (); + + VectorScale (vright, xscaleshrink, r_pright); + VectorScale (vup, yscaleshrink, r_pup); + VectorCopy (vpn, r_ppn); +#endif + frametime = cl.time - cl.oldtime; + time3 = frametime * 15; + time2 = frametime * 10; // 15; + 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; + } + +#ifdef GLQUAKE + // 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; + else + scale = 1 + scale * 0.004; + glColor3ubv ((byte *)&d_8to24table[(int)p->color]); + glTexCoord2f (0,0); + glVertex3fv (p->org); + glTexCoord2f (1,0); + glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale); + glTexCoord2f (0,1); + glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale); +#else + D_DrawParticle (p); +#endif + 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: +#ifdef QUAKE2 + p->vel[2] -= grav * 20; + break; +#endif + case pt_slowgrav: + p->vel[2] -= grav; + break; + } + } + +#ifdef GLQUAKE + glEnd (); + glDisable (GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +#else + D_EndParticles (); +#endif + + // jkrige - wireframe + if (gl_wireframe.value) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + // jkrige - wireframe +} diff --git a/engine/code/render.h b/engine/code/render.h new file mode 100644 index 0000000..f9fe1e2 --- /dev/null +++ b/engine/code/render.h @@ -0,0 +1,162 @@ +/* +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. + +*/ + +// 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; + + +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, particals, 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 +} 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; + +extern struct texture_s *r_notexture_mip; + + +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 + +// jkrige - 2D polyblend +void R_PolyBlend (void); +// jkrige - 2D polyblend + +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); + +#ifdef QUAKE2 +void R_DarkFieldParticles (entity_t *ent); +#endif +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/engine/code/resource.h b/engine/code/resource.h new file mode 100644 index 0000000..4406ad3 --- /dev/null +++ b/engine/code/resource.h @@ -0,0 +1,19 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by winquake.rc +// +#define IDI_ICON2 1 +#define IDD_DIALOG1 108 +#define IDB_BITMAP1 111 +#define IDB_QUAKE1 111 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 112 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1004 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/engine/code/sbar.c b/engine/code/sbar.c new file mode 100644 index 0000000..c1f3995 --- /dev/null +++ b/engine/code/sbar.c @@ -0,0 +1,1391 @@ +/* +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. + +*/ +// sbar.c -- status bar code + +#include "quakedef.h" + +#ifdef _WIN32 +#include "winquake.h" +#endif + +// jkrige - always draw sbar +//int sb_updates; // if >= vid.numpages, no update needed +// jkrige - always draw sbar + +#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; // jkrige - always draw sbar +} + +/* +=============== +Sbar_DontShowScores + +Tab key up +=============== +*/ +void Sbar_DontShowScores (void) +{ + sb_showscores = false; + //sb_updates = 0; // jkrige - always draw sbar +} + +/* +=============== +Sbar_Changed +=============== +*/ +// jkrige - always draw sbar +/*void Sbar_Changed (void) +{ + sb_updates = 0; // update next frame +}*/ +// jkrige - always draw sbar + +/* +=============== +Sbar_Init +=============== +*/ +void Sbar_Init (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"); + + Cmd_AddCommand ("+showscores", Sbar_ShowScores); + Cmd_AddCommand ("-showscores", Sbar_DontShowScores); + + 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"); + } +} + + +//============================================================================= + +// drawing routines are relative to the status bar location + +/* +============= +Sbar_DrawPic +============= +*/ +void Sbar_DrawPic (int x, int y, qpic_t *pic) +{ + if (cl.gametype == GAME_DEATHMATCH) + Draw_Pic (x + ((vid.width - 320)>>1), y + (vid.height-SBAR_HEIGHT), pic); // jkrige - uncommented ((vid.width - 320)>>1) + else + Draw_Pic (x + ((vid.width - 320)>>1), y + (vid.height-SBAR_HEIGHT), pic); +} + +/* +============= +Sbar_DrawTransPic +============= +*/ +void Sbar_DrawTransPic (int x, int y, qpic_t *pic) +{ + if (cl.gametype == GAME_DEATHMATCH) + Draw_TransPic (x + ((vid.width - 320)>>1), y + (vid.height-SBAR_HEIGHT), pic); // jkrige - uncommented ((vid.width - 320)>>1) + else + Draw_TransPic (x + ((vid.width - 320)>>1), y + (vid.height-SBAR_HEIGHT), pic); +} + +/* +================ +Sbar_DrawCharacter + +Draws one solid graphics character +================ +*/ +void Sbar_DrawCharacter (int x, int y, int num) +{ + if (cl.gametype == GAME_DEATHMATCH) + Draw_Character (x + ((vid.width - 320)>>1) + 4, y + vid.height-SBAR_HEIGHT, num); // jkrige - uncommented ((vid.width - 320)>>1) + else + Draw_Character (x + ((vid.width - 320)>>1) + 4, y + vid.height-SBAR_HEIGHT, num); +} + +/* +================ +Sbar_DrawString +================ +*/ +void Sbar_DrawString (int x, int y, char *str) +{ + if (cl.gametype == GAME_DEATHMATCH) + Draw_String (x + ((vid.width - 320)>>1), y + vid.height-SBAR_HEIGHT, str); // jkrige - uncommented ((vid.width - 320)>>1) + else + Draw_String (x + ((vid.width - 320)>>1), y + vid.height-SBAR_HEIGHT, str); +} + +/* +============= +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; + + 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_DrawTransPic (x,y,sb_nums[color][frame]); + 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 +=============== +*/ +void Sbar_SoloScoreboard (void) +{ + char str[80]; + int minutes, seconds, tens, units; + int l; + + sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]); + Sbar_DrawString (8, 4, str); + + sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]); + Sbar_DrawString (8, 12, str); + +// time + minutes = cl.time / 60; + seconds = cl.time - 60*minutes; + tens = seconds / 10; + units = seconds - 10*tens; + sprintf (str,"Time :%3i:%i%i", minutes, tens, units); + Sbar_DrawString (184, 4, str); + +// draw level name + l = strlen (cl.levelname); + Sbar_DrawString (232 - l*4, 12, cl.levelname); +} + +/* +=============== +Sbar_DrawScoreboard +=============== +*/ +void Sbar_DrawScoreboard (void) +{ + Sbar_SoloScoreboard (); + if (cl.gametype == GAME_DEATHMATCH) + Sbar_DeathmatchOverlay (); +#if 0 + int i, j, c; + int x, y; + int l; + int top, bottom; + scoreboard_t *s; + + if (cl.gametype != GAME_DEATHMATCH) + { + Sbar_SoloScoreboard (); + return; + } + + Sbar_UpdateScoreboard (); + + l = scoreboardlines <= 6 ? scoreboardlines : 6; + + 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*8+10 + ((vid.width - 320)>>1), y + vid.height - SBAR_HEIGHT, 28, 4, top); + Draw_Fill ( x*8+10 + ((vid.width - 320)>>1), y+4 + vid.height - SBAR_HEIGHT, 28, 4, bottom); + + // draw text + for (j=0 ; j<20 ; j++) + { + c = scoreboardtext[i][j]; + if (c == 0 || c == ' ') + continue; + Sbar_DrawCharacter ( (x+j)*8, y, c); + } + } +#endif +} + +//============================================================================= + +/* +=============== +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_DrawPic (0, -24, rsb_invbar[0]); + else + Sbar_DrawPic (0, -24, rsb_invbar[1]); + } + else + { + Sbar_DrawPic (0, -24, sb_ibar); + } + +// 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 + // jkrige - always draw sbar + } + } + +// 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 + // jkrige - always draw sbar + } + } + } + + 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",cl.stats[STAT_SHELLS+i] ); + 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; // jkrige - always draw sbar + } + else + { + //MED 01/04/97 changed keys + if (!hipnotic || (i>1)) + { + Sbar_DrawPic (192 + i*16, -16, sb_items[i]); + } + } + + // jkrige - always draw sbar + //if (time && time > cl.time - 2) + // sb_updates = 0; + // jkrige - always draw sbar + + } + //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]); + } + + // jkrige - always draw sbar + //if (time && time > cl.time - 2) + // sb_updates = 0; + // jkrige - always draw sbar + } + } + + 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; // jkrige - always draw sbar + } + else + { + Sbar_DrawPic (288 + i*16, -16, rsb_items[i]); + } + + // jkrige - always draw sbar + //if (time && time > cl.time - 2) + // sb_updates = 0; + // jkrige - always draw sbar + } + } + } + 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; // jkrige - always draw sbar + } + else + Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]); + + // jkrige - always draw sbar + //if (time && time > cl.time - 2) + // sb_updates = 0; + // jkrige - always draw sbar + } + } + } +} + +//============================================================================= + +/* +=============== +Sbar_DrawFrags +=============== +*/ +void Sbar_DrawFrags (void) +{ + int i, k, l; + int top, bottom; + int x, y, f; + int xofs; + char num[12]; + scoreboard_t *s; + + Sbar_SortFrags (); + +// draw the text + l = scoreboardlines <= 4 ? scoreboardlines : 4; + + x = 23; + //if (cl.gametype == GAME_DEATHMATCH) // jkrige - uncommented ((vid.width - 320)>>1) + // xofs = 0; + //else + xofs = (vid.width - 320)>>1; + y = vid.height - SBAR_HEIGHT - 23; + + 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 (xofs + x*8 + 10, y, 28, 4, top); + Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom); + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + Sbar_DrawCharacter ( (x+1)*8 , -24, num[0]); + Sbar_DrawCharacter ( (x+2)*8 , -24, num[1]); + Sbar_DrawCharacter ( (x+3)*8 , -24, num[2]); + + if (k == cl.viewentity - 1) + { + Sbar_DrawCharacter (x*8+2, -24, 16); + Sbar_DrawCharacter ( (x+4)*8-4, -24, 17); + } + x+=4; + } +} + +//============================================================================= + + +/* +=============== +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) // jkrige - uncommented ((vid.width - 320)>>1) + // xofs = 113; + //else + xofs = ((vid.width - 320)>>1) + 113; + + Sbar_DrawPic (112, 0, rsb_teambord); + Draw_Fill (xofs, vid.height-SBAR_HEIGHT+3, 22, 9, top); + Draw_Fill (xofs, vid.height-SBAR_HEIGHT+12, 22, 9, bottom); + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + if (top==8) + { + if (num[0] != ' ') + Sbar_DrawCharacter(109, 3, 18 + num[0] - '0'); + if (num[1] != ' ') + Sbar_DrawCharacter(116, 3, 18 + num[1] - '0'); + if (num[2] != ' ') + Sbar_DrawCharacter(123, 3, 18 + num[2] - '0'); + } + else + { + Sbar_DrawCharacter ( 109, 3, num[0]); + Sbar_DrawCharacter ( 116, 3, num[1]); + Sbar_DrawCharacter ( 123, 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; + + // jkrige - always draw sbar + //sb_updates = 0; // make sure the anim gets drawn over + // jkrige - always draw sbar + } + else + anim = 0; + Sbar_DrawPic (112, 0, sb_faces[f][anim]); +} + +/* +=============== +Sbar_Draw +=============== +*/ +void Sbar_Draw (void) +{ + if (scr_con_current == vid.height) + return; // console is full screen + + // jkrige - always draw sbar + //if (sb_updates >= vid.numpages) + // return; + // jkrige - always draw sbar + + scr_copyeverything = 1; + + // jkrige - always draw sbar + //sb_updates++; + // jkrige - always draw sbar + + // jkrige - scale2d + //if (sb_lines && vid.width > 320) + // Draw_TileClear (0, vid.height - sb_lines, vid.width, sb_lines); + // jkrige - scale2d + + if (sb_lines > 24) + { + Sbar_DrawInventory (); + if (cl.maxclients != 1) + Sbar_DrawFrags (); + } + + if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) + { + Sbar_DrawPic(0, 0, sb_scorebar); + Sbar_DrawScoreboard (); + //sb_updates = 0; // jkrige - always draw sbar + } + else if (sb_lines) + { + Sbar_DrawPic(0, 0, sb_sbar); + + // 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); + } + + if (vid.width > 320) + { + 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_TransPic (x,y,sb_nums[color][frame]); + 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; + + scr_copyeverything = 1; + scr_fullupdate = 0; + + pic = Draw_CachePic ("gfx/ranking.lmp"); + M_DrawPic ((320-pic->width)/2, 8, pic); + +// scores + Sbar_SortFrags (); + +// draw the text + l = scoreboardlines; + + x = 80 + ((vid.width - 320)>>1); + 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); + Draw_Fill ( x, y+4, 40, 4, bottom); + + // draw 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]); + + if (k == cl.viewentity - 1) + Draw_Character ( x - 8, y, 12); + +#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); + + Draw_String ( x+48 , y, num); +} +#endif + + // draw name + Draw_String (x+64, y, s->name); + + y += 10; + } +} + +/* +================== +Sbar_DeathmatchOverlay + +================== +*/ +void Sbar_MiniDeathmatchOverlay (void) +{ + qpic_t *pic; + int i, k, l; + int top, bottom; + int x, y, f; + char num[12]; + scoreboard_t *s; + int numlines; + + if (vid.width < 512 || !sb_lines) + return; + + scr_copyeverything = 1; + scr_fullupdate = 0; + +// scores + Sbar_SortFrags (); + +// draw the text + l = scoreboardlines; + y = vid.height - sb_lines-16; // jkrige - viewsize & statusbar (added -16) + numlines = sb_lines/8; + if (numlines < 3) + return; + + //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 = vid.width / 2; // jkrige - viewsize & statusbar (was 324) + for (/* */; i < scoreboardlines && y < vid.height - 8 ; i++) + { + k = fragsort[i]; + s = &cl.scores[k]; + if (!s->name[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+1, 40, 3, top); + Draw_Fill ( x, y+4, 40, 4, bottom); + + // draw 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]); + + if (k == cl.viewentity - 1) { + Draw_Character ( x, y, 16); + Draw_Character ( x + 32, y, 17); + } + +#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); + + Draw_String ( x+48 , y, num); +} +#endif + + // draw name + Draw_String (x+48, y, s->name); + + y += 8; + } +} + +/* +================== +Sbar_IntermissionOverlay + +================== +*/ +void Sbar_IntermissionOverlay (void) +{ + qpic_t *pic; + int dig; + int num; + + // jkrige - centered intermission + int cx = vid.width / 2; + int cy = vid.height / 2; + // jkrige - centered intermission + + + scr_copyeverything = 1; + scr_fullupdate = 0; + + if (cl.gametype == GAME_DEATHMATCH) + { + Sbar_DeathmatchOverlay (); + return; + } + + + // jkrige - centered intermission + /*pic = Draw_CachePic ("gfx/complete.lmp"); + Draw_Pic (64, 24, pic); + + pic = Draw_CachePic ("gfx/inter.lmp"); + Draw_TransPic (0, 56, pic);*/ + + pic = Draw_CachePic ("gfx/complete.lmp"); + Draw_Pic (cx-94, cy - 96, pic); + + pic = Draw_CachePic ("gfx/inter.lmp"); + Draw_TransPic (cx-160, cy - 64, pic); + // jkrige - centered intermission + +// time + dig = cl.completed_time/60; + + // jkrige - centered intermission + //Sbar_IntermissionNumber (160, 64, dig, 3, 0); + Sbar_IntermissionNumber (cx, cy - 56, dig, 3, 0); + // jkrige - centered intermission + + num = cl.completed_time - dig*60; + + // jkrige - centered intermission + /*Draw_TransPic (234,64,sb_colon); + Draw_TransPic (246,64,sb_nums[0][num/10]); + Draw_TransPic (266,64,sb_nums[0][num%10]); + + Sbar_IntermissionNumber (160, 104, cl.stats[STAT_SECRETS], 3, 0); + Draw_TransPic (232,104,sb_slash); + Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0); + + Sbar_IntermissionNumber (160, 144, cl.stats[STAT_MONSTERS], 3, 0); + Draw_TransPic (232,144,sb_slash); + Sbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);*/ + + Draw_TransPic (cx+74, cy-56, sb_colon); + Draw_TransPic (cx+86, cy-56, sb_nums[0][num/10]); + Draw_TransPic (cx+106, cy-56, sb_nums[0][num%10]); + + Sbar_IntermissionNumber (cx, cy-16, cl.stats[STAT_SECRETS], 3, 0); + Draw_TransPic (cx+72, cy-16, sb_slash); + Sbar_IntermissionNumber (cx+80, cy-16, cl.stats[STAT_TOTALSECRETS], 3, 0); + + Sbar_IntermissionNumber (cx, cy+24, cl.stats[STAT_MONSTERS], 3, 0); + Draw_TransPic (cx+72, cy+24, sb_slash); + Sbar_IntermissionNumber (cx+80, cy+24, cl.stats[STAT_TOTALMONSTERS], 3, 0); + // jkrige - centered intermission +} + + +/* +================== +Sbar_FinaleOverlay + +================== +*/ +void Sbar_FinaleOverlay (void) +{ + qpic_t *pic; + + scr_copyeverything = 1; + + pic = Draw_CachePic ("gfx/finale.lmp"); + Draw_TransPic ( (vid.width-pic->width)/2, 16, pic); +} diff --git a/engine/code/sbar.h b/engine/code/sbar.h new file mode 100644 index 0000000..682c184 --- /dev/null +++ b/engine/code/sbar.h @@ -0,0 +1,41 @@ +/* +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. + +*/ + +// 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. + +#define SBAR_HEIGHT 24 + +extern int sb_lines; // scan lines to draw + +void Sbar_Init (void); + +// jkrige - always draw sbar +//void Sbar_Changed (void); +// call whenever any of the client stats represented on the sbar changes +// jkrige - always draw sbar + +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/engine/code/screen.h b/engine/code/screen.h new file mode 100644 index 0000000..cdb7b51 --- /dev/null +++ b/engine/code/screen.h @@ -0,0 +1,55 @@ +/* +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. + +*/ +// 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); + +extern float scr_con_current; +extern float scr_conlines; // lines of console to display + +extern int scr_fullupdate; // set to 0 to force full redraw +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; + +// only the refresh window will be updated unless these variables are flagged +extern int scr_copytop; +extern int scr_copyeverything; + +extern qboolean block_drawing; + +void SCR_UpdateWholeScreen (void); diff --git a/engine/code/server.h b/engine/code/server.h new file mode 100644 index 0000000..a27e84d --- /dev/null +++ b/engine/code/server.h @@ -0,0 +1,262 @@ +/* +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. + +*/ +// 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 + + // jkrige - skybox + char skybox[128]; + // jkrige - skybox + +#ifdef QUAKE2 + char startspot[64]; +#endif + 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[8192]; +} 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 +#ifdef QUAKE2 +#define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity +#define MOVETYPE_FOLLOW 12 // track movement of aiment +#endif + +// 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 +#ifdef QUAKE2 +#define FL_FLASHLIGHT 8192 +#define FL_ARCHIVE_OVERRIDE 1048576 +#endif + +// entity effects + +#define EF_BRIGHTFIELD 1 +#define EF_MUZZLEFLASH 2 +#define EF_BRIGHTLIGHT 4 +#define EF_DIMLIGHT 8 +#ifdef QUAKE2 +#define EF_DARKLIGHT 16 +#define EF_DARKFIELD 32 +#define EF_LIGHT 64 +#define EF_NODRAW 128 +#endif + +#define SPAWNFLAG_NOT_EASY 256 +#define SPAWNFLAG_NOT_MEDIUM 512 +#define SPAWNFLAG_NOT_HARD 1024 +#define SPAWNFLAG_NOT_DEATHMATCH 2048 + +#ifdef QUAKE2 +// server flags +#define SFL_EPISODE_1 1 +#define SFL_EPISODE_2 2 +#define SFL_EPISODE_3 4 +#define SFL_EPISODE_4 8 +#define SFL_NEW_UNIT 16 +#define SFL_NEW_EPISODE 32 +#define SFL_CROSS_TRIGGERS 65280 +#endif + +//============================================================================ + +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 (); +#ifdef QUAKE2 +void SV_SpawnServer (char *server, char *startspot); +#else +void SV_SpawnServer (char *server); +#endif diff --git a/engine/code/snd_dma.c b/engine/code/snd_dma.c new file mode 100644 index 0000000..ba6a4b0 --- /dev/null +++ b/engine/code/snd_dma.c @@ -0,0 +1,1027 @@ +/* +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. + +*/ +// snd_dma.c -- main control for any streaming sound output device + +#include "quakedef.h" + +#ifdef _WIN32 +#include "winquake.h" +#endif + +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 desired_speed = 11025; +int desired_bits = 16; + +int sound_started=0; + +cvar_t bgmvolume = {"bgmvolume", "1", true}; +cvar_t volume = {"volume", "0.5", 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}; + + +// ==================================================================== +// 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) +{ + //Con_Printf("\nSound Initialization\n"); + Con_Printf("\n-------- Sound Initialization --------\n"); + + if (COM_CheckParm("-nosound")) + return; + + 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); + Cvar_RegisterVariable(&volume); + Cvar_RegisterVariable(&precache); + Cvar_RegisterVariable(&loadas8bit); + Cvar_RegisterVariable(&bgmvolume); + Cvar_RegisterVariable(&bgmbuffer); + Cvar_RegisterVariable(&ambient_level); + Cvar_RegisterVariable(&ambient_fade); + Cvar_RegisterVariable(&snd_noextraupdate); + Cvar_RegisterVariable(&snd_show); + Cvar_RegisterVariable(&_snd_mixahead); + + 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); + + // jkrige - fmod sound system - begin +#ifdef UQE_FMOD + FMOD_Init(); +#else + CDAudio_Init(); +#endif + // jkrige - fmod sound system - end + + Con_Printf("--------------------------------------\n"); +} + + +// ======================================================================= +// 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 ldist, rdist, dist; + vec_t lscale, rscale, scale; + vec3_t source_vec; + sfx_t *snd; + +// 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 && !pDSBuf)) +#else + if (!sound_started || !shm || !shm->buffer) +#endif + return; + + if (shm->samplebits == 8) + clear = 0x80; + else + clear = 0; + +#ifdef _WIN32 + if (pDSBuf) + { + DWORD dwSize; + DWORD *pData; + int reps; + HRESULT hresult; + + reps = 0; + + while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize, NULL, NULL, 0)) != DS_OK) + { + if (hresult != DSERR_BUFFERLOST) + { + Con_Printf ("S_ClearBuffer: DS::Lock Sound Buffer Failed\n"); + S_Shutdown (); + return; + } + + if (++reps > 10000) + { + Con_Printf ("S_ClearBuffer: DS: couldn't restore buffer\n"); + S_Shutdown (); + return; + } + } + + Q_memset(pData, clear, shm->samples * shm->samplebits/8); + + pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0); + + } + else +#endif + { + 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; + +// 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) +{ + +#ifdef _WIN32 + IN_Accumulate (); +#endif + + 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; + +#ifdef _WIN32 +// if the buffer was lost or stopped, restore it and/or restart it + { + DWORD dwStatus; + + if (pDSBuf) + { + if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK) + Con_Printf ("Couldn't get sound buffer status\n"); + + if (dwStatus & DSBSTATUS_BUFFERLOST) + pDSBuf->lpVtbl->Restore (pDSBuf); + + if (!(dwStatus & DSBSTATUS_PLAYING)) + pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); + } + } +#endif + + 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_Printf ("L"); + else + Con_Printf (" "); + Con_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name); + } + Con_Printf ("Total resident: %i\n", total); +} + + +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/engine/code/snd_fmod.c b/engine/code/snd_fmod.c new file mode 100644 index 0000000..a061b14 --- /dev/null +++ b/engine/code/snd_fmod.c @@ -0,0 +1,1129 @@ +/* +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. + +*/ +// snd_fmod.c: FMOD sound system implementation for music playback + +// Developed by Jacques Krige +// Ultimate Quake Engine +// http://www.jacqueskrige.com + + +#include "quakedef.h" + + +#ifdef _WIN32 +#include "winquake.h" +#endif + + +#ifndef UQE_FMOD_CDAUDIO +#include "cdaudio.h" +#endif + +#ifdef UQE_FMOD + +#pragma comment(lib, "../fmod-4/lib/fmodex_vc.lib") + +#include "../fmod-4/inc/fmod.h" +#include "../fmod-4/inc/fmod_errors.h" + +extern int sound_started; + +typedef struct +{ + void *data; + int length; + char filename[MAX_QPATH]; +} SND_File_t; + +typedef struct +{ + float volume; + FMOD_CHANNEL *channel; + int track; + char trackname[MAX_QPATH]; + qboolean inuse; + qboolean looping; + int loopcount; + qboolean paused; +} SND_Channel_t; + + +SND_File_t SND_File; +SND_Channel_t SND_MusicChannel; + +FMOD_SYSTEM *fmod_system; +FMOD_SOUND *fmod_sound; +FMOD_SOUND *fmod_compactdisc; + +FMOD_RESULT fmod_result; + +qboolean SND_Initialised; +qboolean SND_InitialisedCD; + +int oldtrack; + +char bgmtype[16]; +char oldbgmtype[16]; + +float oldbgmvolume; + + +// forward declarations +void FMOD_Restart (void); +void FMOD_MusicStartConsole (void); +void FMOD_MusicUpdate(char *newbgmtype); + + + +// =================================================================================== +// +// CUSTOM FMOD FILE ROUTINES TO ALLOW PAK FILE ACCESS +// +// =================================================================================== + +/* +=================== +SND_FOpen +=================== +*/ +qboolean SND_FOpen (const char *name) +{ + int len; + FILE *f; + + if ((len = COM_FOpenFile((char *)name, &f)) < 1) + { + Con_Printf("SND_FOpen: Failed to open %s, file not found\n", name); + return false; + } + + if (!SND_File.length) + { + strcpy(SND_File.filename, name); + SND_File.length = len; + SND_File.data = COM_FReadFile(f, len); + Con_DPrintf("SND_FOpen: Sucessfully opened %s\n", name); + + return true; + } + + if (f) + fclose(f); + + f = NULL; + + Con_SafePrintf("SND_FOpen: Failed to open %s, insufficient handles\n", name); + + return false; +} + +/* +=================== +SND_FClose +=================== +*/ +void SND_FClose (void) +{ + if (!SND_File.data) + return; + + SND_File.length = 0; + strcpy(SND_File.filename, "\0"); + + if (SND_File.data) + free(SND_File.data); + + SND_File.data = NULL; +} + + + +// =================================================================================== +// +// STARTUP AND SHUTDOWN ROUTINES +// +// =================================================================================== + +/* +=================== +FMOD_ERROR +=================== +*/ +void FMOD_ERROR(FMOD_RESULT result, qboolean notify, qboolean syserror) +{ + if (result != FMOD_OK) + { + if (syserror == false) + { + if (notify == true) + Con_Printf("%s\n", FMOD_ErrorString(result)); + } + else + Sys_Error("FMOD: %s\n", FMOD_ErrorString(result)); + } +} + +/* +=================== +CDA_Startup +=================== +*/ +void CDA_Startup (qboolean notify) +{ +#ifdef UQE_FMOD_CDAUDIO + int i; + int numdrives; + int numtracks; + + if (SND_InitialisedCD == true) + return; + + if (fmod_compactdisc) + return; + + // bump up the file buffer size a bit from the 16k default for CDDA, because it is a slower medium. + fmod_result = FMOD_System_SetStreamBufferSize(fmod_system, 64*1024, FMOD_TIMEUNIT_RAWBYTES); + FMOD_ERROR(fmod_result, notify, false); + + fmod_result = FMOD_System_GetNumCDROMDrives(fmod_system, &numdrives); + FMOD_ERROR(fmod_result, notify, false); + + for (i = 0; i < numdrives; i++) + { + char drivename[MAX_QPATH]; + char scsiname[MAX_QPATH]; + char devicename[MAX_QPATH]; + + fmod_result = FMOD_System_GetCDROMDriveName(fmod_system, i, drivename, MAX_QPATH, scsiname, MAX_QPATH, devicename, MAX_QPATH); + FMOD_ERROR(fmod_result, notify, false); + + if (fmod_result == FMOD_OK) + { + fmod_result = FMOD_System_CreateStream(fmod_system, drivename, FMOD_OPENONLY, 0, &fmod_compactdisc); + + if (fmod_result == FMOD_OK) + { + fmod_result = FMOD_Sound_GetNumSubSounds(fmod_compactdisc, &numtracks); + FMOD_ERROR(fmod_result, notify, false); + + if (fmod_result == FMOD_OK) + { + Con_Printf("CD Audio Initialized (%s)\n", drivename); + SND_InitialisedCD = true; + + break; + } + } + } + } + + FMOD_ERROR(fmod_result, notify, false); +#else + CDAudio_Init(); +#endif +} + +/* +=================== +CDA_Shutdown +=================== +*/ +void CDA_Shutdown (void) +{ +#ifdef UQE_FMOD_CDAUDIO + if (SND_InitialisedCD == false) + return; + + if (fmod_compactdisc) + { + fmod_result = FMOD_Sound_Release(fmod_compactdisc); + FMOD_ERROR(fmod_result, true, false); + + fmod_compactdisc = NULL; + } + + SND_InitialisedCD = false; +#else + CDAudio_Shutdown (); +#endif +} + +/* +=================== +FMOD_Startup +=================== +*/ +void FMOD_Startup (void) +{ + FMOD_CAPS caps; + FMOD_SPEAKERMODE speakermode; + FMOD_OUTPUTTYPE fmod_output; + unsigned int version; + int numdrivers; + char name[256]; + int SND_SoftwareChannels; + int SND_HardwareChannels; + int SND_Bits; + int SND_Rate; + + fmod_result = FMOD_System_Create(&fmod_system); + FMOD_ERROR(fmod_result, true, false); + + fmod_result = FMOD_System_GetVersion(fmod_system, &version); + FMOD_ERROR(fmod_result, true, false); + + if (version < FMOD_VERSION) + { + Con_Printf("\nFMOD version incorrect, found v%1.2f, requires v%1.2f or newer\n", version, FMOD_VERSION); + return; + } + + fmod_result = FMOD_System_GetNumDrivers(fmod_system, &numdrivers); + FMOD_ERROR(fmod_result, true, false); + + if (numdrivers == 0) + { + fmod_result = FMOD_System_SetOutput(fmod_system, FMOD_OUTPUTTYPE_NOSOUND); + FMOD_ERROR(fmod_result, true, false); + } + else + { + fmod_result = FMOD_System_SetOutput(fmod_system, FMOD_OUTPUTTYPE_AUTODETECT); + FMOD_ERROR(fmod_result, true, false); + + fmod_result = FMOD_System_GetDriverCaps(fmod_system, 0, &caps, NULL, &speakermode); + FMOD_ERROR(fmod_result, true, false); + + // set the user selected speaker mode + fmod_result = FMOD_System_SetSpeakerMode(fmod_system, FMOD_SPEAKERMODE_STEREO /*speakermode*/); + FMOD_ERROR(fmod_result, true, false); + + if (caps & FMOD_CAPS_HARDWARE_EMULATED) + { + // the user has the 'Acceleration' slider set to off. this is really bad for latency! + fmod_result = FMOD_System_SetDSPBufferSize(fmod_system, 1024, 10); + FMOD_ERROR(fmod_result, true, false); + + Con_Printf("\nHardware Acceleration is turned off!\n"); + } + + fmod_result = FMOD_System_GetDriverInfo(fmod_system, 0, name, 256, NULL); + FMOD_ERROR(fmod_result, true, false); + + if (strstr(name, "SigmaTel")) + { + // Sigmatel sound devices crackle for some reason if the format is PCM 16bit. + // PCM floating point output seems to solve it. + fmod_result = FMOD_System_SetSoftwareFormat(fmod_system, 48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0, 0, FMOD_DSP_RESAMPLER_LINEAR); + FMOD_ERROR(fmod_result, true, false); + } + } + + fmod_result = FMOD_System_GetSoftwareChannels(fmod_system, &SND_SoftwareChannels); + FMOD_ERROR(fmod_result, true, false); + + fmod_result = FMOD_System_GetSoftwareFormat(fmod_system, &SND_Rate, NULL, NULL, NULL, NULL, &SND_Bits); + FMOD_ERROR(fmod_result, true, false); + + fmod_result = FMOD_System_Init(fmod_system, MAX_CHANNELS, FMOD_INIT_NORMAL, NULL); + FMOD_ERROR(fmod_result, true, false); + + if (fmod_result == FMOD_ERR_OUTPUT_CREATEBUFFER) + { + // the speaker mode selected isn't supported by this soundcard. Switch it back to stereo... + fmod_result = FMOD_System_SetSpeakerMode(fmod_system, FMOD_SPEAKERMODE_STEREO); + FMOD_ERROR(fmod_result, true, false); + + // ... and re-init. + fmod_result = FMOD_System_Init(fmod_system, MAX_CHANNELS, FMOD_INIT_NORMAL, NULL); + FMOD_ERROR(fmod_result, true, false); + } + + fmod_result = FMOD_System_GetSpeakerMode(fmod_system, &speakermode); + FMOD_ERROR(fmod_result, true, false); + + fmod_result = FMOD_System_GetOutput(fmod_system, &fmod_output); + FMOD_ERROR(fmod_result, true, false); + + fmod_result = FMOD_System_GetHardwareChannels(fmod_system, &SND_HardwareChannels); + FMOD_ERROR(fmod_result, true, false); + + + // print all the sound information to the console + Con_Printf("\nFMOD version %01x.%02x.%02x\n", (FMOD_VERSION >> 16) & 0xff, (FMOD_VERSION >> 8) & 0xff, FMOD_VERSION & 0xff); + + switch (fmod_output) + { + case FMOD_OUTPUTTYPE_NOSOUND: + Con_Printf("using No Sound\n"); + break; + + case FMOD_OUTPUTTYPE_DSOUND: + Con_Printf("using Microsoft DirectSound\n"); + break; + + case FMOD_OUTPUTTYPE_WINMM: + Con_Printf("using Windows Multimedia\n"); + break; + + case FMOD_OUTPUTTYPE_WASAPI: + Con_Printf("using Windows Audio Session API\n"); + break; + + case FMOD_OUTPUTTYPE_ASIO: + Con_Printf("using Low latency ASIO\n"); + break; + } + + Con_Printf(" software channels: %i\n", SND_SoftwareChannels); + Con_Printf(" hardware channels: %i\n", SND_HardwareChannels); + Con_Printf(" %i bits/sample\n", SND_Bits); + Con_Printf(" %i bytes/sec\n", SND_Rate); + + switch (speakermode) + { + case FMOD_SPEAKERMODE_RAW: + Con_Printf("Speaker Output: Raw\n"); + break; + + case FMOD_SPEAKERMODE_MONO: + Con_Printf("Speaker Output: Mono\n"); + break; + + case FMOD_SPEAKERMODE_STEREO: + Con_Printf("Speaker Output: Stereo\n"); + break; + + case FMOD_SPEAKERMODE_QUAD: + Con_Printf("Speaker Output: Quad\n"); + break; + + case FMOD_SPEAKERMODE_SURROUND: + Con_Printf("Speaker Output: Surround\n"); + break; + + case FMOD_SPEAKERMODE_5POINT1: + Con_Printf("Speaker Output: 5.1\n"); + break; + + case FMOD_SPEAKERMODE_7POINT1: + Con_Printf("Speaker Output: 7.1\n"); + break; + + case FMOD_SPEAKERMODE_SRS5_1_MATRIX: + Con_Printf("Speaker Output: Stereo compatible\n"); + break; + + case FMOD_SPEAKERMODE_MYEARS: + Con_Printf("Speaker Output: Headphones\n"); + break; + + default: + Con_Printf("Speaker Output: Unknown\n"); + } + + strcpy(bgmtype, "cd"); + oldbgmvolume = bgmvolume.value; + + SND_FClose(); + CDA_Startup(true); + + SND_Initialised = true; + + // clear music channel + SND_MusicChannel.volume = 0.0f; + SND_MusicChannel.channel = NULL; + SND_MusicChannel.track = 0; + strcpy(SND_MusicChannel.trackname, "\0"); + SND_MusicChannel.inuse = false; + SND_MusicChannel.looping = false; + SND_MusicChannel.loopcount = 0; + SND_MusicChannel.paused = false; +} + +/* +=================== +FMOD_Shutdown +=================== +*/ +void FMOD_Shutdown(void) +{ + if (COM_CheckParm("-nosound")) + { + SND_Initialised = false; + SND_InitialisedCD = false; + return; + } + + FMOD_MusicStop(); + CDA_Shutdown(); + + if (fmod_system) + { + fmod_result = FMOD_System_Close(fmod_system); + FMOD_ERROR(fmod_result, true, false); + + fmod_result = FMOD_System_Release(fmod_system); + FMOD_ERROR(fmod_result, true, false); + + fmod_system = NULL; + } + + SND_Initialised = false; + + // clear music channel + SND_MusicChannel.volume = 0.0f; + SND_MusicChannel.channel = NULL; + SND_MusicChannel.track = 0; + strcpy(SND_MusicChannel.trackname, "\0"); + SND_MusicChannel.inuse = false; + SND_MusicChannel.looping = false; + SND_MusicChannel.loopcount = 0; + SND_MusicChannel.paused = false; +} + +/* +=================== +FMOD_Init +=================== +*/ +void FMOD_Init (void) +{ + SND_Initialised = false; + SND_InitialisedCD = false; + + if (!sound_started) + return; + + if (COM_CheckParm("-nosound")) + return; + + FMOD_Startup(); + + Cmd_AddCommand("fmod_restart", FMOD_Restart); + Cmd_AddCommand("fmod_playmusic", FMOD_MusicStartConsole); + Cmd_AddCommand("fmod_stopmusic", FMOD_MusicStop); + Cmd_AddCommand("fmod_pausemusic", FMOD_MusicPause); + Cmd_AddCommand("fmod_resumemusic", FMOD_MusicResume); + + //Con_Printf("--------------------------------------\n"); +} + +/* +=================== +FMOD_Restart +=================== +*/ +void FMOD_Restart (void) +{ + int current_track; + char current_trackname[MAX_QPATH]; + qboolean current_inuse; + qboolean current_looping; + + if (!sound_started) + return; + + if (COM_CheckParm("-nosound")) + { + SND_Initialised = false; + SND_InitialisedCD = false; + return; + } + + current_inuse = SND_MusicChannel.inuse; + + // save music info + if (SND_MusicChannel.inuse == true) + { + current_track = SND_MusicChannel.track; + strcpy(current_trackname, SND_MusicChannel.trackname); + current_looping = SND_MusicChannel.looping; + FMOD_MusicStop(); + } + else + { + current_track = 0; + strcpy(current_trackname, "\0"); + current_looping = false; + } + + FMOD_Shutdown(); + FMOD_Startup(); + + // restart music if needed + if (current_inuse == true) + { + if(current_track > 0) + FMOD_MusicStart(va("%i", (int)current_track), current_looping, false); + else + FMOD_MusicStart(current_trackname, current_looping, false); + } +} + +/* +=================== +FMOD_ChannelStart +=================== +*/ +void FMOD_ChannelStart (FMOD_SOUND *sound, qboolean loop, qboolean paused) +{ + fmod_result = FMOD_System_PlaySound(fmod_system, FMOD_CHANNEL_FREE, sound, (FMOD_BOOL)paused, &SND_MusicChannel.channel); + FMOD_ERROR(fmod_result, true, false); + + if ((SND_MusicChannel.looping = loop) == true) + { + fmod_result = FMOD_Channel_SetMode(SND_MusicChannel.channel, FMOD_LOOP_NORMAL); + FMOD_ERROR(fmod_result, true, false); + } + else + { + fmod_result = FMOD_Channel_SetMode(SND_MusicChannel.channel, FMOD_LOOP_OFF); + FMOD_ERROR(fmod_result, true, false); + + fmod_result = FMOD_Channel_SetLoopCount(SND_MusicChannel.channel, 0); + FMOD_ERROR(fmod_result, true, false); + } + + SND_MusicChannel.inuse = true; +} + + + +// =================================================================================== +// +// CD AUDIO CONTROL ROUTINES +// +// =================================================================================== + +/* +=================== +CDA_Start +=================== +*/ +void CDA_Start(int track, qboolean loop, qboolean notify) +{ +#ifdef UQE_FMOD_CDAUDIO + int numtracks; + + if (SND_InitialisedCD == false) + return; + + if (SND_MusicChannel.inuse == true) + FMOD_MusicStop(); + + if (track <= 0) + return; + + fmod_result = FMOD_Sound_GetNumSubSounds(fmod_compactdisc, &numtracks); + FMOD_ERROR(fmod_result, notify, false); + + if (track > numtracks) + return; + + // fmod track numbers starts at zero + fmod_result = FMOD_Sound_GetSubSound(fmod_compactdisc, track - 1, &fmod_sound); + FMOD_ERROR(fmod_result, notify, false); + + if (fmod_result == FMOD_OK) + FMOD_ChannelStart(fmod_sound, loop, false); +#else + CDAudio_Play(track, loop); +#endif +} + +/* +=================== +CDA_Stop +=================== +*/ +void CDA_Stop (void) +{ +#ifdef UQE_FMOD_CDAUDIO + if (SND_InitialisedCD == false) + return; + + if (SND_MusicChannel.inuse == false) + return; + + if (SND_MusicChannel.channel) + { + fmod_result = FMOD_Channel_Stop(SND_MusicChannel.channel); + FMOD_ERROR(fmod_result, true, false); + } + + SND_MusicChannel.inuse = false; + SND_MusicChannel.looping = false; + SND_MusicChannel.loopcount = 0; + SND_MusicChannel.paused = false; +#else + CDAudio_Stop(); +#endif +} + +/* +=================== +CDA_Pause +=================== +*/ +void CDA_Pause (void) +{ +#ifdef UQE_FMOD_CDAUDIO + if (SND_InitialisedCD == false) + return; + + if (SND_MusicChannel.inuse == false) + return; + + if (SND_MusicChannel.paused == false) + { + fmod_result = FMOD_Channel_SetPaused(SND_MusicChannel.channel, true); + FMOD_ERROR(fmod_result, true, false); + + SND_MusicChannel.paused = true; + } +#else + CDAudio_Pause(); +#endif +} + +/* +=================== +CDA_Resume +=================== +*/ +void CDA_Resume (qboolean force) +{ +#ifdef UQE_FMOD_CDAUDIO + if (SND_InitialisedCD == false) + return; + + if (SND_MusicChannel.inuse == false) + return; + + if (SND_MusicChannel.paused == true && SND_MusicChannel.volume != 0.0f && (oldbgmvolume == 0.0f | force == true)) + { + fmod_result = FMOD_Channel_SetPaused(SND_MusicChannel.channel, false); + FMOD_ERROR(fmod_result, true, false); + + SND_MusicChannel.paused = false; + } +#else + CDAudio_Resume(); +#endif +} + +/* +=================== +CDA_Update +=================== +*/ +void CDA_Update (void) +{ +#ifdef UQE_FMOD_CDAUDIO + if (SND_Initialised == false || SND_MusicChannel.inuse == false) + return; + + FMOD_System_Update(fmod_system); + SND_MusicChannel.volume = bgmvolume.value; + + if (SND_MusicChannel.volume < 0.0f) + SND_MusicChannel.volume = 0.0f; + + if (SND_MusicChannel.volume > 1.0f) + SND_MusicChannel.volume = 1.0f; + + FMOD_Channel_SetVolume(SND_MusicChannel.channel, SND_MusicChannel.volume); + + if (SND_MusicChannel.volume == 0.0f) + CDA_Pause(); + else + CDA_Resume(false); +#else + CDAudio_Update(); +#endif +} + + + +// =================================================================================== +// +// MOD AUDIO CONTROL ROUTINES (OGG / MP3 / WAV) +// +// =================================================================================== + +/* +=================== +MOD_Start +=================== +*/ +void MOD_Start (char *name, qboolean loop, qboolean notify) +{ + char file[MAX_QPATH]; + FMOD_CREATESOUNDEXINFO exinfo; + + if (SND_Initialised == false) + return; + + if (SND_MusicChannel.inuse == true) + FMOD_MusicStop(); + + if (strlen(name) == 0) + return; + + if (SND_FOpen(name) == true) + { + memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO)); + exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); + exinfo.length = SND_File.length; + + fmod_result = FMOD_System_CreateSound(fmod_system, (const char *)SND_File.data, FMOD_HARDWARE | FMOD_OPENMEMORY | FMOD_2D, &exinfo, &fmod_sound); + FMOD_ERROR(fmod_result, true, false); + + strcpy(file, SND_File.filename); + SND_FClose(); + } + + if (!fmod_sound) + { + Con_Printf("Couldn't open stream %s\n", file); + return; + } + else + { + if (notify == true) + Con_Printf("Playing: %s...\n", file); + } + + if (fmod_result == FMOD_OK) + FMOD_ChannelStart(fmod_sound, loop, false); +} + +/* +=================== +MOD_Stop +=================== +*/ +void MOD_Stop (void) +{ + if (SND_Initialised == false || SND_MusicChannel.inuse == false) + return; + + if (SND_MusicChannel.channel) + { + fmod_result = FMOD_Channel_Stop(SND_MusicChannel.channel); + FMOD_ERROR(fmod_result, true, false); + } + + if (fmod_sound) + { + fmod_result = FMOD_Sound_Release(fmod_sound); + FMOD_ERROR(fmod_result, true, false); + + fmod_sound = NULL; + } + + SND_MusicChannel.inuse = false; + SND_MusicChannel.looping = false; + SND_MusicChannel.loopcount = 0; + SND_MusicChannel.paused = false; +} + +/* +=================== +MOD_Pause +=================== +*/ +void MOD_Pause (void) +{ + if (SND_Initialised == false || SND_MusicChannel.inuse == false) + return; + + if (SND_MusicChannel.paused == false) + { + fmod_result = FMOD_Channel_SetPaused(SND_MusicChannel.channel, true); + FMOD_ERROR(fmod_result, true, false); + + SND_MusicChannel.paused = true; + } + + if (SND_MusicChannel.volume == 0.0f) + SND_MusicChannel.paused = true; +} + +/* +=================== +MOD_Resume +=================== +*/ +void MOD_Resume (qboolean force) +{ + if (SND_Initialised == false || SND_MusicChannel.inuse == false) + return; + + if (SND_MusicChannel.paused == true && SND_MusicChannel.volume != 0.0f && (oldbgmvolume == 0.0f | force == true)) + { + fmod_result = FMOD_Channel_SetPaused(SND_MusicChannel.channel, false); + FMOD_ERROR(fmod_result, true, false); + + SND_MusicChannel.paused = false; + } +} + +/* +=================== +MOD_Update +=================== +*/ +void MOD_Update (void) +{ + if (SND_Initialised == false || SND_MusicChannel.inuse == false) + return; + + FMOD_System_Update(fmod_system); + SND_MusicChannel.volume = bgmvolume.value; + + if (SND_MusicChannel.volume < 0.0f) + SND_MusicChannel.volume = 0.0f; + + if (SND_MusicChannel.volume > 1.0f) + SND_MusicChannel.volume = 1.0f; + + FMOD_Channel_SetVolume(SND_MusicChannel.channel, SND_MusicChannel.volume); + + if (SND_MusicChannel.volume == 0.0f) + MOD_Pause(); + else + MOD_Resume(false); +} + + + +// =================================================================================== +// +// MAIN FMOD AUDIO CONTROL ROUTINES +// +// =================================================================================== + +/* +=================== +FMOD_MusicStart +=================== +*/ +void FMOD_MusicStart (char *name, qboolean loop, qboolean notify) +{ + int len; + char file[MAX_QPATH]; + char trackname[MAX_QPATH]; + FILE *f; + + if (!sound_started) + return; + + len = -1; + + // check for an existing audio file + if (name != NULL && strlen(name) != 0) + { + COM_StripExtension(name, file); + + sprintf(trackname, "music/%s.ogg", file); + len = COM_FOpenFile((char *)trackname, &f); + if (len < 0) + { + sprintf(trackname, "music/%s.mp3", file); + len = COM_FOpenFile((char *)trackname, &f); + } + if (len < 0) + { + sprintf(trackname, "music/%s.wav", file); + len = COM_FOpenFile((char *)trackname, &f); + } + if (len < 0) + { + sprintf(trackname, "music/track%02i.ogg", atoi(file)); + len = COM_FOpenFile((char *)trackname, &f); + } + if (len < 0) + { + sprintf(trackname, "music/track%02i.mp3", atoi(file)); + len = COM_FOpenFile((char *)trackname, &f); + } + if (len < 0) + { + sprintf(trackname, "music/track%02i.wav", atoi(file)); + len = COM_FOpenFile((char *)trackname, &f); + } + + if (f) + fclose(f); + + f = NULL; + } + + // set the new bgmtype + if (len > 0) + { + // if an audio file exists play it + SND_MusicChannel.track = atoi(file); + strcpy(SND_MusicChannel.trackname, trackname); + FMOD_MusicUpdate("mod"); + } + else + { + // otherwise fall back to CD Audio + SND_MusicChannel.track = atoi(name); + strcpy(SND_MusicChannel.trackname, "\0"); + FMOD_MusicUpdate("cd"); + } + + if (strcmpi(bgmtype, "cd") == 0) + CDA_Start(SND_MusicChannel.track, loop, notify); + + if (strcmpi(bgmtype, "mod") == 0) + MOD_Start(SND_MusicChannel.trackname, loop, notify); +} + +/* +=================== +FMOD_MusicStartConsole +=================== +*/ +void FMOD_MusicStartConsole (void) +{ + char name[MAX_QPATH]; + char file[MAX_QPATH]; + + if (!sound_started) + return; + + if (Cmd_Argc() < 2) + { + Con_Printf ("fmod_playmusic : play an audio file\n"); + return; + } + + sprintf(name, "%s\0", Cmd_Argv(1)); + COM_StripExtension(name, file); + + MOD_Start(file, false, true); + + return; +} + +/* +=================== +FMOD_MusicStop +=================== +*/ +void FMOD_MusicStop (void) +{ + CDA_Stop(); + MOD_Stop(); +} + +/* +=================== +FMOD_MusicPause +=================== +*/ +void FMOD_MusicPause (void) +{ + if (strcmpi(bgmtype, "cd") == 0) + CDA_Pause(); + + if (strcmpi(bgmtype, "mod") == 0) + MOD_Pause(); +} + +/* +=================== +FMOD_MusicResume +=================== +*/ +void FMOD_MusicResume (void) +{ + if (strcmpi(bgmtype, "cd") == 0) + CDA_Resume(true); + + if (strcmpi(bgmtype, "mod") == 0) + MOD_Resume(true); +} + +/* +=================== +FMOD_MusicUpdate +=================== +*/ +void FMOD_MusicUpdate (char *newbgmtype) +{ + if (SND_MusicChannel.track != oldtrack) + { + if (strcmpi(bgmtype, "cd") == 0) + CDA_Stop(); + + if (strcmpi(bgmtype, "mod") == 0) + MOD_Stop(); + + oldtrack = SND_MusicChannel.track; + } + + if (strcmpi(bgmtype, "cd") == 0) + CDA_Update(); + + if (strcmpi(bgmtype, "mod") == 0) + MOD_Update(); + + if (newbgmtype != NULL) + strcpy(bgmtype, newbgmtype); + + if (strcmpi(bgmtype, oldbgmtype) != 0) + { + FMOD_MusicStop(); + strcpy(oldbgmtype, bgmtype); + } + + oldbgmvolume = SND_MusicChannel.volume; +} + +/* +=================== +FMOD_MusicActivate +=================== +*/ +void FMOD_MusicActivate (qboolean active) +{ + if (active) + FMOD_MusicResume(); + else + FMOD_MusicPause(); +} + +/* +=================== +FMOD_MusicActive +=================== +*/ +qboolean FMOD_MusicActive (void) +{ + return SND_MusicChannel.inuse; +} + +#endif diff --git a/engine/code/snd_fmod.h b/engine/code/snd_fmod.h new file mode 100644 index 0000000..2594629 --- /dev/null +++ b/engine/code/snd_fmod.h @@ -0,0 +1,45 @@ +/* +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. + +*/ +// snd_fmod.c: FMOD sound system implementation for music playback + +// Developed by Jacques Krige +// Ultimate Quake Engine +// http://www.jacqueskrige.com + +#ifndef _SND_FMOD_H_ +#define _SND_FMOD_H_ + +#define UQE_FMOD + +#ifdef UQE_FMOD +#define UQE_FMOD_CDAUDIO + +void FMOD_Init (void); +void FMOD_Shutdown (void); +void FMOD_MusicStart (char *name, qboolean loop, qboolean notify); +void FMOD_MusicStop (void); +void FMOD_MusicPause (void); +void FMOD_MusicResume (void); +void FMOD_MusicUpdate (char *newbgmtype); +void FMOD_MusicActivate (qboolean active); +qboolean FMOD_MusicActive (void); +#endif + +#endif diff --git a/engine/code/snd_mem.c b/engine/code/snd_mem.c new file mode 100644 index 0000000..71e32aa --- /dev/null +++ b/engine/code/snd_mem.c @@ -0,0 +1,341 @@ +/* +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. + +*/ +// 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(); +// Con_Printf("loopstart=%d\n", sfx->loopstart); + + // 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/engine/code/snd_mix.c b/engine/code/snd_mix.c new file mode 100644 index 0000000..d31f6c9 --- /dev/null +++ b/engine/code/snd_mix.c @@ -0,0 +1,398 @@ +/* +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. + +*/ +// snd_mix.c -- portable code to mix sounds for snd_dma.c + +#include "quakedef.h" + +#ifdef _WIN32 +#include "winquake.h" +#else +#define DWORD unsigned long +#endif + +#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); + +#if !id386 +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; + } +} +#endif + +void S_TransferStereo16 (int endtime) +{ + int lpos; + int lpaintedtime; + DWORD *pbuf; +#ifdef _WIN32 + int reps; + DWORD dwSize,dwSize2; + DWORD *pbuf2; + HRESULT hresult; +#endif + + snd_vol = volume.value*256; + + snd_p = (int *) paintbuffer; + lpaintedtime = paintedtime; + +#ifdef _WIN32 + if (pDSBuf) + { + reps = 0; + + while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, + &pbuf2, &dwSize2, 0)) != DS_OK) + { + if (hresult != DSERR_BUFFERLOST) + { + Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n"); + S_Shutdown (); + S_Startup (); + return; + } + + if (++reps > 10000) + { + Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n"); + S_Shutdown (); + S_Startup (); + return; + } + } + } + else +#endif + { + 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); + } + +#ifdef _WIN32 + if (pDSBuf) + pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0); +#endif +} + +void S_TransferPaintBuffer(int endtime) +{ + int out_idx; + int count; + int out_mask; + int *p; + int step; + int val; + int snd_vol; + DWORD *pbuf; +#ifdef _WIN32 + int reps; + DWORD dwSize,dwSize2; + DWORD *pbuf2; + HRESULT hresult; +#endif + + 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; + +#ifdef _WIN32 + if (pDSBuf) + { + reps = 0; + + while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, + &pbuf2,&dwSize2, 0)) != DS_OK) + { + if (hresult != DSERR_BUFFERLOST) + { + Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n"); + S_Shutdown (); + S_Startup (); + return; + } + + if (++reps > 10000) + { + Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n"); + S_Shutdown (); + S_Startup (); + return; + } + } + } + else +#endif + { + 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; + } + } + +#ifdef _WIN32 + if (pDSBuf) { + DWORD dwNewpos, dwWrite; + int il = paintedtime; + int ir = endtime - paintedtime; + + ir += il; + + pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0); + + pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite); + +// if ((dwNewpos >= il) && (dwNewpos <= ir)) +// Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos); + } +#endif +} + + +/* +=============================================================================== + +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; +} + + +#if !id386 + +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; +} + +#endif // !id386 + + +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/engine/code/snd_win.c b/engine/code/snd_win.c new file mode 100644 index 0000000..da499b3 --- /dev/null +++ b/engine/code/snd_win.c @@ -0,0 +1,737 @@ +/* +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. + +*/ +#include "quakedef.h" +#include "winquake.h" + +#define iDirectSoundCreate(a,b,c) pDirectSoundCreate(a,b,c) + +HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter); + +// 64K is > 1 second at 16-bit, 22050 Hz +#define WAV_BUFFERS 64 +#define WAV_MASK 0x3F +#define WAV_BUFFER_SIZE 0x0400 +#define SECONDARY_BUFFER_SIZE 0x10000 + +typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat; + +static qboolean wavonly; +static qboolean dsound_init; +static qboolean wav_init; +static qboolean snd_firsttime = true, snd_isdirect, snd_iswave; +static qboolean primary_format_set; + +static int sample16; +static int snd_sent, snd_completed; + + +/* + * Global variables. Must be visible to window-procedure function + * so it can unlock and free the data block after it has been played. + */ + +HANDLE hData; +HPSTR lpData, lpData2; + +HGLOBAL hWaveHdr; +LPWAVEHDR lpWaveHdr; + +HWAVEOUT hWaveOut; + +WAVEOUTCAPS wavecaps; + +DWORD gSndBufSize; + +MMTIME mmstarttime; + +LPDIRECTSOUND pDS; +LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf; + +HINSTANCE hInstDS; + +qboolean SNDDMA_InitDirect (void); +qboolean SNDDMA_InitWav (void); + + +/* +================== +S_BlockSound +================== +*/ +void S_BlockSound (void) +{ + +// DirectSound takes care of blocking itself + if (snd_iswave) + { + snd_blocked++; + + if (snd_blocked == 1) + { + waveOutReset (hWaveOut); + } + } +} + + +/* +================== +S_UnblockSound +================== +*/ +void S_UnblockSound (void) +{ + +// DirectSound takes care of blocking itself + if (snd_iswave) + { + snd_blocked--; + } +} + + +/* +================== +FreeSound +================== +*/ +void FreeSound (void) +{ + int i; + + if (pDSBuf) + { + pDSBuf->lpVtbl->Stop(pDSBuf); + pDSBuf->lpVtbl->Release(pDSBuf); + } + +// only release primary buffer if it's not also the mixing buffer we just released + if (pDSPBuf && (pDSBuf != pDSPBuf)) + { + pDSPBuf->lpVtbl->Release(pDSPBuf); + } + + if (pDS) + { + pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_NORMAL); + pDS->lpVtbl->Release(pDS); + } + + if (hWaveOut) + { + waveOutReset (hWaveOut); + + if (lpWaveHdr) + { + for (i=0 ; i< WAV_BUFFERS ; i++) + waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)); + } + + waveOutClose (hWaveOut); + + if (hWaveHdr) + { + GlobalUnlock(hWaveHdr); + GlobalFree(hWaveHdr); + } + + if (hData) + { + GlobalUnlock(hData); + GlobalFree(hData); + } + + } + + pDS = NULL; + pDSBuf = NULL; + pDSPBuf = NULL; + hWaveOut = 0; + hData = 0; + hWaveHdr = 0; + lpData = NULL; + lpWaveHdr = NULL; + dsound_init = false; + wav_init = false; +} + + +/* +================== +SNDDMA_InitDirect + +Direct-Sound support +================== +*/ +sndinitstat SNDDMA_InitDirect (void) +{ + DSBUFFERDESC dsbuf; + DSBCAPS dsbcaps; + DWORD dwSize, dwWrite; + DSCAPS dscaps; + WAVEFORMATEX format, pformat; + HRESULT hresult; + int reps; + + memset ((void *)&sn, 0, sizeof (sn)); + + shm = &sn; + + shm->channels = 2; + shm->samplebits = 16; + + // jkrige - change sound speed + //shm->speed = 11025; + shm->speed = 22050; + // jkrige - change sound speed + + memset (&format, 0, sizeof(format)); + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = shm->channels; + format.wBitsPerSample = shm->samplebits; + format.nSamplesPerSec = shm->speed; + format.nBlockAlign = format.nChannels + *format.wBitsPerSample / 8; + format.cbSize = 0; + format.nAvgBytesPerSec = format.nSamplesPerSec + *format.nBlockAlign; + + if (!hInstDS) + { + hInstDS = LoadLibrary("dsound.dll"); + + if (hInstDS == NULL) + { + Con_SafePrintf ("Couldn't load dsound.dll\n"); + return SIS_FAILURE; + } + + pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate"); + + if (!pDirectSoundCreate) + { + Con_SafePrintf ("Couldn't get DS proc addr\n"); + return SIS_FAILURE; + } + } + + while ((hresult = iDirectSoundCreate(NULL, &pDS, NULL)) != DS_OK) + { + if (hresult != DSERR_ALLOCATED) + { + Con_SafePrintf ("DirectSound create failed\n"); + return SIS_FAILURE; + } + + if (MessageBox (NULL, + "The sound hardware is in use by another app.\n\n" + "Select Retry to try to start sound again or Cancel to run Quake with no sound.", + "Sound not available", + MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY) + { + Con_SafePrintf ("DirectSoundCreate failure\n" + " hardware already in use\n"); + return SIS_NOTAVAIL; + } + } + + dscaps.dwSize = sizeof(dscaps); + + if (DS_OK != pDS->lpVtbl->GetCaps (pDS, &dscaps)) + { + Con_SafePrintf ("Couldn't get DS caps\n"); + } + + if (dscaps.dwFlags & DSCAPS_EMULDRIVER) + { + Con_SafePrintf ("No DirectSound driver installed\n"); + FreeSound (); + return SIS_FAILURE; + } + + if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_EXCLUSIVE)) + { + Con_SafePrintf ("Set coop level failed\n"); + FreeSound (); + return SIS_FAILURE; + } + +// get access to the primary buffer, if possible, so we can set the +// sound hardware format + memset (&dsbuf, 0, sizeof(dsbuf)); + dsbuf.dwSize = sizeof(DSBUFFERDESC); + dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbuf.dwBufferBytes = 0; + dsbuf.lpwfxFormat = NULL; + + memset(&dsbcaps, 0, sizeof(dsbcaps)); + dsbcaps.dwSize = sizeof(dsbcaps); + primary_format_set = false; + + if (!COM_CheckParm ("-snoforceformat")) + { + if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL)) + { + pformat = format; + + if (DS_OK != pDSPBuf->lpVtbl->SetFormat (pDSPBuf, &pformat)) + { + if (snd_firsttime) + Con_SafePrintf ("Set primary sound buffer format: no\n"); + } + else + { + if (snd_firsttime) + Con_SafePrintf ("Set primary sound buffer format: yes\n"); + + primary_format_set = true; + } + } + } + + if (!primary_format_set || !COM_CheckParm ("-primarysound")) + { + // create the secondary buffer we'll actually work with + memset (&dsbuf, 0, sizeof(dsbuf)); + dsbuf.dwSize = sizeof(DSBUFFERDESC); + dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE; + dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE; + dsbuf.lpwfxFormat = &format; + + memset(&dsbcaps, 0, sizeof(dsbcaps)); + dsbcaps.dwSize = sizeof(dsbcaps); + + if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) + { + Con_SafePrintf ("DS:CreateSoundBuffer Failed"); + FreeSound (); + return SIS_FAILURE; + } + + shm->channels = format.nChannels; + shm->samplebits = format.wBitsPerSample; + shm->speed = format.nSamplesPerSec; + + if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps)) + { + Con_SafePrintf ("DS:GetCaps failed\n"); + FreeSound (); + return SIS_FAILURE; + } + + if (snd_firsttime) + Con_SafePrintf ("Using secondary sound buffer\n"); + } + else + { + if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_WRITEPRIMARY)) + { + Con_SafePrintf ("Set coop level failed\n"); + FreeSound (); + return SIS_FAILURE; + } + + if (DS_OK != pDSPBuf->lpVtbl->GetCaps (pDSPBuf, &dsbcaps)) + { + Con_Printf ("DS:GetCaps failed\n"); + return SIS_FAILURE; + } + + pDSBuf = pDSPBuf; + Con_SafePrintf ("Using primary sound buffer\n"); + } + + // Make sure mixer is active + pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); + + if (snd_firsttime) + Con_SafePrintf(" %d channel(s)\n" + " %d bits/sample\n" + " %d bytes/sec\n", + shm->channels, shm->samplebits, shm->speed); + + gSndBufSize = dsbcaps.dwBufferBytes; + +// initialize the buffer + reps = 0; + + while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &lpData, &dwSize, NULL, NULL, 0)) != DS_OK) + { + if (hresult != DSERR_BUFFERLOST) + { + Con_SafePrintf ("SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n"); + FreeSound (); + return SIS_FAILURE; + } + + if (++reps > 10000) + { + Con_SafePrintf ("SNDDMA_InitDirect: DS: couldn't restore buffer\n"); + FreeSound (); + return SIS_FAILURE; + } + + } + + memset(lpData, 0, dwSize); +// lpData[4] = lpData[5] = 0x7f; // force a pop for debugging + + pDSBuf->lpVtbl->Unlock(pDSBuf, lpData, dwSize, NULL, 0); + + /* we don't want anyone to access the buffer directly w/o locking it first. */ + lpData = NULL; + + pDSBuf->lpVtbl->Stop(pDSBuf); + pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite); + pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); + + shm->soundalive = true; + shm->splitbuffer = false; + shm->samples = gSndBufSize/(shm->samplebits/8); + shm->samplepos = 0; + shm->submission_chunk = 1; + shm->buffer = (unsigned char *) lpData; + sample16 = (shm->samplebits/8) - 1; + + dsound_init = true; + + return SIS_SUCCESS; +} + + +/* +================== +SNDDM_InitWav + +Crappy windows multimedia base +================== +*/ +qboolean SNDDMA_InitWav (void) +{ + WAVEFORMATEX format; + int i; + HRESULT hr; + + snd_sent = 0; + snd_completed = 0; + + shm = &sn; + + shm->channels = 2; + shm->samplebits = 16; + + // jkrige - change sound speed + //shm->speed = 11025; + shm->speed = 22050; + // jkrige - change sound speed + + memset (&format, 0, sizeof(format)); + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = shm->channels; + format.wBitsPerSample = shm->samplebits; + format.nSamplesPerSec = shm->speed; + format.nBlockAlign = format.nChannels + *format.wBitsPerSample / 8; + format.cbSize = 0; + format.nAvgBytesPerSec = format.nSamplesPerSec + *format.nBlockAlign; + + /* Open a waveform device for output using window callback. */ + while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, + &format, + 0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR) + { + if (hr != MMSYSERR_ALLOCATED) + { + Con_SafePrintf ("waveOutOpen failed\n"); + return false; + } + + if (MessageBox (NULL, + "The sound hardware is in use by another app.\n\n" + "Select Retry to try to start sound again or Cancel to run Quake with no sound.", + "Sound not available", + MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY) + { + Con_SafePrintf ("waveOutOpen failure;\n" + " hardware already in use\n"); + return false; + } + } + + /* + * Allocate and lock memory for the waveform data. The memory + * for waveform data must be globally allocated with + * GMEM_MOVEABLE and GMEM_SHARE flags. + + */ + gSndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE; + hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize); + if (!hData) + { + Con_SafePrintf ("Sound: Out of memory.\n"); + FreeSound (); + return false; + } + lpData = GlobalLock(hData); + if (!lpData) + { + Con_SafePrintf ("Sound: Failed to lock.\n"); + FreeSound (); + return false; + } + memset (lpData, 0, gSndBufSize); + + /* + * Allocate and lock memory for the header. This memory must + * also be globally allocated with GMEM_MOVEABLE and + * GMEM_SHARE flags. + */ + hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, + (DWORD) sizeof(WAVEHDR) * WAV_BUFFERS); + + if (hWaveHdr == NULL) + { + Con_SafePrintf ("Sound: Failed to Alloc header.\n"); + FreeSound (); + return false; + } + + lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr); + + if (lpWaveHdr == NULL) + { + Con_SafePrintf ("Sound: Failed to lock header.\n"); + FreeSound (); + return false; + } + + memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS); + + /* After allocation, set up and prepare headers. */ + for (i=0 ; isoundalive = true; + shm->splitbuffer = false; + shm->samples = gSndBufSize/(shm->samplebits/8); + shm->samplepos = 0; + shm->submission_chunk = 1; + shm->buffer = (unsigned char *) lpData; + sample16 = (shm->samplebits/8) - 1; + + wav_init = true; + + return true; +} + +/* +================== +SNDDMA_Init + +Try to find a sound device to mix for. +Returns false if nothing is found. +================== +*/ + +int SNDDMA_Init(void) +{ + sndinitstat stat; + + if (COM_CheckParm ("-wavonly")) + wavonly = true; + + dsound_init = wav_init = 0; + + stat = SIS_FAILURE; // assume DirectSound won't initialize + + /* Init DirectSound */ + if (!wavonly) + { + if (snd_firsttime || snd_isdirect) + { + stat = SNDDMA_InitDirect ();; + + if (stat == SIS_SUCCESS) + { + snd_isdirect = true; + + if (snd_firsttime) + Con_SafePrintf ("DirectSound initialized\n"); + } + else + { + snd_isdirect = false; + Con_SafePrintf ("DirectSound failed to init\n"); + } + } + } + +// if DirectSound didn't succeed in initializing, try to initialize +// waveOut sound, unless DirectSound failed because the hardware is +// already allocated (in which case the user has already chosen not +// to have sound) + if (!dsound_init && (stat != SIS_NOTAVAIL)) + { + if (snd_firsttime || snd_iswave) + { + + snd_iswave = SNDDMA_InitWav (); + + if (snd_iswave) + { + if (snd_firsttime) + Con_SafePrintf ("Wave sound initialized\n"); + } + else + { + Con_SafePrintf ("Wave sound failed to init\n"); + } + } + } + + snd_firsttime = false; + + if (!dsound_init && !wav_init) + { + if (snd_firsttime) + Con_SafePrintf ("No sound device initialized\n"); + + return 0; + } + + return 1; +} + +/* +============== +SNDDMA_GetDMAPos + +return the current sample position (in mono samples read) +inside the recirculating dma buffer, so the mixing code will know +how many sample are required to fill it up. +=============== +*/ +int SNDDMA_GetDMAPos(void) +{ + MMTIME mmtime; + int s; + DWORD dwWrite; + + if (dsound_init) + { + mmtime.wType = TIME_SAMPLES; + pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite); + s = mmtime.u.sample - mmstarttime.u.sample; + } + else if (wav_init) + { + s = snd_sent * WAV_BUFFER_SIZE; + } + + + s >>= sample16; + + s &= (shm->samples-1); + + return s; +} + +/* +============== +SNDDMA_Submit + +Send sound to device if buffer isn't really the dma buffer +=============== +*/ +void SNDDMA_Submit(void) +{ + LPWAVEHDR h; + int wResult; + + if (!wav_init) + return; + + // + // find which sound blocks have completed + // + while (1) + { + if ( snd_completed == snd_sent ) + { + Con_DPrintf ("Sound overrun\n"); + break; + } + + if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) ) + { + break; + } + + snd_completed++; // this buffer has been played + } + + // + // submit two new sound blocks + // + while (((snd_sent - snd_completed) >> sample16) < 4) + { + h = lpWaveHdr + ( snd_sent&WAV_MASK ); + + snd_sent++; + /* + * Now the data block can be sent to the output device. The + * waveOutWrite function returns immediately and waveform + * data is sent to the output device in the background. + */ + wResult = waveOutWrite(hWaveOut, h, sizeof(WAVEHDR)); + + if (wResult != MMSYSERR_NOERROR) + { + Con_SafePrintf ("Failed to write block to device\n"); + FreeSound (); + return; + } + } +} + +/* +============== +SNDDMA_Shutdown + +Reset the sound device for exiting +=============== +*/ +void SNDDMA_Shutdown(void) +{ + FreeSound (); +} + diff --git a/engine/code/sound.h b/engine/code/sound.h new file mode 100644 index 0000000..1ba08d3 --- /dev/null +++ b/engine/code/sound.h @@ -0,0 +1,177 @@ +/* +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. + +*/ +// 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 128 +#define MAX_DYNAMIC_CHANNELS 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 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/engine/code/spritegn.h b/engine/code/spritegn.h new file mode 100644 index 0000000..b192b54 --- /dev/null +++ b/engine/code/spritegn.h @@ -0,0 +1,110 @@ +/* +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. + +*/ +// +// 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/engine/code/sv_main.c b/engine/code/sv_main.c new file mode 100644 index 0000000..6fcd4ed --- /dev/null +++ b/engine/code/sv_main.c @@ -0,0 +1,1227 @@ +/* +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. + +*/ +// 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 + +// jkrige - configurable fps caps +// dedicated server FPS cap, default 20 (no need to run at higher speed). +// Note: listen servers (including SP) will run at a different cap, defined by cl_maxfps. +cvar_t sv_fps = {"sv_fps", "20", true}; +// jkrige - configurable fps caps + +//============================================================================ + +/* +=============== +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; + + Cvar_RegisterVariable (&sv_maxvelocity); + Cvar_RegisterVariable (&sv_gravity); + Cvar_RegisterVariable (&sv_friction); + Cvar_RegisterVariable (&sv_edgefriction); + Cvar_RegisterVariable (&sv_stopspeed); + Cvar_RegisterVariable (&sv_maxspeed); + Cvar_RegisterVariable (&sv_accelerate); + Cvar_RegisterVariable (&sv_idealpitchscale); + Cvar_RegisterVariable (&sv_aim); + Cvar_RegisterVariable (&sv_nostep); + + // jkrige - configurable fps caps + Cvar_RegisterVariable(&sv_fps); + // jkrige - configurable fps caps + + 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_numv.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]; + + MSG_WriteByte (&client->message, svc_print); + sprintf (message, "%c\nVERSION %4.2f SERVER (%i CRC)", 2, QUAKE_VERSION, pr_crc); + MSG_WriteString (&client->message,message); + + MSG_WriteByte (&client->message, svc_serverinfo); + MSG_WriteLong (&client->message, 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); + + for (s = sv.model_precache+1 ; *s ; s++) + MSG_WriteString (&client->message, *s); + MSG_WriteByte (&client->message, 0); + + for (s = sv.sound_precache+1 ; *s ; s++) + MSG_WriteString (&client->message, *s); + MSG_WriteByte (&client->message, 0); + +// send music + MSG_WriteByte (&client->message, svc_cdtrack); + MSG_WriteByte (&client->message, sv.edicts->v.sounds); + MSG_WriteByte (&client->message, sv.edicts->v.sounds); + + // jkrige - skybox + MSG_WriteByte (&client->message, svc_skybox); + MSG_WriteString (&client->message, sv.skybox); + // jkrige - skybox + +// 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 + +#ifdef IDGODS + client->privileged = IsID(&client->netconnection->addr); +#else + client->privileged = false; +#endif + + 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, sv.worldmodel); + 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]); + 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) +{ + fatbytes = (sv.worldmodel->numleafs+31)>>3; + Q_memset (fatpvs, 0, fatbytes); + SV_AddToFatPVS (org, sv.worldmodel->nodes); + return fatpvs; +} + +//============================================================================= + + +/* +============= +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); + +// send over all entities (excpet the client) that touch the pvs + ent = NEXT_EDICT(sv.edicts); + for (e=1 ; ev.effects == EF_NODRAW) + continue; +#endif + +// ignore if not touching a PV leaf + if (ent != clent) // clent is ALLWAYS sent + { +// ignore ents without visible models + if (!ent->v.modelindex || !pr_strings[ent->v.model]) + continue; + + 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 + } + + if (msg->maxsize - msg->cursize < 16) + { + Con_Printf ("packet overflow\n"); + return; + } + +// 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_NOLERP; // 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; + + 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); + 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]); + } +} + +/* +============= +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; +#ifndef QUAKE2 + eval_t *val; +#endif + +// +// 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 +#ifdef QUAKE2 + items = (int)ent->v.items | ((int)ent->v.items2 << 23); +#else + 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); +#endif + + 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; + +// send the data + + MSG_WriteByte (msg, svc_clientdata); + MSG_WriteShort (msg, bits); + + 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<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"); + } + else + { + svent->baseline.colormap = 0; + svent->baseline.modelindex = + SV_ModelIndex(pr_strings + svent->v.model); + } + + // + // add to the message + // + MSG_WriteByte (&sv.signon,svc_spawnbaseline); + MSG_WriteShort (&sv.signon,entnum); + + MSG_WriteByte (&sv.signon, svent->baseline.modelindex); + MSG_WriteByte (&sv.signon, svent->baseline.frame); + 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]); + } + } +} + + +/* +================ +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) +#ifdef QUAKE2 + Cbuf_InsertText ("reconnect\n"); +#else + Cmd_ExecuteString ("reconnect\n", src_command); +#endif +} + + +/* +================ +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; + +#ifdef QUAKE2 +void SV_SpawnServer (char *server, char *startspot) +#else +void SV_SpawnServer (char *server) +#endif +{ + 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); +#ifdef QUAKE2 + if (startspot) + strcpy(sv.startspot, startspot); +#endif + +// load progs to get entity field count + PR_LoadProgs (); + +// allocate server memory + sv.max_edicts = MAX_EDICTS; + + 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 ; inumvertexes == -1) + { + Con_Printf ("Couldn't spawn server %s\n", sv.modelname); + sv.active = false; + //total_loading_size = 0; + //loading_stage = 0; + return; + } + // jkrige - bsp version crash + + sv.models[1] = sv.worldmodel; + +// +// clear world interaction links +// + SV_ClearWorld (); + + sv.sound_precache[0] = pr_strings; + + sv.model_precache[0] = pr_strings; + sv.model_precache[1] = sv.modelname; + for (i=1 ; 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; +#ifdef QUAKE2 + pr_global_struct->startspot = sv.startspot - pr_strings; +#endif + +// 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 (); + +// 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/engine/code/sv_move.c b/engine/code/sv_move.c new file mode 100644 index 0000000..a0078b9 --- /dev/null +++ b/engine/code/sv_move.c @@ -0,0 +1,427 @@ +/* +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. + +*/ +// 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; +#ifdef QUAKE2 + edict_t *enemy; +#endif + + 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 +#ifdef QUAKE2 + enemy = PROG_TO_EDICT(ent->v.enemy); + if (enemy != sv.edicts && SV_CloseEnough (ent, enemy, dist) ) +#else + if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) ) +#endif + return; + +// bump around... + if ( (rand()&3)==1 || + !SV_StepDirection (ent, ent->v.ideal_yaw, dist)) + { + SV_NewChaseDir (ent, goal, dist); + } +} + diff --git a/engine/code/sv_phys.c b/engine/code/sv_phys.c new file mode 100644 index 0000000..647276d --- /dev/null +++ b/engine/code/sv_phys.c @@ -0,0 +1,2035 @@ +/* +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. + +*/ +// 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"}; + +#ifdef QUAKE2 +static vec3_t vec_origin = {0.0, 0.0, 0.0}; +#endif + +#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 +#ifdef QUAKE2 + || check->v.movetype == MOVETYPE_FOLLOW +#endif + || 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; + float wishspeed; // jkrige - SV_MAXVELOCITY fix + +// +// 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; + } + + // jkrige - SV_MAXVELOCITY fix + /* + 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; + */ + // jkrige - SV_MAXVELOCITY fix + } + + // jkrige - SV_MAXVELOCITY fix + wishspeed = Length(ent->v.velocity); + if (wishspeed > sv_maxvelocity.value) + { + VectorScale (ent->v.velocity, sv_maxvelocity.value/wishspeed, ent->v.velocity); + wishspeed = sv_maxvelocity.value; + } + // jkrige - SV_MAXVELOCITY fix +} + +/* +============= +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; + + 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. + 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); + 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; + +#ifdef QUAKE2 + if (ent->v.gravity) + ent_gravity = ent->v.gravity; + else + ent_gravity = 1.0; +#else + eval_t *val; + + val = GetEdictFieldValue(ent, "gravity"); + if (val && val->_float) + ent_gravity = val->_float; + else + ent_gravity = 1.0; +#endif + 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[MAX_EDICTS]; + vec3_t moved_from[MAX_EDICTS]; + + float solid_backup; // jkrige - MOVETYPE_PUSH fix + + 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); + + +// 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 +#ifdef QUAKE2 + || check->v.movetype == MOVETYPE_FOLLOW +#endif + || 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++; + + + // jkrige - MOVETYPE_PUSH fix + // 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); + + solid_backup = pusher->v.solid; + if ( solid_backup == SOLID_BSP // everything that blocks: bsp models = map brushes = doors, plats, etc. + || solid_backup == SOLID_BBOX // normally boxes + || solid_backup == SOLID_SLIDEBOX ) // normally monsters + { + // try moving the contacted entity + pusher->v.solid = SOLID_NOT; + SV_PushEntity (check, move); + pusher->v.solid = solid_backup; + + // if it is still inside the pusher, block + block = SV_TestEntityPosition (check); + } + else + { + block = NULL; + } + // jkrige - MOVETYPE_PUSH fix + + + 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); + } + return; + } + } + + +} + +#ifdef QUAKE2 +/* +============ +SV_PushRotate + +============ +*/ +void SV_PushRotate (edict_t *pusher, float movetime) +{ + int i, e; + edict_t *check, *block; + vec3_t move, a, amove; + vec3_t entorig, pushorig; + int num_moved; + edict_t *moved_edict[MAX_EDICTS]; + vec3_t moved_from[MAX_EDICTS]; + vec3_t org, org2; + vec3_t forward, right, up; + + if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2]) + { + pusher->v.ltime += movetime; + return; + } + + for (i=0 ; i<3 ; i++) + amove[i] = pusher->v.avelocity[i] * movetime; + + VectorSubtract (vec3_origin, amove, a); + AngleVectors (a, forward, right, up); + + VectorCopy (pusher->v.angles, pushorig); + +// move the pusher to it's final position + + VectorAdd (pusher->v.angles, amove, pusher->v.angles); + pusher->v.ltime += movetime; + SV_LinkEdict (pusher, false); + + +// 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_FOLLOW + || 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] >= pusher->v.absmax[0] + || check->v.absmin[1] >= pusher->v.absmax[1] + || check->v.absmin[2] >= pusher->v.absmax[2] + || check->v.absmax[0] <= pusher->v.absmin[0] + || check->v.absmax[1] <= pusher->v.absmin[1] + || check->v.absmax[2] <= pusher->v.absmin[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++; + + // calculate destination position + VectorSubtract (check->v.origin, pusher->v.origin, org); + org2[0] = DotProduct (org, forward); + org2[1] = -DotProduct (org, right); + org2[2] = DotProduct (org, up); + VectorSubtract (org2, org, move); + + // 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.angles); + 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); + VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); + SV_LinkEdict (moved_edict[i], false); + } + return; + } + else + { + VectorAdd (check->v.angles, amove, check->v.angles); + } + } + + +} +#endif + +// jkrige - rotating bmodels (ported from Hexen II) +#if 0 +void SV_PushRotate (edict_t *pusher, float movetime) +{ + int i, e, t; + edict_t *check, *block; + vec3_t move, a, amove, mins, maxs, move2, move3, testmove; +// vec3_t amove_norm; + vec3_t entorig, pushorig, pushorigangles; + int num_moved; + edict_t *moved_edict[MAX_EDICTS]; + vec3_t moved_from[MAX_EDICTS]; + vec3_t org, org2, check_center; + vec3_t forward, right, up; + edict_t *ground; + edict_t *master; + edict_t *slave; + int slaves_moved; + qboolean moveit; +// float turn_away, amove_mag; + +#if 0 + Con_DPrintf("SV_PushRotate entity %i (time=%f)\n", NUM_FOR_EDICT(pusher), movetime); + Con_DPrintf("%f %f %f (avelocity)\n", pusher->v.avelocity[0], pusher->v.avelocity[1], pusher->v.avelocity[2]); + Con_DPrintf("%f %f %f\n", pusher->v.angles[0], pusher->v.angles[1], pusher->v.angles[2]); +#endif + + for (i=0 ; i<3 ; i++) + { + amove[i] = pusher->v.avelocity[i] * movetime; + move[i] = pusher->v.velocity[i] * movetime; + mins[i] = pusher->v.absmin[i] + move[i]; + maxs[i] = pusher->v.absmax[i] + move[i]; + } + + VectorSubtract (vec3_origin, amove, a); + AngleVectors (a, forward, right, up); + + VectorCopy (pusher->v.origin, pushorig); + VectorCopy (pusher->v.angles, pushorigangles); + + // move the pusher to it's final position + VectorAdd (pusher->v.origin, move, pusher->v.origin); + VectorAdd (pusher->v.angles, amove, pusher->v.angles); + + pusher->v.ltime += movetime; + SV_LinkEdict (pusher, false); + + master = pusher; + slaves_moved = 0; +/* while (master->v.aiment) + { + slave = PROG_TO_EDICT(master->v.aiment); + + //Con_DPrintf("%f %f %f slave entity %i\n", slave->v.angles[0], slave->v.angles[1], slave->v.angles[2], NUM_FOR_EDICT(slave)); + + slaves_moved++; + VectorCopy (slave->v.angles, moved_from[MAX_EDICTS - slaves_moved]); + moved_edict[MAX_EDICTS - slaves_moved] = slave; + + if (slave->v.movedir[PITCH]) + slave->v.angles[PITCH] = master->v.angles[PITCH]; + else + slave->v.angles[PITCH] += slave->v.avelocity[PITCH] * movetime; + + if (slave->v.movedir[YAW]) + slave->v.angles[YAW] = master->v.angles[YAW]; + else + slave->v.angles[YAW] += slave->v.avelocity[YAW] * movetime; + + if (slave->v.movedir[ROLL]) + slave->v.angles[ROLL] = master->v.angles[ROLL]; + else + slave->v.angles[ROLL] += slave->v.avelocity[ROLL] * movetime; + + slave->v.ltime = master->v.ltime; + SV_LinkEdict (slave, false); + + master = slave; + } +*/ + + // 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_FOLLOW // jkrige + || check->v.movetype == MOVETYPE_NOCLIP) + continue; + + // if the entity is standing on the pusher, it will definitely be moved + moveit = false; + ground = PROG_TO_EDICT(check->v.groundentity); + if ((int)check->v.flags & FL_ONGROUND) + { + if (ground == pusher) + { + moveit = true; + } + else + { + for (i=0; iv.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] ) + { + for (i=0; iv.absmin[0] >= slave->v.absmax[0] + || check->v.absmin[1] >= slave->v.absmax[1] + || check->v.absmin[2] >= slave->v.absmax[2] + || check->v.absmax[0] <= slave->v.absmin[0] + || check->v.absmax[1] <= slave->v.absmin[1] + || check->v.absmax[2] <= slave->v.absmin[2] ) + continue; + } + if (i == slaves_moved) + 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++; + + // put check in first move spot + VectorAdd (check->v.origin, move, check->v.origin); + // Use center of model, like in QUAKE!!!! + // Our origins are on the bottom!!! + for (i=0 ; i<3 ; i++) + check_center[i] = (check->v.absmin[i] + check->v.absmax[i])/2; + // calculate destination position + VectorSubtract (check_center, pusher->v.origin, org); + // put check back + VectorSubtract (check->v.origin, move, check->v.origin); + org2[0] = DotProduct (org, forward); + org2[1] = -DotProduct (org, right); + org2[2] = DotProduct (org, up); + VectorSubtract (org2, org, move2); + + //Con_DPrintf("%f %f %f (move2)\n", move2[0], move2[1], move2[2]); + + // VectorAdd (check->v.origin, move2, check->v.origin); + + // Add all moves together + VectorAdd(move,move2,move3); + + // Find the angle of rotation as compared to vector from pusher + // origin to check center + // turn_away = DotProduct(org,a); + + // try moving the contacted entity + for (t = 0; t < 13; t++) + { + switch (t) + { + case 0: + //try x, y and z + VectorCopy(move3,testmove); + break; + case 1: + //Try xy only + VectorSubtract(check->v.origin,testmove,check->v.origin); + testmove[0]=move3[0]; + testmove[1]=move3[1]; + testmove[2]=0; + break; + case 2: + //Try z only + VectorSubtract(check->v.origin,testmove,check->v.origin); + testmove[0]=0; + testmove[1]=0; + testmove[2]=move3[2]; + break; + case 3: + //Try none + VectorSubtract(check->v.origin,testmove,check->v.origin); + testmove[0]=0; + testmove[1]=0; + testmove[2]=0; + break; + case 4: + //Try xy in opposite dir + testmove[0]=move3[0]*-1; + testmove[1]=move3[1]*-1; + testmove[2]=move3[2]; + break; + case 5: + //Try z in opposite dir + VectorSubtract(check->v.origin,testmove,check->v.origin); + testmove[0]=move3[0]; + testmove[1]=move3[1]; + testmove[2]=move3[2]*-1; + break; + case 6: + //Try xyz in opposite dir + VectorSubtract(check->v.origin,testmove,check->v.origin); + testmove[0]=move3[0]*-1; + testmove[1]=move3[1]*-1; + testmove[2]=move3[2]*-1; + break; + case 7: + //Try move3 times 2 + VectorSubtract(check->v.origin,testmove,check->v.origin); + VectorScale(move3,2,testmove); + break; + case 8: + //Try normalized org + VectorSubtract(check->v.origin,testmove,check->v.origin); + + // VectorCopy(amove,amove_norm); + // amove_mag=VectorNormalize(amove_norm); + // //VectorNormalize(org); + // VectorScale(org,amove_mag,org); + + // VectorNormalize(org); + VectorScale(org,movetime,org);//movetime*20? + VectorCopy(org,testmove); + break; + case 9: + //Try normalized org z * 3 only + VectorSubtract(check->v.origin,testmove,check->v.origin); + testmove[0]=0; + testmove[1]=0; + testmove[2]=org[2]*3;//was: +org[2]*(fabs(org[1])+fabs(org[2])); + break; + case 10: + //Try normalized org xy * 2 only + VectorSubtract(check->v.origin,testmove,check->v.origin); + testmove[0]=org[0]*2;//was: +org[0]*fabs(org[2]); + testmove[1]=org[1]*2;//was: +org[1]*fabs(org[2]); + testmove[2]=0; + break; + case 11: + //Try xy in opposite org dir + VectorSubtract(check->v.origin,testmove,check->v.origin); + testmove[0]=org[0]*-2; + testmove[1]=org[1]*-2; + testmove[2]=org[2]; + break; + case 12: + //Try z in opposite dir + VectorSubtract(check->v.origin,testmove,check->v.origin); + testmove[0]=org[0]; + testmove[1]=org[1]; + testmove[2]=org[2]*-3; + break; + } + + if (t != 3) + { + //THIS IS VERY BAD BAD HACK... + pusher->v.solid = SOLID_NOT; + SV_PushEntity (check, move3); + //@@TODO: do we ever want to do anybody's angles? maybe just yaw??? + // if (!((int)check->v.flags & (FL_CLIENT | FL_MONSTER))) + // VectorAdd (check->v.angles, amove, check->v.angles); + check->v.angles[YAW] += amove[YAW]; + pusher->v.solid = SOLID_BSP; + } + // if it is still inside the pusher, block + block = SV_TestEntityPosition (check); + if (!block) + break; + } + + //Con_DPrintf("t: %i\n",t); + + // if (turn_away > 0) + // { + if (block) + { // fail the move + //Con_DPrintf("Check blocked\n"); + 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); + VectorCopy (pushorigangles, pusher->v.angles); + SV_LinkEdict (pusher, false); + pusher->v.ltime -= movetime; + + for (i=0; iv.angles); + SV_LinkEdict (slave, false); + slave->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); + //@@TODO:: see above + // if (!((int)moved_edict[i]->v.flags & (FL_CLIENT | FL_MONSTER))) + // VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); + moved_edict[i]->v.angles[YAW] -= amove[YAW]; + + SV_LinkEdict (moved_edict[i], false); + } + return; + } + // } + // else if (block) // undo last move + // VectorCopy (entorig, check->v.origin); + } + +#if 0 + Con_DPrintf("result:\n"); + Con_DPrintf("%f %f %f\n", pusher->v.angles[0], pusher->v.angles[1], pusher->v.angles[2]); + for (i=0; iv.angles[0], slave->v.angles[1], slave->v.angles[2], NUM_FOR_EDICT(slave)); + } + Con_DPrintf("\n"); +#endif +} +#endif +// jkrige - rotating bmodels (ported from Hexen II) + +/* +================ +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) + { + // jkrige - rotating bmodels + /* +#ifdef QUAKE2 + if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2]) + SV_PushRotate (ent, movetime); + else +#endif + SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked + */ + //if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2]) + // SV_PushRotate (ent, movetime); + //else + SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked + // jkrige - rotating bmodels + } + + 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; +#ifdef QUAKE2 + int truecont; +#endif + + 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) + { +#ifdef QUAKE2 + truecont = SV_TruePointContents (point); +#endif + 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; + } +#ifdef QUAKE2 + if (truecont <= CONTENTS_CURRENT_0 && truecont >= CONTENTS_CURRENT_DOWN) + { + static vec3_t current_table[] = + { + {1, 0, 0}, + {0, 1, 0}, + {-1, 0, 0}, + {0, -1, 0}, + {0, 0, 1}, + {0, 0, -1} + }; + + VectorMA (ent->v.basevelocity, 150.0*ent->v.waterlevel/3.0, current_table[CONTENTS_CURRENT_0 - truecont], ent->v.basevelocity); + } +#endif + } + + 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); +#ifdef QUAKE2 + VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); +#endif + SV_WalkMove (ent); + +#ifdef QUAKE2 + VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); +#endif + 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); +} + +#ifdef QUAKE2 +/* +============= +SV_Physics_Follow + +Entities that are "stuck" to another entity +============= +*/ +void SV_Physics_Follow (edict_t *ent) +{ +// regular thinking + SV_RunThink (ent); + VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin); + SV_LinkEdict (ent, true); +} +#endif + +/* +============= +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; +#ifdef QUAKE2 + vec3_t point; + + point[0] = ent->v.origin[0]; + point[1] = ent->v.origin[1]; + point[2] = ent->v.origin[2] + ent->v.mins[2] + 1; + cont = SV_PointContents (point); +#else + cont = SV_PointContents (ent->v.origin); +#endif + 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; +#ifdef QUAKE2 + edict_t *groundentity; + + groundentity = PROG_TO_EDICT(ent->v.groundentity); + if ((int)groundentity->v.flags & FL_CONVEYOR) + VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity); + else + VectorCopy(vec_origin, ent->v.basevelocity); + SV_CheckWater (ent); +#endif + // regular thinking + if (!SV_RunThink (ent)) + return; + +#ifdef QUAKE2 + if (ent->v.velocity[2] > 0) + ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; + + if ( ((int)ent->v.flags & FL_ONGROUND) ) +//@@ + if (VectorCompare(ent->v.basevelocity, vec_origin)) + return; + + SV_CheckVelocity (ent); + +// add gravity + if (! ((int)ent->v.flags & FL_ONGROUND) + && ent->v.movetype != MOVETYPE_FLY + && ent->v.movetype != MOVETYPE_BOUNCEMISSILE + && ent->v.movetype != MOVETYPE_FLYMISSILE) + SV_AddGravity (ent); + +#else +// 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); +#endif + +// move angles + VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); + +// move origin +#ifdef QUAKE2 + VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); +#endif + VectorScale (ent->v.velocity, host_frametime, move); + trace = SV_PushEntity (ent, move); +#ifdef QUAKE2 + VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); +#endif + if (trace.fraction == 1) + return; + if (ent->free) + return; + + if (ent->v.movetype == MOVETYPE_BOUNCE) + backoff = 1.5; +#ifdef QUAKE2 + else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE) + backoff = 2.0; +#endif + 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) + { +#ifdef QUAKE2 + if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE)) +#else + if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE) +#endif + { + 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. +============= +*/ +#ifdef QUAKE2 +void SV_Physics_Step (edict_t *ent) +{ + qboolean wasonground; + qboolean inwater; + qboolean hitsound = false; + float *vel; + float speed, newspeed, control; + float friction; + edict_t *groundentity; + + groundentity = PROG_TO_EDICT(ent->v.groundentity); + if ((int)groundentity->v.flags & FL_CONVEYOR) + VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity); + else + VectorCopy(vec_origin, ent->v.basevelocity); +//@@ + pr_global_struct->time = sv.time; + pr_global_struct->self = EDICT_TO_PROG(ent); + PF_WaterMove(); + + SV_CheckVelocity (ent); + + wasonground = (int)ent->v.flags & FL_ONGROUND; +// ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; + + // add gravity except: + // flying monsters + // swimming monsters who are in the water + inwater = SV_CheckWater(ent); + if (! wasonground) + if (!((int)ent->v.flags & FL_FLY)) + if (!(((int)ent->v.flags & FL_SWIM) && (ent->v.waterlevel > 0))) + { + if (ent->v.velocity[2] < sv_gravity.value*-0.1) + hitsound = true; + if (!inwater) + SV_AddGravity (ent); + } + + if (!VectorCompare(ent->v.velocity, vec_origin) || !VectorCompare(ent->v.basevelocity, vec_origin)) + { + ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; + // apply friction + // let dead monsters who aren't completely onground slide + if (wasonground) + if (!(ent->v.health <= 0.0 && !SV_CheckBottom(ent))) + { + vel = ent->v.velocity; + speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); + if (speed) + { + friction = sv_friction.value; + + 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; + } + } + + VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); + SV_FlyMove (ent, host_frametime, NULL); + VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); + + // determine if it's on solid ground at all + { + vec3_t mins, maxs, point; + int x, y; + + VectorAdd (ent->v.origin, ent->v.mins, mins); + VectorAdd (ent->v.origin, ent->v.maxs, maxs); + + point[2] = mins[2] - 1; + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + point[0] = x ? maxs[0] : mins[0]; + point[1] = y ? maxs[1] : mins[1]; + if (SV_PointContents (point) == CONTENTS_SOLID) + { + ent->v.flags = (int)ent->v.flags | FL_ONGROUND; + break; + } + } + + } + + SV_LinkEdict (ent, true); + + if ((int)ent->v.flags & FL_ONGROUND) + if (!wasonground) + if (hitsound) + SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); + } + +// regular thinking + SV_RunThink (ent); + SV_CheckWaterTransition (ent); +} +#else +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); +} +#endif + +//============================================================================ + +/* +================ +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); +#ifdef QUAKE2 + else if (ent->v.movetype == MOVETYPE_FOLLOW) + SV_Physics_Follow (ent); +#endif + 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 +#ifdef QUAKE2 + || ent->v.movetype == MOVETYPE_BOUNCEMISSILE +#endif + || 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; +} + + +#ifdef QUAKE2 +trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore) +{ + edict_t tempent, *tent; + trace_t trace; + vec3_t move; + vec3_t end; + double save_frametime; +// extern particle_t *active_particles, *free_particles; +// particle_t *p; + + + save_frametime = host_frametime; + host_frametime = 0.05; + + memcpy(&tempent, ent, sizeof(edict_t)); + tent = &tempent; + + while (1) + { + SV_CheckVelocity (tent); + SV_AddGravity (tent); + VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles); + VectorScale (tent->v.velocity, host_frametime, move); + VectorAdd (tent->v.origin, move, end); + trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent); + VectorCopy (trace.endpos, tent->v.origin); + +// p = free_particles; +// if (p) +// { +// free_particles = p->next; +// p->next = active_particles; +// active_particles = p; +// +// p->die = 256; +// p->color = 15; +// p->type = pt_static; +// VectorCopy (vec3_origin, p->vel); +// VectorCopy (tent->v.origin, p->org); +// } + + if (trace.ent) + if (trace.ent != ignore) + break; + } +// p->color = 224; + host_frametime = save_frametime; + return trace; +} +#endif diff --git a/engine/code/sv_user.c b/engine/code/sv_user.c new file mode 100644 index 0000000..203e6bf --- /dev/null +++ b/engine/code/sv_user.c @@ -0,0 +1,635 @@ +/* +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. + +*/ +// 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"}; + + +/* +=============== +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; + + // jkrige - slook cvar + if(!cl_slook.value) + return; + // jkrige - slook cvar + + 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"}; +#if 0 +void SV_Accelerate (vec3_t wishvel) +{ + int i; + float addspeed, accelspeed; + vec3_t pushvec; + + if (wishspeed == 0) + return; + + VectorSubtract (wishvel, velocity, pushvec); + addspeed = VectorNormalize (pushvec); + + accelspeed = sv_accelerate.value*host_frametime*addspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + velocity[i] += accelspeed*pushvec[i]; +} +#endif +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_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 +// + if ( (sv_player->v.waterlevel >= 2) + && (sv_player->v.movetype != MOVETYPE_NOCLIP) ) + { + SV_WaterMove (); + return; + } + + SV_AirMove (); +} + + +/* +=================== +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++) + angle[i] = MSG_ReadAngle (); + + 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; + +#ifdef QUAKE2 +// read light level + host_client->edict->v.light_level = MSG_ReadByte (); +#endif +} + +/* +=================== +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/engine/code/sys.h b/engine/code/sys.h new file mode 100644 index 0000000..0a3950d --- /dev/null +++ b/engine/code/sys.h @@ -0,0 +1,89 @@ +/* +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. + +*/ +// 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); + +// jkrige - pk3 file support +// jkrige - increased max number of file handles +//#define MAX_HANDLES 10 +#define MAX_HANDLES 25 +// jkrige - increased max number of file handles +extern FILE *sys_handles[MAX_HANDLES]; +extern unzFile sys_zhandles[MAX_HANDLES]; +//long Sys_FileTell (int handle); +int Sys_FFileRead (FILE *f, void *dest, int count); +void Sys_FFileClose (FILE *f); +int findhandle (qboolean zip); +// jkrige - pk3 file support + +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 + +// Pa3PyX: Same as above, but time in milliseconds can be specified +#define Sys_LongSleep(time_len) (Sleep(time_len)) + +void Sys_SendKeyEvents (void); +// Perform Key_Event () callbacks until the input que is empty + +// jkrige - assembly removal +//void Sys_LowFPPrecision (void); +//void Sys_HighFPPrecision (void); +//void Sys_SetFPCW (void); +// jkrige - assembly removal diff --git a/engine/code/sys_win.c b/engine/code/sys_win.c new file mode 100644 index 0000000..96b621b --- /dev/null +++ b/engine/code/sys_win.c @@ -0,0 +1,1007 @@ +/* +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. + +*/ +// sys_win.c -- Win32 system interface code + +#include "quakedef.h" +#include "winquake.h" +#include "errno.h" +#include "resource.h" +#include "conproc.h" + +//#define MINIMUM_WIN_MEMORY 0x0880000 +//#define MAXIMUM_WIN_MEMORY 0x1000000 +#define MINIMUM_WIN_MEMORY 0x2000000 // jkrige - memory increase: 33 554 432 bytes (32MB) +#define MAXIMUM_WIN_MEMORY 0x4000000 // jkrige - memory increase: 67 108 864 bytes (64MB) + +#define CONSOLE_ERROR_TIMEOUT 60.0 // # of seconds to wait on Sys_Error running + // dedicated before exiting +#define PAUSE_SLEEP 50 // sleep time on pause or minimization +#define NOT_FOCUS_SLEEP 20 // sleep time when not focus + +int starttime; +qboolean ActiveApp, Minimized; +//qboolean WinNT; // jkrige - remove windows version check + +static double pfreq; +static double curtime = 0.0; +static double lastcurtime = 0.0; +static int lowshift; +qboolean isDedicated; +static qboolean sc_return_on_enter = false; +HANDLE hinput, houtput; + +static char *tracking_tag = "Clams & Mooses"; + +static HANDLE tevent; +static HANDLE hFile; +static HANDLE heventParent; +static HANDLE heventChild; + +void Sys_InitFloatTime(void); + +// jkrige - assembly removal +//void Sys_PushFPCW_SetHigh (void); +//void Sys_PopFPCW (void); +//void MaskExceptions(void); +// jkrige - assembly removal + +volatile int sys_checksum; + + +/* +================ +Sys_PageIn +================ +*/ +void Sys_PageIn (void *ptr, int size) +{ + byte *x; + int j, m, n; + +// touch all the memory to make sure it's there. The 16-page skip is to +// keep Win 95 from thinking we're trying to page ourselves in (we are +// doing that, of course, but there's no reason we shouldn't) + x = (byte *)ptr; + + for (n=0 ; n<4 ; n++) + { + for (m=0 ; m<(size - 16 * 0x1000) ; m += 4) + { + sys_checksum += *(int *)&x[m]; + sys_checksum += *(int *)&x[m + 16 * 0x1000]; + } + } +} + + +/* +=============================================================================== + +FILE IO + +=============================================================================== +*/ + +// jkrige - pk3 file support +//#define MAX_HANDLES 10 +unzFile sys_zhandles[MAX_HANDLES]; +// jkrige - pk3 file support + +FILE *sys_handles[MAX_HANDLES]; + +// jkrige - pk3 file support +/*int findhandle (void) +{ + int i; + + for (i=1 ; i 2000000.0)) + { + lowshift++; + lowpart >>= 1; + lowpart |= (highpart & 1) << 31; + highpart >>= 1; + } + + pfreq = 1.0 / (double)lowpart; + + Sys_InitFloatTime (); + + // jkrige - remove windows version check - begin + /* + vinfo.dwOSVersionInfoSize = sizeof(vinfo); + + if (!GetVersionEx (&vinfo)) + Sys_Error ("Couldn't get OS info"); + + if ((vinfo.dwMajorVersion < 4) || + (vinfo.dwPlatformId == VER_PLATFORM_WIN32s)) + { + Sys_Error ("WinQuake requires at least Win95 or NT 4.0"); + } + + if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) + WinNT = true; + else + WinNT = false; + */ + // jkrige - remove windows version check - end +} + + +void Sys_Error (char *error, ...) +{ + va_list argptr; + char text[1024], text2[1024]; + char *text3 = "Press Enter to exit\n"; + char *text4 = "***********************************\n"; + char *text5 = "\n"; + DWORD dummy; + double starttime; + static int in_sys_error0 = 0; + static int in_sys_error1 = 0; + static int in_sys_error2 = 0; + static int in_sys_error3 = 0; + + if (!in_sys_error3) + { + in_sys_error3 = 1; + VID_ForceUnlockedAndReturnState (); + } + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + if (isDedicated) + { + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + sprintf (text2, "ERROR: %s\n", text); + WriteFile (houtput, text5, strlen (text5), &dummy, NULL); + WriteFile (houtput, text4, strlen (text4), &dummy, NULL); + WriteFile (houtput, text2, strlen (text2), &dummy, NULL); + WriteFile (houtput, text3, strlen (text3), &dummy, NULL); + WriteFile (houtput, text4, strlen (text4), &dummy, NULL); + + + starttime = Sys_FloatTime (); + sc_return_on_enter = true; // so Enter will get us out of here + + while (!Sys_ConsoleInput () && + ((Sys_FloatTime () - starttime) < CONSOLE_ERROR_TIMEOUT)) + { + } + } + else + { + // switch to windowed so the message box is visible, unless we already + // tried that and failed + if (!in_sys_error0) + { + in_sys_error0 = 1; + VID_SetDefaultMode (); + MessageBox(NULL, text, "Quake Error", + MB_OK | MB_SETFOREGROUND | MB_ICONSTOP); + } + else + { + MessageBox(NULL, text, "Double Quake Error", + MB_OK | MB_SETFOREGROUND | MB_ICONSTOP); + } + } + + if (!in_sys_error1) + { + in_sys_error1 = 1; + Host_Shutdown (); + } + +// shut down QHOST hooks if necessary + if (!in_sys_error2) + { + in_sys_error2 = 1; + DeinitConProc (); + } + + exit (1); +} + +void Sys_Printf (char *fmt, ...) +{ + va_list argptr; + char text[1024]; + DWORD dummy; + + if (isDedicated) + { + va_start (argptr,fmt); + vsprintf (text, fmt, argptr); + va_end (argptr); + + WriteFile(houtput, text, strlen (text), &dummy, NULL); + } +} + +void Sys_Quit (void) +{ + + VID_ForceUnlockedAndReturnState (); + + Host_Shutdown(); + + if (tevent) + CloseHandle (tevent); + + if (isDedicated) + FreeConsole (); + +// shut down QHOST hooks if necessary + DeinitConProc (); + + exit (0); +} + + +/* +================ +Sys_FloatTime +================ +*/ +double Sys_FloatTime (void) +{ + static int sametimecount; + static unsigned int oldtime; + static int first = 1; + LARGE_INTEGER PerformanceCount; + unsigned int temp, t2; + double time; + + // jkrige - assembly removal + //Sys_PushFPCW_SetHigh (); + // jkrige - assembly removal + + QueryPerformanceCounter (&PerformanceCount); + + temp = ((unsigned int)PerformanceCount.LowPart >> lowshift) | + ((unsigned int)PerformanceCount.HighPart << (32 - lowshift)); + + if (first) + { + oldtime = temp; + first = 0; + } + else + { + // check for turnover or backward time + if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000)) + { + oldtime = temp; // so we can't get stuck + } + else + { + t2 = temp - oldtime; + + time = (double)t2 * pfreq; + oldtime = temp; + + curtime += time; + + if (curtime == lastcurtime) + { + sametimecount++; + + if (sametimecount > 100000) + { + curtime += 1.0; + sametimecount = 0; + } + } + else + { + sametimecount = 0; + } + + lastcurtime = curtime; + } + } + + // jkrige - assembly removal + //Sys_PopFPCW (); + // jkrige - assembly removal + + return curtime; +} + + +/* +================ +Sys_InitFloatTime +================ +*/ +void Sys_InitFloatTime (void) +{ + int j; + + Sys_FloatTime (); + + j = COM_CheckParm("-starttime"); + + if (j) + { + curtime = (double) (Q_atof(com_argv[j+1])); + } + else + { + curtime = 0.0; + } + + lastcurtime = curtime; +} + + +char *Sys_ConsoleInput (void) +{ + static char text[256]; + static int len; + INPUT_RECORD recs[1024]; + int count; + int i, dummy; + int ch, numread, numevents; + + if (!isDedicated) + return NULL; + + + for ( ;; ) + { + if (!GetNumberOfConsoleInputEvents (hinput, &numevents)) + Sys_Error ("Error getting # of console events"); + + if (numevents <= 0) + break; + + if (!ReadConsoleInput(hinput, recs, 1, &numread)) + Sys_Error ("Error reading console input"); + + if (numread != 1) + Sys_Error ("Couldn't read console input"); + + if (recs[0].EventType == KEY_EVENT) + { + if (!recs[0].Event.KeyEvent.bKeyDown) + { + ch = recs[0].Event.KeyEvent.uChar.AsciiChar; + + switch (ch) + { + case '\r': + WriteFile(houtput, "\r\n", 2, &dummy, NULL); + + if (len) + { + text[len] = 0; + len = 0; + return text; + } + else if (sc_return_on_enter) + { + // special case to allow exiting from the error handler on Enter + text[0] = '\r'; + len = 0; + return text; + } + + break; + + case '\b': + WriteFile(houtput, "\b \b", 3, &dummy, NULL); + if (len) + { + len--; + } + break; + + default: + if (ch >= ' ') + { + WriteFile(houtput, &ch, 1, &dummy, NULL); + text[len] = ch; + len = (len + 1) & 0xff; + } + + break; + + } + } + } + } + + return NULL; +} + +void Sys_Sleep (void) +{ + Sleep (1); +} + + +void Sys_SendKeyEvents (void) +{ + MSG msg; + + while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) + { + // we always update if there are any event, even if we're paused + scr_skipupdate = 0; + + if (!GetMessage (&msg, NULL, 0, 0)) + Sys_Quit (); + + TranslateMessage (&msg); + DispatchMessage (&msg); + } +} + + +/* +============================================================================== + + WINDOWS CRAP + +============================================================================== +*/ + + +/* +================== +WinMain +================== +*/ +void SleepUntilInput (int time) +{ + + MsgWaitForMultipleObjects(1, &tevent, FALSE, time, QS_ALLINPUT); +} + + +/* +================== +WinMain +================== +*/ +HINSTANCE global_hInstance; +int global_nCmdShow; +char *argv[MAX_NUM_ARGVS]; +static char *empty_string = ""; +HWND hwnd_dialog; + + +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + MSG msg; + quakeparms_t parms; + double time, oldtime, newtime; + MEMORYSTATUS lpBuffer; + static char cwd[1024]; + int t; + RECT rect; + + /* previous instances do not exist in Win32 */ + if (hPrevInstance) + return 0; + + global_hInstance = hInstance; + global_nCmdShow = nCmdShow; + + lpBuffer.dwLength = sizeof(MEMORYSTATUS); + GlobalMemoryStatus (&lpBuffer); + + if (!GetCurrentDirectory (sizeof(cwd), cwd)) + Sys_Error ("Couldn't determine current directory"); + + if (cwd[Q_strlen(cwd)-1] == '/') + cwd[Q_strlen(cwd)-1] = 0; + + parms.basedir = cwd; + parms.cachedir = NULL; + + parms.argc = 1; + argv[0] = empty_string; + + while (*lpCmdLine && (parms.argc < MAX_NUM_ARGVS)) + { + while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126))) + lpCmdLine++; + + if (*lpCmdLine) + { + argv[parms.argc] = lpCmdLine; + parms.argc++; + + while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) + lpCmdLine++; + + if (*lpCmdLine) + { + *lpCmdLine = 0; + lpCmdLine++; + } + + } + } + + parms.argv = argv; + + COM_InitArgv (parms.argc, parms.argv); + + parms.argc = com_argc; + parms.argv = com_argv; + + isDedicated = (COM_CheckParm ("-dedicated") != 0); + + if (!isDedicated) + { + hwnd_dialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, NULL); + + if (hwnd_dialog) + { + if (GetWindowRect (hwnd_dialog, &rect)) + { + if (rect.left > (rect.top * 2)) + { + SetWindowPos (hwnd_dialog, 0, + (rect.left / 2) - ((rect.right - rect.left) / 2), + rect.top, 0, 0, + SWP_NOZORDER | SWP_NOSIZE); + } + } + + ShowWindow (hwnd_dialog, SW_SHOWDEFAULT); + UpdateWindow (hwnd_dialog); + SetForegroundWindow (hwnd_dialog); + } + } + +// take the greater of all the available memory or half the total memory, +// but at least 8 Mb and no more than 16 Mb, unless they explicitly +// request otherwise + parms.memsize = lpBuffer.dwAvailPhys; + + if (parms.memsize < MINIMUM_WIN_MEMORY) + parms.memsize = MINIMUM_WIN_MEMORY; + + if (parms.memsize < (lpBuffer.dwTotalPhys >> 1)) + parms.memsize = lpBuffer.dwTotalPhys >> 1; + + if (parms.memsize > MAXIMUM_WIN_MEMORY) + parms.memsize = MAXIMUM_WIN_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); + + tevent = CreateEvent(NULL, FALSE, FALSE, NULL); + + if (!tevent) + Sys_Error ("Couldn't create event"); + + if (isDedicated) + { + if (!AllocConsole ()) + { + Sys_Error ("Couldn't create dedicated server console"); + } + + hinput = GetStdHandle (STD_INPUT_HANDLE); + houtput = GetStdHandle (STD_OUTPUT_HANDLE); + + // give QHOST a chance to hook into the console + if ((t = COM_CheckParm ("-HFILE")) > 0) + { + if (t < com_argc) + hFile = (HANDLE)Q_atoi (com_argv[t+1]); + } + + if ((t = COM_CheckParm ("-HPARENT")) > 0) + { + if (t < com_argc) + heventParent = (HANDLE)Q_atoi (com_argv[t+1]); + } + + if ((t = COM_CheckParm ("-HCHILD")) > 0) + { + if (t < com_argc) + heventChild = (HANDLE)Q_atoi (com_argv[t+1]); + } + + InitConProc (hFile, heventParent, heventChild); + } + + Sys_Init (); + +// because sound is off until we become active + S_BlockSound (); + + Sys_Printf ("Host_Init\n"); + Host_Init (&parms); + + oldtime = Sys_FloatTime (); + + /* main window message loop */ + while (1) + { + if (isDedicated) + { + newtime = Sys_FloatTime (); + time = newtime - oldtime; + + while (time < sys_ticrate.value ) + { + Sys_Sleep(); + newtime = Sys_FloatTime (); + time = newtime - oldtime; + } + } + else + { + // yield the CPU for a little while when paused, minimized, or not the focus + if ((cl.paused && (!ActiveApp && !DDActive)) || Minimized || block_drawing) + { + SleepUntilInput (PAUSE_SLEEP); + scr_skipupdate = 1; // no point in bothering to draw + } + else if (!ActiveApp && !DDActive) + { + SleepUntilInput (NOT_FOCUS_SLEEP); + } + + newtime = Sys_FloatTime (); + time = newtime - oldtime; + } + + Host_Frame (time); + oldtime = newtime; + } + + /* return success of application */ + return TRUE; +} + diff --git a/engine/code/unzip.c b/engine/code/unzip.c new file mode 100644 index 0000000..295f254 --- /dev/null +++ b/engine/code/unzip.c @@ -0,0 +1,4321 @@ +/***************************************************************************** + * name: unzip.c + * + * desc: IO on .zip files using portions of zlib + * + * $Archive: /MissionPack/code/qcommon/unzip.c $ + * + *****************************************************************************/ + +//#include "../client/client.h" +#include "quakedef.h" +//#include "unzip.h" + +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.3, July 9th, 1998 + + Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +#define OF(args) args +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ +typedef Byte *voidp; + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#endif /* _ZCONF_H */ + +#define ZLIB_VERSION "1.1.3" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +// static const char * zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +int deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +// static int deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +// static int deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +int inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +static int inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +static int inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +int deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +/* +static int deflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +*/ +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +/* +static int deflateCopy OF((z_streamp dest, + z_streamp source)); +*/ +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +// static int deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +/* +static int deflateParams OF((z_streamp strm, + int level, + int strategy)); +*/ +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +int inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +/* +static int inflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +*/ +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +// static int inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +static int inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +/* +static int compress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +*/ +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +/* +static int compress2 OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen, + int level)); +*/ +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +/* +static int uncompress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +*/ +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +gzFile gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +gzFile gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +int gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +int gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +int gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +//int QDECL gzprintf OF((gzFile file, const char *format, ...)); jkrige +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +int gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +char * gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +int gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +int gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +int gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +long gzseek OF((gzFile file, + long offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +int gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +long gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +int gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +int gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +// static const char * gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +static uLong adler32 OF((uLong adler, const Byte *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +/* +static int deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +static int inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +static int deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +*/ +static int inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); + +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +// static const char * zError OF((int err)); +// static int inflateSyncPoint OF((z_streamp z)); +// static const uLong * get_crc_table OF((void)); + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +// static const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +// jkrige +//#define zmemcpy Com_Memcpy +#define zmemcpy memcpy +// jkrige + +#define zmemcmp memcmp +#define zmemzero(dest, len) Com_Memset(dest, 0, len) + +/* Diagnostic functions */ +#ifdef _ZIP_DEBUG_ + int z_verbose = 0; +# define Assert(cond,msg) assert(cond); + //{if(!(cond)) Sys_Error(msg);} +# define Trace(x) {if (z_verbose>=0) Sys_Error x ;} +# define Tracev(x) {if (z_verbose>0) Sys_Error x ;} +# define Tracevv(x) {if (z_verbose>1) Sys_Error x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) Sys_Error x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) Sys_Error x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Byte *buf, uInt len)); +static voidp zcalloc OF((voidp opaque, unsigned items, unsigned size)); +static void zcfree OF((voidp opaque, voidp ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidp)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (65536) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +// jkrige - pk3 file support +//# define ALLOC(size) (Z_Malloc(size)) +# define ALLOC(size) (malloc(size)) +// jkrige - pk3 file support +#endif +#ifndef TRYFREE +// jkrige - pk3 file support +//# define TRYFREE(p) {if (p) Z_Free(p);} +# define TRYFREE(p) {if (p) free(p);} +// jkrige - pk3 file support +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + +/* +static int unzlocal_getByte(FILE *fin,int *pi) +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} +*/ + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +static int unzlocal_getShort (FILE* fin, uLong *pX) +{ + short v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = LittleShort( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + +static int unzlocal_getLong (FILE *fin, uLong *pX) +{ + int v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = LittleLong( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + + +/* My own strcmpi / strcasecmp */ +static int strcmpcasenosensitive_internal (const char* fileName1,const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity) +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +extern uLong unzlocal_SearchCentralDir(FILE *fin) +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +extern unzFile unzReOpen (const char* path, unzFile file) +{ + unz_s *s; + FILE * fin; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + s=(unz_s*)ALLOC(sizeof(unz_s)); + + // jkrige + //Com_Memcpy(s, (unz_s*)file, sizeof(unz_s)); + memcpy(s, (unz_s*)file, sizeof(unz_s)); + // jkrige + + s->file = fin; + return (unzFile)s; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile unzOpen (const char* path) +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +static void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +static int unzlocal_GetCurrentFileInfoInternal (unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) { + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) { + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + } + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) { + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + } + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int unzGetCurrentFileInfo ( unzFile file, unz_file_info *pfile_info, + char *szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char *szComment, uLong commentBufferSize) +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int unzGoToNextFile (unzFile file) +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Get the position of the info of the current file in the zip. + return UNZ_OK if there is no problem +*/ +extern int unzGetCurrentFileInfoPosition (unzFile file, unsigned long *pos ) +{ + unz_s* s; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + *pos = s->pos_in_central_dir; + return UNZ_OK; +} + +/* + Set the position of the info of the current file in the zip. + return UNZ_OK if there is no problem +*/ +extern int unzSetCurrentFileInfoPosition (unzFile file, unsigned long pos ) +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + s->pos_in_central_dir = pos; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return UNZ_OK; +} + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz_s* s; + int err; + + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the static header of the current zipfile + Check the coherency of the static header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in static header + (filename and size of extra field data) +*/ +static int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar, + uLong *poffset_local_extrafield, + uInt *psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) { + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int unzOpenCurrentFile (unzFile file) +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the static extra field */ + uInt size_local_extrafield; /* size of the static extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*)ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidp)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int unzReadCurrentFile (unzFile file, void *buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Byte*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (s->cur_file_info.compressed_size == pfile_in_zip_read_info->rest_read_compressed) + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Byte*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + +// pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, +// pfile_in_zip_read_info->stream.next_out, +// uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Byte *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + +// pfile_in_zip_read_info->crc32 = +// crc32(pfile_in_zip_read_info->crc32,bufBefore, +// (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern long unztell (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (long)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int unzeof (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the static-header version of the extra field (sometimes, there is + more info in the static-header version than in the central-header) + + if buf==NULL, it return the size of the static extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int unzGetLocalExtrafield (unzFile file,void *buf,unsigned len) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + +/* + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } +*/ + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) +{ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state inflate_blocks_statef; + +static inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +static int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +static void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +static int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +#if 0 +static void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +static int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); +#endif + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +static const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +static int inflate_trees_bits OF(( + uInt *, /* 19 code lengths */ + uInt *, /* bits tree desired/actual depth */ + inflate_huft * *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +static int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uInt *, /* that many (total) code lengths */ + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +static int inflate_trees_fixed OF(( + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + z_streamp)); /* for memory allocation */ + + +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state inflate_codes_statef; + +static inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +static int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +static void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uInt *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Byte *window; /* sliding window */ + Byte *end; /* one byte after sliding window */ + Byte *read; /* window read pointer */ + Byte *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load static pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +static uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +static int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +#endif + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); + Tracev(("inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev(("inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev(("inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev(("inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev(("inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev(("inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev(("inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev(("inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev(("inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + tl = NULL; + td = NULL; + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BAD; + r = t; + LEAVE + } + Tracev(("inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev(("inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev(("inflate: blocks freed\n")); + return Z_OK; +} + +#if 0 +void inflate_set_dictionary(inflate_blocks_statef *s, const Byte *d, uInt n) +{ + zmemcpy(s->window, d, n); + s->read = s->write = s->window + n; +} + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL + */ +int inflate_blocks_sync_point(inflate_blocks_statef *s) +{ + return s->mode == LENS; +} +#endif + + +/* And'ing with mask[n] masks the lower n bits */ +static uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt n; + Byte *p; + Byte *q; + + /* static copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} + +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +static const char inflate_copyright[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +static int huft_build OF(( + uInt *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uInt *, /* list of base values for non-simple codes */ + const uInt *, /* list of extra bits for non-simple codes */ + inflate_huft **, /* result: starting table */ + uInt *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uInt * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +static int huft_build(uInt *b, uInt n, uInt s, const uInt *d, const uInt *e, inflate_huft ** t, uInt *m, inflate_huft *hp, uInt *hn, uInt *v) +//uInt *b; /* code lengths in bits (all assumed <= BMAX) */ +//uInt n; /* number of codes (assumed <= 288) */ +//uInt s; /* number of simple-valued codes (0..s-1) */ +//const uInt *d; /* list of base values for non-simple codes */ +//const uInt *e; /* list of extra bits for non-simple codes */ +//inflate_huft ** t; /* result: starting table */ +//uInt *m; /* maximum lookup bits, returns actual */ +//inflate_huft *hp; /* space for trees */ +//uInt *hn; /* hufts used in space */ +//uInt *v; /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uInt *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uInt *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_MEM_ERROR; /* not enough memory */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(uInt *c, uInt *bb, inflate_huft * *tb, inflate_huft *hp, z_streamp z) +//uInt *c; /* 19 code lengths */ +//uInt *bb; /* bits tree desired/actual depth */ +//inflate_huft * *tb; /* bits tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic(uInt nl, uInt nd, uInt *c, uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, inflate_huft *hp, z_streamp z) +//uInt nl; /* number of literal/length codes */ +//uInt nd; /* number of distance codes */ +//uInt *c; /* that many (total) code lengths */ +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} + +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +static uInt fixed_bl = 9; +static uInt fixed_bd = 5; +static inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +static inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; + +int inflate_trees_fixed(uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, z_streamp z) +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//z_streamp z; /* for memory allocation */ +{ + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +static int inflate_fast(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, inflate_blocks_statef *s, z_streamp z) +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Byte *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv(("inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} + +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, z_streamp z) +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev(("inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Byte *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv(("inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv(("inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv(("inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +void inflate_codes_free(inflate_codes_statef *c, z_streamp z) +{ + ZFREE(z, c); + Tracev(("inflate: codes free\n")); +} + +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#undef DO1 +#undef DO2 +#undef DO4 +#undef DO8 + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +static uLong adler32(uLong adler, const Byte *buf, uInt len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +static inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +static int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +static void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +static int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +#if 0 +static void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +static int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); +#endif + +typedef enum { + imMETHOD, /* waiting for method byte */ + imFLAG, /* waiting for flag byte */ + imDICT4, /* four dictionary check bytes to go */ + imDICT3, /* three dictionary check bytes to go */ + imDICT2, /* two dictionary check bytes to go */ + imDICT1, /* one dictionary check byte to go */ + imDICT0, /* waiting for inflateSetDictionary */ + imBLOCKS, /* decompressing blocks */ + imCHECK4, /* four check bytes to go */ + imCHECK3, /* three check bytes to go */ + imCHECK2, /* two check bytes to go */ + imCHECK1, /* one check byte to go */ + imDONE, /* finished check, done */ + imBAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? imBLOCKS : imMETHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev(("inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev(("inflate: end\n")); + return Z_OK; +} + + + +int inflateInit2_(z_streamp z, int w, const char *version, int stream_size) +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = (void *(*)(void *, unsigned, unsigned))zcalloc; + z->opaque = (voidp)0; + } + if (z->zfree == Z_NULL) z->zfree = (void (*)(void *, void *))zcfree; + if ((z->state = (struct internal_state *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev(("inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + +#if 0 +int inflateInit_(z_streamp z, const char *version, int stream_size) +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} +#endif + +#define iNEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define iNEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z_streamp z, int f) +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case imMETHOD: + iNEEDBYTE + if (((z->state->sub.method = iNEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = imBAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = imBAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = imFLAG; + case imFLAG: + iNEEDBYTE + b = iNEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = imBLOCKS; + break; + } + z->state->mode = imDICT4; + case imDICT4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imDICT3; + case imDICT3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imDICT2; + case imDICT2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imDICT1; + case imDICT1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = imDICT0; + return Z_NEED_DICT; + case imDICT0: + z->state->mode = imBAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case imBLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = imDONE; + break; + } + z->state->mode = imCHECK4; + case imCHECK4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imCHECK3; + case imCHECK3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imCHECK2; + case imCHECK2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imCHECK1; + case imCHECK1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib check ok\n")); + z->state->mode = imDONE; + case imDONE: + return Z_STREAM_END; + case imBAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + +// defined but not used +#if 0 +int inflateSetDictionary(z_streamp z, const Byte *dictionary, uInt dictLength) +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != imDICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = imBLOCKS; + return Z_OK; +} + +int inflateSync(z_streamp z) +{ + uInt n; /* number of bytes to look at */ + Byte *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != imBAD) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + static const Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = imBLOCKS; + return Z_OK; +} + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +int inflateSyncPoint(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(z->state->blocks); +} +#endif + +voidp zcalloc (voidp opaque, unsigned items, unsigned size) +{ + if (opaque) items += size - size; /* make compiler happy */ + + // jkrige - pk3 file support + //return (voidp)Z_Malloc(items*size); + return (voidp)malloc(items*size); + // jkrige - pk3 file support +} + +void zcfree (voidp opaque, voidp ptr) +{ + // jkrige - pk3 file support + //Z_Free(ptr); + free(ptr); + // jkrige - pk3 file support + + if (opaque) return; /* make compiler happy */ +} + + diff --git a/engine/code/unzip.h b/engine/code/unzip.h new file mode 100644 index 0000000..2c31298 --- /dev/null +++ b/engine/code/unzip.h @@ -0,0 +1,336 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef void* unzFile; +#endif + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + unsigned int tm_sec; /* seconds after the minute - [0,59] */ + unsigned int tm_min; /* minutes after the hour - [0,59] */ + unsigned int tm_hour; /* hours since midnight - [0,23] */ + unsigned int tm_mday; /* day of the month - [1,31] */ + unsigned int tm_mon; /* months since January - [0,11] */ + unsigned int tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + unsigned long number_entry; /* total number of entries in the central dir on this disk */ + unsigned long size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + unsigned long version; /* version made by 2 unsigned chars */ + unsigned long version_needed; /* version needed to extract 2 unsigned chars */ + unsigned long flag; /* general purpose bit flag 2 unsigned chars */ + unsigned long compression_method; /* compression method 2 unsigned chars */ + unsigned long dosDate; /* last mod file date in Dos fmt 4 unsigned chars */ + unsigned long crc; /* crc-32 4 unsigned chars */ + unsigned long compressed_size; /* compressed size 4 unsigned chars */ + unsigned long uncompressed_size; /* uncompressed size 4 unsigned chars */ + unsigned long size_filename; /* filename length 2 unsigned chars */ + unsigned long size_file_extra; /* extra field length 2 unsigned chars */ + unsigned long size_file_comment; /* file comment length 2 unsigned chars */ + + unsigned long disk_num_start; /* disk number start 2 unsigned chars */ + unsigned long internal_fa; /* internal file attributes 2 unsigned chars */ + unsigned long external_fa; /* external file attributes 4 unsigned chars */ + + tm_unz tmu_date; +} unz_file_info; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + unsigned long offset_curfile;/* relative offset of static header 4 unsigned chars */ +} unz_file_info_internal; + +typedef void* (*alloc_func) (void* opaque, unsigned int items, unsigned int size); +typedef void (*free_func) (void* opaque, void* address); + +struct internal_state; + +typedef struct z_stream_s { + unsigned char *next_in; /* next input unsigned char */ + unsigned int avail_in; /* number of unsigned chars available at next_in */ + unsigned long total_in; /* total nb of input unsigned chars read so */ + + unsigned char *next_out; /* next output unsigned char should be put there */ + unsigned int avail_out; /* remaining free space at next_out */ + unsigned long total_out; /* total nb of unsigned chars output so */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + unsigned char* opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + unsigned long adler; /* adler32 value of the uncompressed data */ + unsigned long reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream *z_streamp; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + unsigned long pos_in_zipfile; /* position in unsigned char on the zipfile, for fseek*/ + unsigned long stream_initialised; /* flag set if stream structure is initialised*/ + + unsigned long offset_local_extrafield;/* offset of the static extra field */ + unsigned int size_local_extrafield;/* size of the static extra field */ + unsigned long pos_local_extrafield; /* position in the static extra field in read*/ + + unsigned long crc32; /* crc32 of all data uncompressed */ + unsigned long crc32_wait; /* crc32 we must obtain after decompress all */ + unsigned long rest_read_compressed; /* number of unsigned char to be decompressed */ + unsigned long rest_read_uncompressed;/*number of unsigned char to be obtained after decomp*/ + FILE* file; /* io structore of the zipfile */ + unsigned long compression_method; /* compression method (0==store) */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + FILE* file; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ + unsigned long num_file; /* number of the current file in the zipfile*/ + unsigned long pos_in_central_dir; /* pos of the current file in the central dir*/ + unsigned long current_file_ok; /* flag about the usability of the current file*/ + unsigned long central_pos; /* position of the beginning of the central dir*/ + + unsigned long size_central_dir; /* size of the central directory */ + unsigned long offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + unsigned char* tmpFile; + int tmpPos,tmpSize; +} unz_s; + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +#define UNZ_CASESENSITIVE 1 +#define UNZ_NOTCASESENSITIVE 2 +#define UNZ_OSDEFAULTCASE 0 + +extern int unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity); + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + +extern unzFile unzOpen (const char *path); +extern unzFile unzReOpen (const char* path, unzFile file); + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int unzClose (unzFile file); + +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info); + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int unzGetGlobalComment (unzFile file, char *szComment, unsigned long uSizeBuf); + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of unsigned char copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int unzGoToFirstFile (unzFile file); + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int unzGoToNextFile (unzFile file); + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int unzGetCurrentFileInfoPosition (unzFile file, unsigned long *pos ); + +/* + Get the position of the info of the current file in the zip. + return UNZ_OK if there is no problem +*/ + +extern int unzSetCurrentFileInfoPosition (unzFile file, unsigned long pos ); + +/* + Set the position of the info of the current file in the zip. + return UNZ_OK if there is no problem +*/ + +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity); + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, char *szFileName, unsigned long fileNameBufferSize, void *extraField, unsigned long extraFieldBufferSize, char *szComment, unsigned long commentBufferSize); + +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int unzOpenCurrentFile (unzFile file); + +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int unzCloseCurrentFile (unzFile file); + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + + +extern int unzReadCurrentFile (unzFile file, void* buf, unsigned len); + +/* + Read unsigned chars from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of unsigned char copied if somes unsigned chars are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern long unztell(unzFile file); + +/* + Give the current position in uncompressed data +*/ + +extern int unzeof (unzFile file); + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int unzGetLocalExtrafield (unzFile file, void* buf, unsigned len); + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of unsigned chars copied in buf, or (if <0) + the error code +*/ diff --git a/engine/code/vid.h b/engine/code/vid.h new file mode 100644 index 0000000..1708ba8 --- /dev/null +++ b/engine/code/vid.h @@ -0,0 +1,85 @@ +/* +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. + +*/ +// vid.h -- video driver defs + +#define VID_CBITS 6 +#define VID_GRADES (1 << VID_CBITS) + +// a pixel can be one, two, or four bytes +typedef byte pixel_t; + +typedef struct vrect_s +{ + int x,y,width,height; + struct vrect_s *pnext; +} vrect_t; + +typedef struct +{ + pixel_t *buffer; // invisible buffer + pixel_t *colormap; // 256 * VID_GRADES size + unsigned short *colormap16; // 256 * VID_GRADES size + int fullbright; // index of first fullbright color + unsigned rowbytes; // may be > 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 +} viddef_t; + +extern viddef_t vid; // global video state +extern unsigned short d_8to16table[256]; +extern unsigned d_8to24table[256]; +extern void (*vid_menudrawfn)(void); +extern void (*vid_menukeyfn)(int key); + +void VID_SetPalette (unsigned char *palette); +// called at startup and after any gamma correction + +void VID_ShiftPalette (unsigned char *palette); +// called for bonus and pain flashes, and for underwater color changes + +void VID_Init (unsigned char *palette); +// Called at startup to set up translation tables, takes 256 8 bit RGB values +// the palette data will go away after the call, so it must be copied off if +// the video driver will need it again + +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, unsigned char *palette); +// sets the mode; only used by the Quake engine for resetting to mode 0 (the +// base mode) on memory allocation failures + +void VID_HandlePause (qboolean pause); +// called only on Win32, when pause happens, so the mouse can be released + diff --git a/engine/code/vid_gamma.c b/engine/code/vid_gamma.c new file mode 100644 index 0000000..d8c603a --- /dev/null +++ b/engine/code/vid_gamma.c @@ -0,0 +1,308 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +/* +** VID_GAMMA.C +*/ + +#include "quakedef.h" + +#ifdef _WIN32 +#include "winquake.h" +#endif + +static unsigned char gl_gammatable[256]; + +static int overbrightBits; +static unsigned short oldHardwareGamma[3][256]; +qboolean deviceSupportsGamma = false; +qboolean deviceSupportsGamma3DFX = false; + +/* +** VG_CheckHardwareGamma +** +** Determines if the underlying hardware supports the Win32 gamma correction API. +*/ +void VG_CheckHardwareGamma( void ) +{ + HDC hDC; + + deviceSupportsGamma = false; + deviceSupportsGamma3DFX = false; + + if ( qwglSetDeviceGammaRamp3DFX ) + { + deviceSupportsGamma3DFX = true; + + hDC = GetDC( GetDesktopWindow() ); + deviceSupportsGamma3DFX = qwglGetDeviceGammaRamp3DFX( hDC, oldHardwareGamma ); + ReleaseDC( GetDesktopWindow(), hDC ); + + return; + } + + if ( !deviceSupportsGamma3DFX ) + { + hDC = GetDC( GetDesktopWindow() ); + deviceSupportsGamma = GetDeviceGammaRamp( hDC, oldHardwareGamma ); + ReleaseDC( GetDesktopWindow(), hDC ); + + if ( deviceSupportsGamma ) + { + // do a sanity check on the gamma values + if ( ( HIBYTE( oldHardwareGamma[0][255] ) <= HIBYTE( oldHardwareGamma[0][0] ) ) || + ( HIBYTE( oldHardwareGamma[1][255] ) <= HIBYTE( oldHardwareGamma[1][0] ) ) || + ( HIBYTE( oldHardwareGamma[2][255] ) <= HIBYTE( oldHardwareGamma[2][0] ) ) ) + { + deviceSupportsGamma = false; + Con_Printf("Device has broken gamma support\n"); + } + + // make sure that we didn't have a prior crash in the game, and if so we need to + // restore the gamma values to at least a linear value + if ( ( HIBYTE( oldHardwareGamma[0][181] ) == 255 ) ) + { + int g; + + Con_Printf("Suspicious gamma tables, using linear ramp for restoration\n"); + + for ( g = 0; g < 255; g++ ) + { + oldHardwareGamma[0][g] = g << 8; + oldHardwareGamma[1][g] = g << 8; + oldHardwareGamma[2][g] = g << 8; + } + } + } + } +} + +/* +** VG_SetGamma +** +** This routine should only be called if deviceSupportsGamma is TRUE +*/ +void VG_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] ) +{ + unsigned short table[3][256]; + int i, j; + int ret; + //OSVERSIONINFO vinfo; // jkrige - remove windows version check + HDC hDC; + + hDC = GetDC( GetDesktopWindow() ); + + if ( (!deviceSupportsGamma && !deviceSupportsGamma3DFX) || !hDC ) + return; + + for ( i = 0; i < 256; i++ ) { + table[0][i] = ( ( ( unsigned short ) red[i] ) << 8 ) | red[i]; + table[1][i] = ( ( ( unsigned short ) green[i] ) << 8 ) | green[i]; + table[2][i] = ( ( ( unsigned short ) blue[i] ) << 8 ) | blue[i]; + } + + // jkrige - remove windows version check - begin + // Win2K puts this odd restriction on gamma ramps... + /*vinfo.dwOSVersionInfoSize = sizeof(vinfo); + GetVersionEx( &vinfo ); + if ( vinfo.dwMajorVersion == 5 && vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) + { + Con_DPrintf("performing Windows 2000 gamma clamp.\n"); + for ( j = 0 ; j < 3 ; j++ ) { + for ( i = 0 ; i < 128 ; i++ ) { + if ( table[j][i] > ( (128+i) << 8 ) ) { + table[j][i] = (128+i) << 8; + } + } + if ( table[j][127] > 254<<8 ) { + table[j][127] = 254<<8; + } + } + } + else + { + Con_DPrintf("skipping Windows 2000 gamma clamp.\n"); + }*/ + // jkrige - remove windows version check - end + + // enforce constantly increasing + for ( j = 0 ; j < 3 ; j++ ) { + for ( i = 1 ; i < 256 ; i++ ) { + if ( table[j][i] < table[j][i-1] ) { + table[j][i] = table[j][i-1]; + } + } + } + + if ( qwglSetDeviceGammaRamp3DFX ) + { + qwglSetDeviceGammaRamp3DFX( hDC, table ); + } + else + { + ret = SetDeviceGammaRamp( hDC, table ); + if ( !ret ) + Con_Printf("SetDeviceGammaRamp failed.\n"); + } + ReleaseDC( GetDesktopWindow(), hDC ); +} + +/* +** VG_RestoreGamma +*/ +void VG_RestoreGamma( void ) +{ + HDC hDC; + + hDC = GetDC( GetDesktopWindow() ); + + if ( deviceSupportsGamma ) + { + if ( qwglSetDeviceGammaRamp3DFX ) + { + qwglSetDeviceGammaRamp3DFX( hDC, oldHardwareGamma ); + } + else + { + SetDeviceGammaRamp( hDC, oldHardwareGamma ); + } + } + + ReleaseDC( GetDesktopWindow(), hDC ); +} + +/* +=============== +VG_GammaCorrect +=============== +*/ +void VG_GammaCorrect( byte *buffer, int bufSize ) { + int i; + + for ( i = 0; i < bufSize; i++ ) { + buffer[i] = gl_gammatable[buffer[i]]; + } +} + +/* +=============== +VG_SetColorMappings +=============== +*/ +void VG_SetColorMappings( void ) +{ + int i, j; + float g; + int inf; + int shift; + + // setup the overbright lighting + overbrightBits = (int)gl_overbrightbits.value; + + if ( !deviceSupportsGamma ) + overbrightBits = 0; // need hardware gamma for overbright + + // never overbright in windowed mode + if ( modestate != MS_FULLSCREEN && modestate != MS_FULLDIB ) + overbrightBits = 0; + + // allow 2 overbright bits in 24 bit, but only 1 in 16 bit + + // jkrige - no 16bit mode + //if ( vid.bpp > 16 ) + //{ + if ( overbrightBits > 2 ) + overbrightBits = 2; + //} + //else + //{ + // if ( overbrightBits > 1 ) + // overbrightBits = 1; + //} + // jkrige - no 16bit mode + + + if ( overbrightBits < 0 ) + overbrightBits = 0; + + if ( gl_gamma.value < 0.5f ) + { + Cvar_SetValue ("gamma", 0.5f); + return; + } + else if ( gl_gamma.value > 2.75f ) + { + Cvar_SetValue ("gamma", 2.75f); + return; + } + + g = 3.0f - gl_gamma.value; + + // jkrige - quake 3 + //if ( r_intensity->value <= 1 ) { + // ri.Cvar_Set( "r_intensity", "1" ); + //} + // jkrige - quake 3 + + if ( gl_overbrightbits.value < 0.0f ) + { + Cvar_SetValue ("gl_overbrightbits", 0.0f); + return; + } + else if ( gl_overbrightbits.value > (float)overbrightBits ) + { + Cvar_SetValue ("gl_overbrightbits", (float)overbrightBits); + return; + } + + shift = (int)gl_overbrightbits.value; + + for ( i = 0; i < 256; i++ ) { + if ( g == 1 ) { + inf = i; + } else { + inf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f; + } + inf <<= shift; + if (inf < 0) { + inf = 0; + } + if (inf > 255) { + inf = 255; + } + gl_gammatable[i] = inf; + } + + // jkrige - quake 3 + /*for (i=0 ; i<256 ; i++) { + j = i * r_intensity->value; + if (j > 255) { + j = 255; + } + s_intensitytable[i] = j; + }*/ + // jkrige - quake 3 + + if ( deviceSupportsGamma ) + { + VG_SetGamma( gl_gammatable, gl_gammatable, gl_gammatable ); + } +} \ No newline at end of file diff --git a/engine/code/vid_gamma.h b/engine/code/vid_gamma.h new file mode 100644 index 0000000..c1e1951 --- /dev/null +++ b/engine/code/vid_gamma.h @@ -0,0 +1,28 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +extern qboolean deviceSupportsGamma; + +void VG_SetColorMappings( void ); +void VG_CheckHardwareGamma( void ); +void VG_RestoreGamma( void ); +void VG_GammaCorrect( byte *buffer, int bufSize ); \ No newline at end of file diff --git a/engine/code/view.c b/engine/code/view.c new file mode 100644 index 0000000..147081b --- /dev/null +++ b/engine/code/view.c @@ -0,0 +1,1210 @@ +/* +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. + +*/ +// view.c -- player eye positioning + +#include "quakedef.h" +//#include "r_local.h" // jkrige - removed + +/* + +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 lcd_x = {"lcd_x","0"}; +cvar_t lcd_yaw = {"lcd_yaw","0"}; + +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_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 cl_crossx = {"cl_crossx", "0", false}; +cvar_t cl_crossy = {"cl_crossy", "0", false}; + +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; + + +/* +=============== +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); + + // jkrige - view weapon bob fix + if (bob > 7) + bob = 7; + else if (bob < -7) + bob = -7; + //if (bob > 4) + // bob = 4; + //else if (bob < -7) + // bob = -7; + // jkrige - view weapon bob fix + + 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 ) + { + 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) + { + // jkrige - lookspring fix + //V_StartPitchDrift (); + if(lookspring.value) + V_StartPitchDrift (); + // jkrige - lookspring fix + } + 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; + } +} + + + + + +/* +============================================================================== + + PALETTE FLASHES + +============================================================================== +*/ + + +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 }; + +// jkrige - gamma +#ifdef GLQUAKE +cvar_t gl_gamma = {"gamma", "2.45", true}; +cvar_t gl_overbrightbits = {"gl_overbrightbits", "0", true}; +#else +cvar_t v_gamma = {"gamma", "1", true}; +#endif +// jkrige - gamma + +byte gammatable[256]; // palette is sent through this + +#ifdef GLQUAKE +byte ramps[3][256]; +float v_blend[4]; // rgba 0.0 - 1.0 +#endif // GLQUAKE + +void BuildGammaTable (float g) +{ + int i, inf; + + if (g == 1.0) + { + for (i=0 ; i<256 ; i++) + gammatable[i] = i; + return; + } + + for (i=0 ; i<256 ; i++) + { + inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5; + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + gammatable[i] = inf; + } +} + +/* +================= +V_CheckGamma +================= +*/ +// jkrige - gamma +qboolean V_CheckGamma (void) +{ + static float oldgammavalue; + static float oldoverbrightvalue; + + // jkrige - gamma +#ifdef GLQUAKE + if (gl_gamma.value == oldgammavalue && gl_overbrightbits.value == oldoverbrightvalue) + return false; + + oldgammavalue = gl_gamma.value; + oldoverbrightvalue = gl_overbrightbits.value; + + VG_SetColorMappings(); +#else + if (v_gamma.value == oldgammavalue) + return false; + + oldgammavalue = v_gamma.value; + BuildGammaTable (v_gamma.value); +#endif + // jkrige - gamma + + vid.recalc_refdef = 1; // force a surface cache flush + + return true; +} +/*qboolean V_CheckGamma (void) +{ + static float oldgammavalue; + + if (v_gamma.value == oldgammavalue) + return false; + oldgammavalue = v_gamma.value; + + BuildGammaTable (v_gamma.value); + vid.recalc_refdef = 1; // force a surface cache flush + + return true; +}*/ +// jkrige - gamma + + + +/* +=============== +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: + 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 +============= +*/ +#ifdef GLQUAKE +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; +} +#endif + +/* +============= +V_UpdatePalette +============= +*/ +#ifdef GLQUAKE +void V_UpdatePalette (void) +{ + int i, j; + qboolean new; + byte *basepal, *newpal; + byte pal[768]; + float r,g,b,a; + int ir, ig, ib; + qboolean force; + + V_CalcPowerupCshift (); + + new = false; + + for (i=0 ; i 255) + ir = 255; + if (ig > 255) + ig = 255; + if (ib > 255) + ib = 255; + + ramps[0][i] = gammatable[ir]; + ramps[1][i] = gammatable[ig]; + ramps[2][i] = gammatable[ib]; + } + + basepal = host_basepal; + newpal = pal; + + for (i=0 ; i<256 ; i++) + { + ir = basepal[0]; + ig = basepal[1]; + ib = basepal[2]; + basepal += 3; + + newpal[0] = ramps[0][ir]; + newpal[1] = ramps[1][ig]; + newpal[2] = ramps[2][ib]; + newpal += 3; + } + + VID_ShiftPalette (pal); +} +#else // !GLQUAKE +void V_UpdatePalette (void) +{ + int i, j; + qboolean new; + byte *basepal, *newpal; + byte pal[768]; + int r,g,b; + qboolean force; + + V_CalcPowerupCshift (); + + new = false; + + for (i=0 ; i>8; + g += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[1]-g))>>8; + b += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[2]-b))>>8; + } + + newpal[0] = gammatable[r]; + newpal[1] = gammatable[g]; + newpal[2] = gammatable[b]; + newpal += 3; + } + + VID_ShiftPalette (pal); +} +#endif // !GLQUAKE + + +/* +============================================================================== + + VIEW RENDERING + +============================================================================== +*/ + +float angledelta (float a) +{ + a = anglemod(a); + if (a > 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; + + // jkrige - smoothed stair stepping + static float steprate = 1; + static float steprate_accum = 1; + // jkrige - smoothed stair stepping + + 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); + + 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++) + { + // jkrige - view weapon bob fix + //view->origin[i] += forward[i]*bob*0.4; + view->origin[i] += forward[i]*bob*0.12; + // jkrige - view weapon bob fix + + //view->origin[i] += right[i]*bob*0.4; + //view->origin[i] += up[i]*bob*0.8; + } + view->origin[2] += bob; + + +// fudge position around to keep amount of weapon visible +// roughly equal with different FOV + +#if 0 + if (cl.model_precache[cl.stats[STAT_WEAPON]] && strcmp (cl.model_precache[cl.stats[STAT_WEAPON]]->name, "progs/v_shot2.mdl")) +#endif + + // jkrige - viewsize decreased + /*if (scr_viewsize.value == 110) + view->origin[2] += 1; + else if (scr_viewsize.value == 100) + view->origin[2] += 2; + else if (scr_viewsize.value == 90) + view->origin[2] += 1; + else if (scr_viewsize.value == 80) + view->origin[2] += 0.5;*/ + view->origin[2] += 2.2; + // jkrige - viewsize decreased + + view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; + view->frame = cl.stats[STAT_WEAPONFRAME]; + view->colormap = vid.colormap; + +// set up the refresh position + VectorAdd (r_refdef.viewangles, cl.punchangle, r_refdef.viewangles); + + // smooth out stair step ups + if (cl.onground && ent->origin[2] - oldz > 0) + { + float steptime; + + steptime = cl.time - cl.oldtime; + if (steptime < 0) + steptime = 0; //FIXME I_Error ("steptime < 0"); + + // jkrige - smoothed stair stepping + oldz += steptime * (80*steprate*steprate_accum); + //oldz += steptime * 80; + // jkrige - smoothed stair stepping + + + if (oldz > ent->origin[2]) + oldz = ent->origin[2]; + + + // jkrige - smoothed stair stepping + steprate_accum += 0.05; + steprate = 0.125*(ent->origin[2] - oldz); + if (steprate < 1) + steprate = 1; + + if (ent->origin[2] - oldz > 56) + oldz = ent->origin[2] - 12; + + //if (ent->origin[2] - oldz > 12) + //oldz = ent->origin[2] - 12; + // jkrige - smoothed stair stepping + + r_refdef.vieworg[2] += oldz - ent->origin[2]; + view->origin[2] += oldz - ent->origin[2]; + } + else + { + oldz = ent->origin[2]; + + // jkrige - smoothed stair stepping + steprate = 1; + steprate_accum = 1; + // jkrige - smoothed stair stepping + } + + // jkrige - removed chase + //if (chase_active.value) + // Chase_Update (); + // jkrige - removed chase +} + +/* +================== +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; + +// don't allow cheats in multiplayer + if (cl.maxclients > 1) + { + Cvar_Set ("scr_ofsx", "0"); + Cvar_Set ("scr_ofsy", "0"); + Cvar_Set ("scr_ofsz", "0"); + } + + if (cl.intermission) + { // intermission / finale rendering + V_CalcIntermissionRefdef (); + } + else + { + if (!cl.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ ) + V_CalcRefdef (); + } + + R_PushDlights (); + + if (lcd_x.value) + { + // + // render two interleaved views + // + int i; + + vid.rowbytes <<= 1; + vid.aspect *= 0.5; + + r_refdef.viewangles[YAW] -= lcd_yaw.value; + for (i=0 ; i<3 ; i++) + r_refdef.vieworg[i] -= right[i]*lcd_x.value; + R_RenderView (); + + vid.buffer += vid.rowbytes>>1; + + R_PushDlights (); + + r_refdef.viewangles[YAW] += lcd_yaw.value*2; + for (i=0 ; i<3 ; i++) + r_refdef.vieworg[i] += 2*right[i]*lcd_x.value; + R_RenderView (); + + vid.buffer -= vid.rowbytes>>1; + + r_refdef.vrect.height <<= 1; + + vid.rowbytes >>= 1; + vid.aspect *= 2; + } + else + { + R_RenderView (); + } + +#ifndef GLQUAKE + if (crosshair.value) + Draw_Character (scr_vrect.x + scr_vrect.width/2 + cl_crossx.value, scr_vrect.y + scr_vrect.height/2 + cl_crossy.value, '+'); +#endif + +} + +//============================================================================ + +/* +============= +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 (&lcd_x); + Cvar_RegisterVariable (&lcd_yaw); + + Cvar_RegisterVariable (&v_centermove); + Cvar_RegisterVariable (&v_centerspeed); + + Cvar_RegisterVariable (&v_iyaw_cycle); + Cvar_RegisterVariable (&v_iroll_cycle); + Cvar_RegisterVariable (&v_ipitch_cycle); + Cvar_RegisterVariable (&v_iyaw_level); + Cvar_RegisterVariable (&v_iroll_level); + Cvar_RegisterVariable (&v_ipitch_level); + + Cvar_RegisterVariable (&v_idlescale); + Cvar_RegisterVariable (&crosshair); + Cvar_RegisterVariable (&cl_crossx); + Cvar_RegisterVariable (&cl_crossy); + Cvar_RegisterVariable (&gl_cshiftpercent); + + Cvar_RegisterVariable (&scr_ofsx); + Cvar_RegisterVariable (&scr_ofsy); + Cvar_RegisterVariable (&scr_ofsz); + Cvar_RegisterVariable (&cl_rollspeed); + Cvar_RegisterVariable (&cl_rollangle); + Cvar_RegisterVariable (&cl_bob); + Cvar_RegisterVariable (&cl_bobcycle); + Cvar_RegisterVariable (&cl_bobup); + + Cvar_RegisterVariable (&v_kicktime); + Cvar_RegisterVariable (&v_kickroll); + Cvar_RegisterVariable (&v_kickpitch); + + BuildGammaTable (1.0); // no gamma yet + + // jkrige - gamma +#ifdef GLQUAKE + Cvar_RegisterVariable (&gl_gamma); + Cvar_RegisterVariable (&gl_overbrightbits); +#else + Cvar_RegisterVariable (&v_gamma); +#endif + // jkrige - gamma +} + + diff --git a/engine/code/view.h b/engine/code/view.h new file mode 100644 index 0000000..66d06ad --- /dev/null +++ b/engine/code/view.h @@ -0,0 +1,42 @@ +/* +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. + +*/ +// view.h + +// jkrige - gamma +#ifdef GLQUAKE +extern cvar_t gl_gamma; +extern cvar_t gl_overbrightbits; +#else +extern cvar_t v_gamma; +#endif +// jkrige - gamma + +extern byte gammatable[256]; // palette is sent through this +extern byte ramps[3][256]; +extern float v_blend[4]; + +extern cvar_t lcd_x; + + +void V_Init (void); +void V_RenderView (void); +float V_CalcRoll (vec3_t angles, vec3_t velocity); +void V_UpdatePalette (void); + diff --git a/engine/code/wad.c b/engine/code/wad.c new file mode 100644 index 0000000..c84f72c --- /dev/null +++ b/engine/code/wad.c @@ -0,0 +1,158 @@ +/* +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. + +*/ +// wad.c + +#include "quakedef.h" + +int wad_numlumps; +lumpinfo_t *wad_lumps; +byte *wad_base; + +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 (char *filename) +{ + lumpinfo_t *lump_p; + wadinfo_t *header; + unsigned i; + int infotableofs; + + wad_base = COM_LoadHunkFile (filename); + if (!wad_base) + Sys_Error ("W_LoadWadFile: couldn't load %s", filename); + + 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; + } + + Sys_Error ("W_GetLumpinfo: %s not found", name); + return NULL; +} + +void *W_GetLumpName (char *name) +{ + lumpinfo_t *lump; + + lump = W_GetLumpinfo (name); + + 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/engine/code/wad.h b/engine/code/wad.h new file mode 100644 index 0000000..9a740d9 --- /dev/null +++ b/engine/code/wad.h @@ -0,0 +1,75 @@ +/* +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. + +*/ +// 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 + +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 (char *filename); +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/engine/code/wglext.h b/engine/code/wglext.h new file mode 100644 index 0000000..9193948 --- /dev/null +++ b/engine/code/wglext.h @@ -0,0 +1,840 @@ +#ifndef __wglext_h_ +#define __wglext_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2013-2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +/* +** This header is generated from the Khronos OpenGL / OpenGL ES XML +** API Registry. The current version of the Registry, generator scripts +** used to make the header, and the header can be found at +** http://www.opengl.org/registry/ +** +** Khronos $Revision: 32433 $ on $Date: 2016-02-10 02:02:08 -0500 (Wed, 10 Feb 2016) $ +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#define WGL_WGLEXT_VERSION 20160209 + +/* Generated C header for: + * API: wgl + * Versions considered: .* + * Versions emitted: _nomatch_^ + * Default extensions included: wgl + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef WGL_ARB_buffer_region +#define WGL_ARB_buffer_region 1 +#define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 +#define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 +#define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 +#define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 +typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType); +typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion); +typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height); +typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); +#ifdef WGL_WGLEXT_PROTOTYPES +HANDLE WINAPI wglCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType); +VOID WINAPI wglDeleteBufferRegionARB (HANDLE hRegion); +BOOL WINAPI wglSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height); +BOOL WINAPI wglRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); +#endif +#endif /* WGL_ARB_buffer_region */ + +#ifndef WGL_ARB_context_flush_control +#define WGL_ARB_context_flush_control 1 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#endif /* WGL_ARB_context_flush_control */ + +#ifndef WGL_ARB_create_context +#define WGL_ARB_create_context 1 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define ERROR_INVALID_VERSION_ARB 0x2095 +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); +#ifdef WGL_WGLEXT_PROTOTYPES +HGLRC WINAPI wglCreateContextAttribsARB (HDC hDC, HGLRC hShareContext, const int *attribList); +#endif +#endif /* WGL_ARB_create_context */ + +#ifndef WGL_ARB_create_context_profile +#define WGL_ARB_create_context_profile 1 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif /* WGL_ARB_create_context_profile */ + +#ifndef WGL_ARB_create_context_robustness +#define WGL_ARB_create_context_robustness 1 +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#endif /* WGL_ARB_create_context_robustness */ + +#ifndef WGL_ARB_extensions_string +#define WGL_ARB_extensions_string 1 +typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); +#ifdef WGL_WGLEXT_PROTOTYPES +const char *WINAPI wglGetExtensionsStringARB (HDC hdc); +#endif +#endif /* WGL_ARB_extensions_string */ + +#ifndef WGL_ARB_framebuffer_sRGB +#define WGL_ARB_framebuffer_sRGB 1 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 +#endif /* WGL_ARB_framebuffer_sRGB */ + +#ifndef WGL_ARB_make_current_read +#define WGL_ARB_make_current_read 1 +#define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 +#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 +typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +HDC WINAPI wglGetCurrentReadDCARB (void); +#endif +#endif /* WGL_ARB_make_current_read */ + +#ifndef WGL_ARB_multisample +#define WGL_ARB_multisample 1 +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 +#endif /* WGL_ARB_multisample */ + +#ifndef WGL_ARB_pbuffer +#define WGL_ARB_pbuffer 1 +DECLARE_HANDLE(HPBUFFERARB); +#define WGL_DRAW_TO_PBUFFER_ARB 0x202D +#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E +#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F +#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 +#define WGL_PBUFFER_LARGEST_ARB 0x2033 +#define WGL_PBUFFER_WIDTH_ARB 0x2034 +#define WGL_PBUFFER_HEIGHT_ARB 0x2035 +#define WGL_PBUFFER_LOST_ARB 0x2036 +typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer); +typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC); +typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer); +typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +HPBUFFERARB WINAPI wglCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB hPbuffer); +int WINAPI wglReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC); +BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB hPbuffer); +BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); +#endif +#endif /* WGL_ARB_pbuffer */ + +#ifndef WGL_ARB_pixel_format +#define WGL_ARB_pixel_format 1 +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_DRAW_TO_BITMAP_ARB 0x2002 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NEED_PALETTE_ARB 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define WGL_SWAP_METHOD_ARB 0x2007 +#define WGL_NUMBER_OVERLAYS_ARB 0x2008 +#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 +#define WGL_TRANSPARENT_ARB 0x200A +#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 +#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 +#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 +#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A +#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B +#define WGL_SHARE_DEPTH_ARB 0x200C +#define WGL_SHARE_STENCIL_ARB 0x200D +#define WGL_SHARE_ACCUM_ARB 0x200E +#define WGL_SUPPORT_GDI_ARB 0x200F +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201A +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ALPHA_SHIFT_ARB 0x201C +#define WGL_ACCUM_BITS_ARB 0x201D +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_SWAP_EXCHANGE_ARB 0x2028 +#define WGL_SWAP_COPY_ARB 0x2029 +#define WGL_SWAP_UNDEFINED_ARB 0x202A +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_COLORINDEX_ARB 0x202C +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); +BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); +BOOL WINAPI wglChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#endif +#endif /* WGL_ARB_pixel_format */ + +#ifndef WGL_ARB_pixel_format_float +#define WGL_ARB_pixel_format_float 1 +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 +#endif /* WGL_ARB_pixel_format_float */ + +#ifndef WGL_ARB_render_texture +#define WGL_ARB_render_texture 1 +#define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 +#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 +#define WGL_TEXTURE_FORMAT_ARB 0x2072 +#define WGL_TEXTURE_TARGET_ARB 0x2073 +#define WGL_MIPMAP_TEXTURE_ARB 0x2074 +#define WGL_TEXTURE_RGB_ARB 0x2075 +#define WGL_TEXTURE_RGBA_ARB 0x2076 +#define WGL_NO_TEXTURE_ARB 0x2077 +#define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 +#define WGL_TEXTURE_1D_ARB 0x2079 +#define WGL_TEXTURE_2D_ARB 0x207A +#define WGL_MIPMAP_LEVEL_ARB 0x207B +#define WGL_CUBE_MAP_FACE_ARB 0x207C +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 +#define WGL_FRONT_LEFT_ARB 0x2083 +#define WGL_FRONT_RIGHT_ARB 0x2084 +#define WGL_BACK_LEFT_ARB 0x2085 +#define WGL_BACK_RIGHT_ARB 0x2086 +#define WGL_AUX0_ARB 0x2087 +#define WGL_AUX1_ARB 0x2088 +#define WGL_AUX2_ARB 0x2089 +#define WGL_AUX3_ARB 0x208A +#define WGL_AUX4_ARB 0x208B +#define WGL_AUX5_ARB 0x208C +#define WGL_AUX6_ARB 0x208D +#define WGL_AUX7_ARB 0x208E +#define WGL_AUX8_ARB 0x208F +#define WGL_AUX9_ARB 0x2090 +typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); +typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); +typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); +BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); +BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList); +#endif +#endif /* WGL_ARB_render_texture */ + +#ifndef WGL_ARB_robustness_application_isolation +#define WGL_ARB_robustness_application_isolation 1 +#define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 +#endif /* WGL_ARB_robustness_application_isolation */ + +#ifndef WGL_ARB_robustness_share_group_isolation +#define WGL_ARB_robustness_share_group_isolation 1 +#endif /* WGL_ARB_robustness_share_group_isolation */ + +#ifndef WGL_3DFX_multisample +#define WGL_3DFX_multisample 1 +#define WGL_SAMPLE_BUFFERS_3DFX 0x2060 +#define WGL_SAMPLES_3DFX 0x2061 +#endif /* WGL_3DFX_multisample */ + +#ifndef WGL_3DL_stereo_control +#define WGL_3DL_stereo_control 1 +#define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 +#define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 +#define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 +#define WGL_STEREO_POLARITY_INVERT_3DL 0x2058 +typedef BOOL (WINAPI * PFNWGLSETSTEREOEMITTERSTATE3DLPROC) (HDC hDC, UINT uState); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglSetStereoEmitterState3DL (HDC hDC, UINT uState); +#endif +#endif /* WGL_3DL_stereo_control */ + +#ifndef WGL_AMD_gpu_association +#define WGL_AMD_gpu_association 1 +#define WGL_GPU_VENDOR_AMD 0x1F00 +#define WGL_GPU_RENDERER_STRING_AMD 0x1F01 +#define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 +#define WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 +#define WGL_GPU_RAM_AMD 0x21A3 +#define WGL_GPU_CLOCK_AMD 0x21A4 +#define WGL_GPU_NUM_PIPES_AMD 0x21A5 +#define WGL_GPU_NUM_SIMD_AMD 0x21A6 +#define WGL_GPU_NUM_RB_AMD 0x21A7 +#define WGL_GPU_NUM_SPI_AMD 0x21A8 +typedef UINT (WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids); +typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, int property, GLenum dataType, UINT size, void *data); +typedef UINT (WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc); +typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id); +typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList); +typedef BOOL (WINAPI * PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC) (HGLRC hglrc); +typedef BOOL (WINAPI * PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (HGLRC hglrc); +typedef HGLRC (WINAPI * PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void); +typedef VOID (WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#ifdef WGL_WGLEXT_PROTOTYPES +UINT WINAPI wglGetGPUIDsAMD (UINT maxCount, UINT *ids); +INT WINAPI wglGetGPUInfoAMD (UINT id, int property, GLenum dataType, UINT size, void *data); +UINT WINAPI wglGetContextGPUIDAMD (HGLRC hglrc); +HGLRC WINAPI wglCreateAssociatedContextAMD (UINT id); +HGLRC WINAPI wglCreateAssociatedContextAttribsAMD (UINT id, HGLRC hShareContext, const int *attribList); +BOOL WINAPI wglDeleteAssociatedContextAMD (HGLRC hglrc); +BOOL WINAPI wglMakeAssociatedContextCurrentAMD (HGLRC hglrc); +HGLRC WINAPI wglGetCurrentAssociatedContextAMD (void); +VOID WINAPI wglBlitContextFramebufferAMD (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#endif +#endif /* WGL_AMD_gpu_association */ + +#ifndef WGL_ATI_pixel_format_float +#define WGL_ATI_pixel_format_float 1 +#define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 +#endif /* WGL_ATI_pixel_format_float */ + +#ifndef WGL_EXT_create_context_es2_profile +#define WGL_EXT_create_context_es2_profile 1 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#endif /* WGL_EXT_create_context_es2_profile */ + +#ifndef WGL_EXT_create_context_es_profile +#define WGL_EXT_create_context_es_profile 1 +#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#endif /* WGL_EXT_create_context_es_profile */ + +#ifndef WGL_EXT_depth_float +#define WGL_EXT_depth_float 1 +#define WGL_DEPTH_FLOAT_EXT 0x2040 +#endif /* WGL_EXT_depth_float */ + +#ifndef WGL_EXT_display_color_table +#define WGL_EXT_display_color_table 1 +typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id); +typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length); +typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id); +typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id); +#ifdef WGL_WGLEXT_PROTOTYPES +GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort id); +GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *table, GLuint length); +GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort id); +VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort id); +#endif +#endif /* WGL_EXT_display_color_table */ + +#ifndef WGL_EXT_extensions_string +#define WGL_EXT_extensions_string 1 +typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +const char *WINAPI wglGetExtensionsStringEXT (void); +#endif +#endif /* WGL_EXT_extensions_string */ + +#ifndef WGL_EXT_framebuffer_sRGB +#define WGL_EXT_framebuffer_sRGB 1 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 +#endif /* WGL_EXT_framebuffer_sRGB */ + +#ifndef WGL_EXT_make_current_read +#define WGL_EXT_make_current_read 1 +#define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 +typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +HDC WINAPI wglGetCurrentReadDCEXT (void); +#endif +#endif /* WGL_EXT_make_current_read */ + +#ifndef WGL_EXT_multisample +#define WGL_EXT_multisample 1 +#define WGL_SAMPLE_BUFFERS_EXT 0x2041 +#define WGL_SAMPLES_EXT 0x2042 +#endif /* WGL_EXT_multisample */ + +#ifndef WGL_EXT_pbuffer +#define WGL_EXT_pbuffer 1 +DECLARE_HANDLE(HPBUFFEREXT); +#define WGL_DRAW_TO_PBUFFER_EXT 0x202D +#define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E +#define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F +#define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 +#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 +#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 +#define WGL_PBUFFER_LARGEST_EXT 0x2033 +#define WGL_PBUFFER_WIDTH_EXT 0x2034 +#define WGL_PBUFFER_HEIGHT_EXT 0x2035 +typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer); +typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC); +typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer); +typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT hPbuffer); +int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC); +BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT hPbuffer); +BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); +#endif +#endif /* WGL_EXT_pbuffer */ + +#ifndef WGL_EXT_pixel_format +#define WGL_EXT_pixel_format 1 +#define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 +#define WGL_DRAW_TO_WINDOW_EXT 0x2001 +#define WGL_DRAW_TO_BITMAP_EXT 0x2002 +#define WGL_ACCELERATION_EXT 0x2003 +#define WGL_NEED_PALETTE_EXT 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 +#define WGL_SWAP_METHOD_EXT 0x2007 +#define WGL_NUMBER_OVERLAYS_EXT 0x2008 +#define WGL_NUMBER_UNDERLAYS_EXT 0x2009 +#define WGL_TRANSPARENT_EXT 0x200A +#define WGL_TRANSPARENT_VALUE_EXT 0x200B +#define WGL_SHARE_DEPTH_EXT 0x200C +#define WGL_SHARE_STENCIL_EXT 0x200D +#define WGL_SHARE_ACCUM_EXT 0x200E +#define WGL_SUPPORT_GDI_EXT 0x200F +#define WGL_SUPPORT_OPENGL_EXT 0x2010 +#define WGL_DOUBLE_BUFFER_EXT 0x2011 +#define WGL_STEREO_EXT 0x2012 +#define WGL_PIXEL_TYPE_EXT 0x2013 +#define WGL_COLOR_BITS_EXT 0x2014 +#define WGL_RED_BITS_EXT 0x2015 +#define WGL_RED_SHIFT_EXT 0x2016 +#define WGL_GREEN_BITS_EXT 0x2017 +#define WGL_GREEN_SHIFT_EXT 0x2018 +#define WGL_BLUE_BITS_EXT 0x2019 +#define WGL_BLUE_SHIFT_EXT 0x201A +#define WGL_ALPHA_BITS_EXT 0x201B +#define WGL_ALPHA_SHIFT_EXT 0x201C +#define WGL_ACCUM_BITS_EXT 0x201D +#define WGL_ACCUM_RED_BITS_EXT 0x201E +#define WGL_ACCUM_GREEN_BITS_EXT 0x201F +#define WGL_ACCUM_BLUE_BITS_EXT 0x2020 +#define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 +#define WGL_DEPTH_BITS_EXT 0x2022 +#define WGL_STENCIL_BITS_EXT 0x2023 +#define WGL_AUX_BUFFERS_EXT 0x2024 +#define WGL_NO_ACCELERATION_EXT 0x2025 +#define WGL_GENERIC_ACCELERATION_EXT 0x2026 +#define WGL_FULL_ACCELERATION_EXT 0x2027 +#define WGL_SWAP_EXCHANGE_EXT 0x2028 +#define WGL_SWAP_COPY_EXT 0x2029 +#define WGL_SWAP_UNDEFINED_EXT 0x202A +#define WGL_TYPE_RGBA_EXT 0x202B +#define WGL_TYPE_COLORINDEX_EXT 0x202C +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); +BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); +BOOL WINAPI wglChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#endif +#endif /* WGL_EXT_pixel_format */ + +#ifndef WGL_EXT_pixel_format_packed_float +#define WGL_EXT_pixel_format_packed_float 1 +#define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 +#endif /* WGL_EXT_pixel_format_packed_float */ + +#ifndef WGL_EXT_swap_control +#define WGL_EXT_swap_control 1 +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); +typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglSwapIntervalEXT (int interval); +int WINAPI wglGetSwapIntervalEXT (void); +#endif +#endif /* WGL_EXT_swap_control */ + +#ifndef WGL_EXT_swap_control_tear +#define WGL_EXT_swap_control_tear 1 +#endif /* WGL_EXT_swap_control_tear */ + +#ifndef WGL_I3D_digital_video_control +#define WGL_I3D_digital_video_control 1 +#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 +#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 +#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 +#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 +typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue); +BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue); +#endif +#endif /* WGL_I3D_digital_video_control */ + +#ifndef WGL_I3D_gamma +#define WGL_I3D_gamma 1 +#define WGL_GAMMA_TABLE_SIZE_I3D 0x204E +#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F +typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); +typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); +typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue); +BOOL WINAPI wglSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue); +BOOL WINAPI wglGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); +BOOL WINAPI wglSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); +#endif +#endif /* WGL_I3D_gamma */ + +#ifndef WGL_I3D_genlock +#define WGL_I3D_genlock 1 +#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 +#define WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D 0x2045 +#define WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D 0x2046 +#define WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D 0x2047 +#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 +#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 +#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A +#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B +#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C +typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC); +typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC); +typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge); +typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay); +typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnableGenlockI3D (HDC hDC); +BOOL WINAPI wglDisableGenlockI3D (HDC hDC); +BOOL WINAPI wglIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag); +BOOL WINAPI wglGenlockSourceI3D (HDC hDC, UINT uSource); +BOOL WINAPI wglGetGenlockSourceI3D (HDC hDC, UINT *uSource); +BOOL WINAPI wglGenlockSourceEdgeI3D (HDC hDC, UINT uEdge); +BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge); +BOOL WINAPI wglGenlockSampleRateI3D (HDC hDC, UINT uRate); +BOOL WINAPI wglGetGenlockSampleRateI3D (HDC hDC, UINT *uRate); +BOOL WINAPI wglGenlockSourceDelayI3D (HDC hDC, UINT uDelay); +BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay); +BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); +#endif +#endif /* WGL_I3D_genlock */ + +#ifndef WGL_I3D_image_buffer +#define WGL_I3D_image_buffer 1 +#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 +#define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 +typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags); +typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress); +typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); +typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count); +#ifdef WGL_WGLEXT_PROTOTYPES +LPVOID WINAPI wglCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags); +BOOL WINAPI wglDestroyImageBufferI3D (HDC hDC, LPVOID pAddress); +BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); +BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count); +#endif +#endif /* WGL_I3D_image_buffer */ + +#ifndef WGL_I3D_swap_frame_lock +#define WGL_I3D_swap_frame_lock 1 +typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnableFrameLockI3D (void); +BOOL WINAPI wglDisableFrameLockI3D (void); +BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *pFlag); +BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *pFlag); +#endif +#endif /* WGL_I3D_swap_frame_lock */ + +#ifndef WGL_I3D_swap_frame_usage +#define WGL_I3D_swap_frame_usage 1 +typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage); +typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetFrameUsageI3D (float *pUsage); +BOOL WINAPI wglBeginFrameTrackingI3D (void); +BOOL WINAPI wglEndFrameTrackingI3D (void); +BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#endif +#endif /* WGL_I3D_swap_frame_usage */ + +#ifndef WGL_NV_DX_interop +#define WGL_NV_DX_interop 1 +#define WGL_ACCESS_READ_ONLY_NV 0x00000000 +#define WGL_ACCESS_READ_WRITE_NV 0x00000001 +#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 +typedef BOOL (WINAPI * PFNWGLDXSETRESOURCESHAREHANDLENVPROC) (void *dxObject, HANDLE shareHandle); +typedef HANDLE (WINAPI * PFNWGLDXOPENDEVICENVPROC) (void *dxDevice); +typedef BOOL (WINAPI * PFNWGLDXCLOSEDEVICENVPROC) (HANDLE hDevice); +typedef HANDLE (WINAPI * PFNWGLDXREGISTEROBJECTNVPROC) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); +typedef BOOL (WINAPI * PFNWGLDXUNREGISTEROBJECTNVPROC) (HANDLE hDevice, HANDLE hObject); +typedef BOOL (WINAPI * PFNWGLDXOBJECTACCESSNVPROC) (HANDLE hObject, GLenum access); +typedef BOOL (WINAPI * PFNWGLDXLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); +typedef BOOL (WINAPI * PFNWGLDXUNLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglDXSetResourceShareHandleNV (void *dxObject, HANDLE shareHandle); +HANDLE WINAPI wglDXOpenDeviceNV (void *dxDevice); +BOOL WINAPI wglDXCloseDeviceNV (HANDLE hDevice); +HANDLE WINAPI wglDXRegisterObjectNV (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); +BOOL WINAPI wglDXUnregisterObjectNV (HANDLE hDevice, HANDLE hObject); +BOOL WINAPI wglDXObjectAccessNV (HANDLE hObject, GLenum access); +BOOL WINAPI wglDXLockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); +BOOL WINAPI wglDXUnlockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); +#endif +#endif /* WGL_NV_DX_interop */ + +#ifndef WGL_NV_DX_interop2 +#define WGL_NV_DX_interop2 1 +#endif /* WGL_NV_DX_interop2 */ + +#ifndef WGL_NV_copy_image +#define WGL_NV_copy_image 1 +typedef BOOL (WINAPI * PFNWGLCOPYIMAGESUBDATANVPROC) (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglCopyImageSubDataNV (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#endif +#endif /* WGL_NV_copy_image */ + +#ifndef WGL_NV_delay_before_swap +#define WGL_NV_delay_before_swap 1 +typedef BOOL (WINAPI * PFNWGLDELAYBEFORESWAPNVPROC) (HDC hDC, GLfloat seconds); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglDelayBeforeSwapNV (HDC hDC, GLfloat seconds); +#endif +#endif /* WGL_NV_delay_before_swap */ + +#ifndef WGL_NV_float_buffer +#define WGL_NV_float_buffer 1 +#define WGL_FLOAT_COMPONENTS_NV 0x20B0 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 +#define WGL_TEXTURE_FLOAT_R_NV 0x20B5 +#define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 +#define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 +#define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 +#endif /* WGL_NV_float_buffer */ + +#ifndef WGL_NV_gpu_affinity +#define WGL_NV_gpu_affinity 1 +DECLARE_HANDLE(HGPUNV); +struct _GPU_DEVICE { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD Flags; + RECT rcVirtualScreen; +}; +typedef struct _GPU_DEVICE *PGPU_DEVICE; +#define ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0 +#define ERROR_MISSING_AFFINITY_MASK_NV 0x20D1 +typedef BOOL (WINAPI * PFNWGLENUMGPUSNVPROC) (UINT iGpuIndex, HGPUNV *phGpu); +typedef BOOL (WINAPI * PFNWGLENUMGPUDEVICESNVPROC) (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); +typedef HDC (WINAPI * PFNWGLCREATEAFFINITYDCNVPROC) (const HGPUNV *phGpuList); +typedef BOOL (WINAPI * PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); +typedef BOOL (WINAPI * PFNWGLDELETEDCNVPROC) (HDC hdc); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnumGpusNV (UINT iGpuIndex, HGPUNV *phGpu); +BOOL WINAPI wglEnumGpuDevicesNV (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); +HDC WINAPI wglCreateAffinityDCNV (const HGPUNV *phGpuList); +BOOL WINAPI wglEnumGpusFromAffinityDCNV (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); +BOOL WINAPI wglDeleteDCNV (HDC hdc); +#endif +#endif /* WGL_NV_gpu_affinity */ + +#ifndef WGL_NV_multisample_coverage +#define WGL_NV_multisample_coverage 1 +#define WGL_COVERAGE_SAMPLES_NV 0x2042 +#define WGL_COLOR_SAMPLES_NV 0x20B9 +#endif /* WGL_NV_multisample_coverage */ + +#ifndef WGL_NV_present_video +#define WGL_NV_present_video 1 +DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV); +#define WGL_NUM_VIDEO_SLOTS_NV 0x20F0 +typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); +typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); +typedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +int WINAPI wglEnumerateVideoDevicesNV (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); +BOOL WINAPI wglBindVideoDeviceNV (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); +BOOL WINAPI wglQueryCurrentContextNV (int iAttribute, int *piValue); +#endif +#endif /* WGL_NV_present_video */ + +#ifndef WGL_NV_render_depth_texture +#define WGL_NV_render_depth_texture 1 +#define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 +#define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 +#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 +#define WGL_DEPTH_COMPONENT_NV 0x20A7 +#endif /* WGL_NV_render_depth_texture */ + +#ifndef WGL_NV_render_texture_rectangle +#define WGL_NV_render_texture_rectangle 1 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 +#define WGL_TEXTURE_RECTANGLE_NV 0x20A2 +#endif /* WGL_NV_render_texture_rectangle */ + +#ifndef WGL_NV_swap_group +#define WGL_NV_swap_group 1 +typedef BOOL (WINAPI * PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group); +typedef BOOL (WINAPI * PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier); +typedef BOOL (WINAPI * PFNWGLQUERYSWAPGROUPNVPROC) (HDC hDC, GLuint *group, GLuint *barrier); +typedef BOOL (WINAPI * PFNWGLQUERYMAXSWAPGROUPSNVPROC) (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMECOUNTNVPROC) (HDC hDC, GLuint *count); +typedef BOOL (WINAPI * PFNWGLRESETFRAMECOUNTNVPROC) (HDC hDC); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglJoinSwapGroupNV (HDC hDC, GLuint group); +BOOL WINAPI wglBindSwapBarrierNV (GLuint group, GLuint barrier); +BOOL WINAPI wglQuerySwapGroupNV (HDC hDC, GLuint *group, GLuint *barrier); +BOOL WINAPI wglQueryMaxSwapGroupsNV (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); +BOOL WINAPI wglQueryFrameCountNV (HDC hDC, GLuint *count); +BOOL WINAPI wglResetFrameCountNV (HDC hDC); +#endif +#endif /* WGL_NV_swap_group */ + +#ifndef WGL_NV_vertex_array_range +#define WGL_NV_vertex_array_range 1 +typedef void *(WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); +typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer); +#ifdef WGL_WGLEXT_PROTOTYPES +void *WINAPI wglAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); +void WINAPI wglFreeMemoryNV (void *pointer); +#endif +#endif /* WGL_NV_vertex_array_range */ + +#ifndef WGL_NV_video_capture +#define WGL_NV_video_capture 1 +DECLARE_HANDLE(HVIDEOINPUTDEVICENV); +#define WGL_UNIQUE_ID_NV 0x20CE +#define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF +typedef BOOL (WINAPI * PFNWGLBINDVIDEOCAPTUREDEVICENVPROC) (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); +typedef UINT (WINAPI * PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC) (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); +typedef BOOL (WINAPI * PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +typedef BOOL (WINAPI * PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglBindVideoCaptureDeviceNV (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); +UINT WINAPI wglEnumerateVideoCaptureDevicesNV (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); +BOOL WINAPI wglLockVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +BOOL WINAPI wglQueryVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); +BOOL WINAPI wglReleaseVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +#endif +#endif /* WGL_NV_video_capture */ + +#ifndef WGL_NV_video_output +#define WGL_NV_video_output 1 +DECLARE_HANDLE(HPVIDEODEV); +#define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0 +#define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1 +#define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2 +#define WGL_VIDEO_OUT_COLOR_NV 0x20C3 +#define WGL_VIDEO_OUT_ALPHA_NV 0x20C4 +#define WGL_VIDEO_OUT_DEPTH_NV 0x20C5 +#define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 +#define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 +#define WGL_VIDEO_OUT_FRAME 0x20C8 +#define WGL_VIDEO_OUT_FIELD_1 0x20C9 +#define WGL_VIDEO_OUT_FIELD_2 0x20CA +#define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB +#define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC +typedef BOOL (WINAPI * PFNWGLGETVIDEODEVICENVPROC) (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEODEVICENVPROC) (HPVIDEODEV hVideoDevice); +typedef BOOL (WINAPI * PFNWGLBINDVIDEOIMAGENVPROC) (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOIMAGENVPROC) (HPBUFFERARB hPbuffer, int iVideoBuffer); +typedef BOOL (WINAPI * PFNWGLSENDPBUFFERTOVIDEONVPROC) (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); +typedef BOOL (WINAPI * PFNWGLGETVIDEOINFONVPROC) (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetVideoDeviceNV (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); +BOOL WINAPI wglReleaseVideoDeviceNV (HPVIDEODEV hVideoDevice); +BOOL WINAPI wglBindVideoImageNV (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); +BOOL WINAPI wglReleaseVideoImageNV (HPBUFFERARB hPbuffer, int iVideoBuffer); +BOOL WINAPI wglSendPbufferToVideoNV (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); +BOOL WINAPI wglGetVideoInfoNV (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#endif +#endif /* WGL_NV_video_output */ + +#ifndef WGL_OML_sync_control +#define WGL_OML_sync_control 1 +typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); +typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator); +typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); +typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); +typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); +typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); +BOOL WINAPI wglGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator); +INT64 WINAPI wglSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); +INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); +BOOL WINAPI wglWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); +BOOL WINAPI wglWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); +#endif +#endif /* WGL_OML_sync_control */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/engine/code/winquake.h b/engine/code/winquake.h new file mode 100644 index 0000000..fc2634f --- /dev/null +++ b/engine/code/winquake.h @@ -0,0 +1,183 @@ +/* +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. + +*/ +// winquake.h: Win32-specific Quake header file + +#pragma warning( disable : 4229 ) // mgraph gets this + +#include +#define WM_MOUSEWHEEL 0x020A + +#ifndef SERVERONLY +#include +#include +#ifndef GLQUAKE +#include +#endif +#endif + +extern HINSTANCE global_hInstance; +extern int global_nCmdShow; + +#ifndef SERVERONLY + +extern LPDIRECTDRAW lpDD; +extern qboolean DDActive; +extern LPDIRECTDRAWSURFACE lpPrimary; +extern LPDIRECTDRAWSURFACE lpFrontBuffer; +extern LPDIRECTDRAWSURFACE lpBackBuffer; +extern LPDIRECTDRAWPALETTE lpDDPal; +extern LPDIRECTSOUND pDS; +extern LPDIRECTSOUNDBUFFER pDSBuf; + +extern DWORD gSndBufSize; +//#define SNDBUFSIZE 65536 + +void VID_LockBuffer (void); +void VID_UnlockBuffer (void); + +#endif + +typedef enum {MS_WINDOWED, MS_FULLSCREEN, MS_FULLDIB, MS_UNINIT} modestate_t; + +// jkrige - moved to winquake.h (here) +#define MAX_MODE_LIST 30 +#ifdef GLQUAKE +#define BASEWIDTH 640 +#define BASEHEIGHT 480 +#define BASEFOV 90 + +//#define SCALEHEIGHT 540.0f +//#define SCALEWIDTH SCALEHEIGHT / 0.5625f // / 0.75f + +#else +#define BASEWIDTH 320 +#define BASEHEIGHT 240 // jkrige - was 200 + +//#define SCALEWIDTH 320 +//#define SCALEHEIGHT 240 // jkrige - was 200 +#endif +// jkrige - moved to winquake.h (here) + +// jkrige - moved to winquake.h (here) +#ifdef GLQUAKE +typedef struct { + modestate_t type; + int width; + int height; + int modenum; + int dib; + int fullscreen; + int bpp; + int halfscreen; + // jkrige - increased maximum video mode descriptions + char modedesc[33]; + //char modedesc[17]; + // jkrige - increased maximum video mode descriptions +} vmode_t; +#else +typedef struct { + modestate_t type; + int width; + int height; + int modenum; + int mode13; + int stretched; + int dib; + int fullscreen; + int bpp; + int halfscreen; + char modedesc[13]; +} vmode_t; +#endif +// jkrige - moved to winquake.h (here) + +// jkrige - scale2d +#ifdef GLQUAKE +extern qpic_t *conback; +#endif +extern vmode_t modelist[MAX_MODE_LIST]; +// jkrige - scale2d + +extern modestate_t modestate; + +extern HWND mainwindow; +extern qboolean ActiveApp, Minimized; + +//extern qboolean WinNT; // jkrige - remove windows version check + +int VID_ForceUnlockedAndReturnState (void); +void VID_ForceLockState (int lk); + +void IN_ShowMouse (void); +void IN_DeactivateMouse (void); +void IN_HideMouse (void); +void IN_ActivateMouse (void); +void IN_RestoreOriginalMouseState (void); +void IN_SetQuakeMouseState (void); +void IN_MouseEvent (int mstate); + +extern qboolean winsock_lib_initialized; + +extern cvar_t _windowed_mouse; + +// jkrige - scale2d +extern cvar_t vid_mode; +// jkrige - scale2d + + +// jkrige - non power of two +extern cvar_t gl_texture_non_power_of_two; +// jkrige - non power of two + + +extern int window_center_x, window_center_y; +extern RECT window_rect; + +extern qboolean mouseinitialized; +extern HWND hwnd_dialog; + +extern HANDLE hinput, houtput; + +void IN_UpdateClipCursor (void); +void CenterWindow(HWND hWndCenter, int width, int height, BOOL lefttopjustify); + +void S_BlockSound (void); +void S_UnblockSound (void); + +void VID_SetDefaultMode (void); + +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); diff --git a/engine/code/winquake.rc b/engine/code/winquake.rc new file mode 100644 index 0000000..c52e44e --- /dev/null +++ b/engine/code/winquake.rc @@ -0,0 +1,108 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON2 ICON "quake.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOGEX 0, 0, 155, 72 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_VISIBLE +EXSTYLE WS_EX_TOOLWINDOW +FONT 16, "Times New Roman", 0, 0, 0x1 +BEGIN + CONTROL IDB_BITMAP1,IDC_STATIC,"Static",SS_BITMAP,0,0,155,72 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_QUAKE1 BITMAP "quake.bmp" + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/engine/code/world.c b/engine/code/world.c new file mode 100644 index 0000000..b075323 --- /dev/null +++ b/engine/code/world.c @@ -0,0 +1,1023 @@ +/* +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. + +*/ +// 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 dclipnode_t box_clipnodes[6]; +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) + { + // jkrige - MOVETYPE_PUSH fix + //Sys_Error ("MOVETYPE_PUSH with a non bsp model"); + Sys_Error ("SOLID_BSP with a non bsp model"); + // jkrige - MOVETYPE_PUSH fix + } + + 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) + { + 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); + + 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; + + 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 + +#ifdef QUAKE2 + if (ent->v.solid == SOLID_BSP && (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) ) + { // expand for rotation + float max, v; + int i; + + max = 0; + for (i=0 ; i<3 ; i++) + { + v =fabs( ent->v.mins[i]); + if (v > max) + max = v; + v =fabs( ent->v.maxs[i]); + if (v > max) + max = v; + } + + for (i=0 ; i<3 ; i++) + { + ent->v.absmin[i] = ent->v.origin[i] - max; + ent->v.absmax[i] = ent->v.origin[i] + max; + } + } + else +#endif + { + 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 + +=============================================================================== +*/ + +#if !id386 + +/* +================== +SV_HullPointContents + +================== +*/ +int SV_HullPointContents (hull_t *hull, int num, vec3_t p) +{ + float d; + dclipnode_t *node; + 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; +} + +#endif // !id386 + + +/* +================== +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) +{ + dclipnode_t *node; + 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); + + + // jkrige - rotating bmodels +/*#ifdef QUAKE2 + // rotate start and end into the models frame of reference + if (ent->v.solid == SOLID_BSP && + (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) ) + { + vec3_t a; + vec3_t forward, right, up; + vec3_t temp; + + AngleVectors (ent->v.angles, forward, right, up); + + VectorCopy (start_l, temp); + start_l[0] = DotProduct (temp, forward); + start_l[1] = -DotProduct (temp, right); + start_l[2] = DotProduct (temp, up); + + VectorCopy (end_l, temp); + end_l[0] = DotProduct (temp, forward); + end_l[1] = -DotProduct (temp, right); + end_l[2] = DotProduct (temp, up); + } +#endif*/ + // rotate start and end into the models frame of reference + /* ported from Hexen II + if (ent->v.solid == SOLID_BSP && + (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) ) + { + vec3_t a; + vec3_t forward, right, up; + vec3_t temp; + + AngleVectors (ent->v.angles, forward, right, up); + + VectorCopy (start_l, temp); + start_l[0] = DotProduct (temp, forward); + start_l[1] = -DotProduct (temp, right); + start_l[2] = DotProduct (temp, up); + + VectorCopy (end_l, temp); + end_l[0] = DotProduct (temp, forward); + end_l[1] = -DotProduct (temp, right); + end_l[2] = DotProduct (temp, up); + } + */ + // jkrige - rotating bmodels + + +// trace a line through the apropriate clipping hull + SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace); + + + // jkrige - rotating bmodels +/*#ifdef QUAKE2 + // rotate endpos back to world frame of reference + if (ent->v.solid == SOLID_BSP && + (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) ) + { + vec3_t a; + vec3_t forward, right, up; + vec3_t temp; + + if (trace.fraction != 1) + { + VectorSubtract (vec3_origin, ent->v.angles, a); + AngleVectors (a, forward, right, up); + + VectorCopy (trace.endpos, temp); + trace.endpos[0] = DotProduct (temp, forward); + trace.endpos[1] = -DotProduct (temp, right); + trace.endpos[2] = DotProduct (temp, up); + + VectorCopy (trace.plane.normal, temp); + trace.plane.normal[0] = DotProduct (temp, forward); + trace.plane.normal[1] = -DotProduct (temp, right); + trace.plane.normal[2] = DotProduct (temp, up); + } + } +#endif*/ + // rotate endpos back to world frame of reference + /* ported from Hexen II + if (ent->v.solid == SOLID_BSP && + (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) ) + { + vec3_t a; + vec3_t forward, right, up; + vec3_t temp; + + if (trace.fraction != 1) + { + VectorSubtract (vec3_origin, ent->v.angles, a); + AngleVectors (a, forward, right, up); + + VectorCopy (trace.endpos, temp); + trace.endpos[0] = DotProduct (temp, forward); + trace.endpos[1] = -DotProduct (temp, right); + trace.endpos[2] = DotProduct (temp, up); + + VectorCopy (trace.plane.normal, temp); + trace.plane.normal[0] = DotProduct (temp, forward); + trace.plane.normal[1] = -DotProduct (temp, right); + trace.plane.normal[2] = DotProduct (temp, up); + } + } + */ + // jkrige - rotating bmodels + + +// 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/engine/code/world.h b/engine/code/world.h new file mode 100644 index 0000000..cddb94f --- /dev/null +++ b/engine/code/world.h @@ -0,0 +1,78 @@ +/* +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. + +*/ +// 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/engine/code/wqreadme.txt b/engine/code/wqreadme.txt new file mode 100644 index 0000000..9ba2f1b --- /dev/null +++ b/engine/code/wqreadme.txt @@ -0,0 +1,1119 @@ +-------------------------- +| wqreadme.txt | +| WinQuake documentation | +| 3/21/97 | +-------------------------- + +WinQuake (WQ) is a native Win32 version of Quake, and will run on +either Win95 or Windows NT 4.0 or later. It is designed to take +advantage of whatever enhanced video, sound, and input capabilities +(such as DirectX or VESA VBE video modes) are present, but has +fallback functionality so it can run on any Win95 or NT 4.0 or later +system, even if neither DirectX nor VESA VBE is available. You may +experience problems running WQ on some systems, because driver and +operating-system support for game functionality are not yet mature +under Win32, and many bugs and incompatibilities remain in those +components. If you encounter what seems to be a bug, first please +check through the list of known problems, below. If your problem +doesn't appear on the list, please fill out and submit the WQ bug +report at http://www.idsoftware.com/contact/. + +The material accompanying Quake is the reference for all +non-Windows-related matters concerning WinQuake; in terms of gameplay, +WQ is the same as Quake. This file contains Windows-related +information only. + +The rest of this document is organized as follows: + +Installing and running WinQuake +Common problems and workarounds +A bit about how WQ video works +Video command-line switches +A bit about how WQ sound works +Sound command-line switches +Notes on networking +Notes on the mouse +Log of changes to documentation +Special thanks + + +----------------------------------- +| Installing and running WinQuake | +----------------------------------- + +In order to run WinQuake, you must first have Quake installed. +Assuming Quake is installed in the standard directory, c:\quake, +unzip the WinQuake zip file into c:\quake. The following files +from the zip file must be present in order for WQ to run: + +winquake.exe +pmpro16.dll +pmpro32.dll +wdir16.dll +wdir32.dll +wdirnop.com +wdirnop.pif + +Then you can run WinQuake by making c:\quake the current directory, +typing "winquake" and pressing the Enter key. Alternatively, you can +use wq.bat to run WinQuake. The wq batch file requires one parameter +describing how to configure WQ for performance; just type "wq" to get +a list of the six options. The first of the six options is + +wq fast + +This is the same as typing "winquake"; this runs WinQuake in an +aggressive configuration that is likely to yield the best performance +if it runs successfully on your system, but which has a risk of +causing WinQuake or even your system to crash if there are bugs or +incompatibilities in your video or sound drivers. Alternatively, you +can use + +wq safe + +to run WinQuake in a conservative configuration, likely to run +on almost all machines with no problems, but possibly with slower +graphics, fewer high-resolution modes, and delayed sound. Or you +can run + +wq verysafe + +to run WinQuake in a very conservative configuration that is pretty +much guaranteed to run, but will probably have slow performance, and +will have no sound. Two other options are + +wq fastvid + +which has maximum video performance, but greater sound latency (delay +until the sound is heard), and + +wq fastsnd + +which uses more conservative video modes, but low-latency sound. + +(One odd note is that DirectSound has much lower-latency sound than +wave sound, but is currently quite a bit slower overall. Thus you +may find that "wq fastvid" is actually faster, by as much as 5-10%, +than "wq fast"; however, it may not feel faster, because the sound +will lag.) + +Finally, you can use + +wq max + +which is the same as wq fast, but turns on DirectInput, which +provides more responsive mouse control, but does not work properly +on all systems. + +Note that DirectX is not required for WQ to run, but WQ will +automatically take advantage of DirectSound and DirectDraw if they +are present. If DirectSound is not present, there will generally be +considerable sound latency (sound will become audible several hundred +milliseconds after the event that caused it). Note also that there +are currently no true DirectSound drivers for Windows NT, so WQ will +always run using wave output on NT, and will consequently have lagged +sound. See below for information about obtaining DirectX if you do +not have it. + +Note that VESA VBE modes aren't required for WQ to run, but WQ will +automatically make VESA modes available if they're present. Your BIOS +may already have VESA VBE 2.0 support built in, but most BIOSes +don't. Worse, some BIOSes do have VESA VBE 2.0 built-in, but have +buggy implementations, which may prevent you from being able to run +the faster configurations of WQ. An easy way to get reliable VESA 2.0 +support is by obtaining SciTech Display Doctor; see below for +further information. WQ can also use VBE/AF 1.0 and greater modes; +again, SciTech Display Doctor is the commonest way to get VBE/AF +support. + +Note that winquake -dedicated completely replaces the old winded +dedicated Win32 server, which is now obsolete. + +WinQuake normally uses half the physical memory in your system for its +heap, but not less than 8.5 Mb and not more than 16 Mb. You can +override this with "-heapsize n", where n is the amount of memory to +allocate for the heap, in Kb. + +To use the joystick, you must bring down the console by pressing the +tilde ('~') key, and type "joystick 1"; you can disable the +joystick with "joystick 0" at any time. The joystick setting +remains in effect for subsequent WinQuake sessions until changed, so +you only need to do joystick 1 once to enable the joystick. If the +joystick somehow causes problems that keep you from being able to run +WinQuake at all, you can start WinQuake -nojoy to complete disable the +joystick for that session. + + +----------------------------------- +| Common problems and workarounds | +----------------------------------- + +WQ crashes or won't run +----------------------- + +If WQ refuses to run or crashes on your system, try running +it using "wq safe" or "wq verysafe". Or you can use command-line +switches: + +winquake -nodirectdraw -nowindirect -wavonly + +This will almost certainly solve your problem; however, it may result +in lagged sound (a long delay from action to hearing the sound), may +result in fewer or slower high-res video modes, and the mouse may be +somewhat less responsive. If this does work, you can try removing +each of the command-line switches until you identify the one that +fixes the problem, thereby sacrificing as little functionality as +possible. + +If the above command line does not fix your problems, try: + +winquake -dibonly -nosound + +which forces WQ into silent operation with bare-bones video support +and no use of DirectInput for mouse input (the normal Windows mouse +APIs are used instead). Again, if this works, try removing switches +until you identify the needed one. + +Both of the above command lines are quick fixes. Often, the problem +is caused by outdated or buggy DirectX drivers or code, and can +frequently be completely fixed simply by installing the latest +Microsoft-supplied version of DirectX, which you may be able to find +on http://www.microsoft.com/mediadev/download/directx.exe, although +the availability and location of the DirectX file changes +periodically; note that at last check, this is a 3.4 Mb file. (Be +aware, though, that sometimes Microsoft's DirectX drivers don't +support features that the manufacturers' drivers do support, such as +display refresh rate control.) + +One known problem of this sort involves the current SB16 drivers from +Creative Labs, which cause WQ to crash on some machines. The +DirectSound drivers from Microsoft, available via the above-mentioned +URL, fix this problem. + +It can also sometimes help to get the latest Windows drivers for your +video adapter or sound card (although as the SB16 example indicates, +this is not always a good idea), and for video boards that have flash +BIOSes, it can sometimes help to get the latest BIOS upgrade. + + +How do I select fullscreen or windowed WQ operation? +---------------------------------------------------- +Check out WQ's new, spiffy Video menu, accessible from the Options +menu. There are now two types of modes listed, windowed and +fullscreen. You can make any of these modes the current and/or +default mode, just as in DOS Quake. If you make a windowed mode the +default, WQ will still briefly start up in fullscreen mode, then +switch to windowed; if this is a problem, use the -startwindowed +command-line switch. More complete video control is available +through the console, as described in the "A bit about how WQ video +works" section, below. + + +Gee, I wish I could use a mouse to play WQ with in a window +----------------------------------------------------------- +You can! While in a windowed mode, go to the Options menu. At the +bottom, you'll find a new selection that lets you choose to have the +mouse active when you're in a window. Of course, if you do this, +you'll have to use the keyboard (Alt-Tab, the Windows key, Ctrl-Esc, +Alt-Esc, or Shift-Alt-Tab) to switch away from WQ. + + +Serial/modem menu is missing +---------------------------- +WQ currently does not support direct connect serial or modem play. + + +DOS Quake reports unknown variables on startup after running WQ +--------------------------------------------------------------- +WQ uses some console variables that do not exist in DOS Quake, and +some of these are automatically archived in config.cfg when you exit +WQ. If you then start DOS Quake, DOS Quake will complain that it +doesn't recognize those variables. You will also lose the settings +of these variables when you return to WQ. Apart from losing the +settings, this is harmless; ignore it. + + +Problems running WQ on NT 3.51 +------------------------------ +NT 3.51 isn't supported by WQ. + + +WQ crashes while switching modes or Alt-Tabbing +----------------------------------------------- +So far, all cases of this seem to be tied to Creative Lab's SB16 sound +drivers, and have been fixed by getting the latest DirectX drivers, as +described above. Alternatively, you should be able to fix this either +by not switching modes or Alt-Tabbing, or by running -wavonly to +disable DirectSound support. + + +WQ sometimes runs pretty slowly fullscreen +------------------------------------------ +There are several possible reasons for this, starting with "You have a +slow computer." Assuming that's not the case, if you don't have +either DirectDraw or SciTech Display Doctor installed (see the "A bit +about how WQ video works" section), it would probably be a good thing +to install one or the other, because slow operation can be a result +of slow copying or stretching of pixels to the screen by a Windows +driver, something that's eliminated by both DirectDraw and Display +Doctor. You can also sometimes get a faster 320x200 mode on Win95 by +doing vid_describemodes, then using vid_mode to select a non-VGA +320x200 mode, as described in the "A bit about how WQ video works" +section. + +You can also try using a primary sound buffer on Win95 (this doesn't +work on NT) by using the -primarysound command-line switch; this can +improve performance by several percent, but does not work on all +systems, and can result in odd sound effects on some systems when +minimizing WQ or switching the focus away from it. If you use this +switch, please don't report sound bugs; it's in there purely for you +to use if it helps you, and we know it has problems on many systems. +Finally, you can use -wavonly to select wave sound; this will increase +your sound latency (sounds will be heard later than they should), but +allows WQ to run 5-10% faster on some systems. That's about all you +can do to speed up fullscreen WQ on Win95, other than shrinking the +active area of the screen with the screen size control in the Options +menu. + +NT 4.0 comes with DirectX installed, but doesn't have any resolutions +lower than 640x480. In order to support a lower-resolution 320x240 +mode, WQ has NT double each pixel in both directions to get enough +pixels for 640x480. The extra stretching costs some performance, the +result being that NT can seem sluggish on all but high-end Pentiums +and Pentium Pros. (In fact, depending on the quality of your driver's +stretching code, it can sometimes be faster to run WQ at 640x480 than +320x240-stretched on NT.) One thing that can help on NT is switching +to 640x480, then using the Options menu to shrink the active area of +the screen. + +A common cause of slowness running in a window is having the desktop +run in 16- or 32-bpp mode. WQ is an 8-bpp application, and it slows +things down if pixels have to be translated from 8-bpp to 16- or +32-bpp. (Note that this is generally a problem only when running in a +window; fullscreen apps rarely suffer from this.) + + +Sound is sluggish on NT +----------------------- +NT doesn't have any real DirectSound drivers yet, so there's no way to +do quick-response sound on NT. When DirectSound drivers for NT +appear, WQ's sound should automatically be snappier. + + +Sound breaks up or gets choppy, especially in menus +--------------------------------------------------- +This is generally a sign that WQ's frame rate is too low on your +system. Try reducing resolution or shrinking the active area of the +screen. In some circumstances, it may help to set the console +variable _snd_mixahead to a larger value. + + +The color black doesn't change with palette flashes sometimes +------------------------------------------------------------- +Normally, DirectDraw lets WQ change all 256 colors, so when a palette +flash happens, we can change all the colors, including black. +However, on NT DirectDraw currently doesn't allow changing black; +likewise, on both NT and Win95, black can't be changed in a window, +either a normal window or fullscreen. Consequently, in some modes and +in a window, some parts of the WQ screen (such as the sigils on the +status bar and the spray where a shotgun blast hits) stay black when +the palette flashes. There is no workaround. + + +Problems can result if Office shortcut bar is running +----------------------------------------------------- +Various odd behaviors, especially with sound, have been reported if +the Office shortcut bar is running while WQ is running. If you +experience odd problems, you might try shutting down the Office +shortcut bar and see if that fixes anything. + + +Other apps fail to play sound while WinQuake is running +------------------------------------------------------- +The sound hardware is currently not a fully shareable resource on +Win32. Consequently, while WQ is running, it always has the sound +hardware allocated to itself, to make sure that sound is never lost to +another app. This means that normally (when WQ is using DirectSound), +apps that use wave sound (most non-game apps) will not be able to play +sound while WQ is running, even if WQ is minimized or not the active +app, although other DirectSound apps will be able to play sound when +WQ is not the active app. If WQ is using wave sound rather than +DirectSound (either because -wavonly is used on the command line, or +because there is no DirectSound driver, as is always the case on NT), +then no other app will be able to play any sound while WQ is running, +period. + + +WQ doesn't have quite the right colors when it’s not the active app +------------------------------------------------------------------- +We're working on fixing this. But WQ puts everything back again as +soon as it is reactivated, and anyway, when it’s not active, you can’t +actually do anything in WQ, so it doesn’t really matter anyway, right? + + +Desktop is weird colors when WQ runs windowed +--------------------------------------------- +WQ needs all 256 colors to look right and run fast, which causes it to +have to change some of the 20 colors used to draw the desktop. + + +Sometimes Permedia boards crash unless -nowindirect is used +----------------------------------------------------------- +It looks like this is probably a Permedia driver bug, so it might help +if you get the most recent drivers. + + +Right-click on WQ button in task bar to close doesn’t work as expected +---------------------------------------------------------------------- +In some modes, right-clicking on the WQ task bar button doesn't work +the way you'd expect. We're trying to fix this, but if it's a +problem, don't right-click. + + +Screen saver never kicks in when running WQ fullscreen +------------------------------------------------------ +It does work windowed, but when WinQuake is fullscreen, it completely +owns the screen and doesn't share it with anyone, even the +screensaver. If you use Alt-Tab to minimize WQ, the screensaver will +then be enabled, so Alt-Tab away from WQ if you're leaving your +computer alone for a while and want the screensaver to be able to kick +in. + + +WQ doesn’t work in a window in 16-color mode +-------------------------------------------- +That’s 16 *colors*, not 16-bpp. If you’re still running a 16-color +desktop, run WQ fullscreen. + + +Can't minimize window while mouse active +---------------------------------------- +When running in a window with the mouse active as a WQ input device, +there is no easy way to minimize the window, because the system menu +can't be brought up from the keyboard (because some of you use Alt +and Spacebar for playing the game), and the mouse can't be used to +manipulate the window because it's controlling WQ. To minimize, you +can disable the mouse for WQ and use it to minimize the window. Or +on Win95 you can Alt-Tab away from WQ, then use the mouse to +minimize (this doesn't work on NT, where clicking on the window +controls just reactivates WQ). Or you can bind a key to the +vid_minimize command, as in + +bind m "vid_minimize" + +and press that key to minimize the window. + + +Window controls don't work on NT when mouse enabled +--------------------------------------------------- +When running in a window on NT with the mouse enabled (so you can use +the mouse to play WQ), if you Alt-Tab away from WQ, then use the mouse +to click on the WQ system menu control, or the minimize, maximize, or +close controls, the controls are ignored and WQ just reactivates. + + +Mouse sometimes vanishes in system menu on Win95 +------------------------------------------------ +On Win95, if WQ is running in a window with the mouse enabled (so you +can use the mouse to play WQ), if you Alt-Tab away, then click on the +system menu, the menu comes up, but the mouse vanishes. However, you +can still use the keyboard to select system menu items, or to exit +the system menu. + + +WQ behaves oddly if Scandisk starts defragmenting +------------------------------------------------- +If WQ is running fullscreen on Win95 when Scandisk starts an automatic +defragging, WQ is forced to minimize, and when it is brought back up, +may either be in a strange mode where it runs one frame for each +keystroke (in which case Alt-Tab generally fixes things), or may hang +the system. We don't know what the problem is right now, but you may +want to make sure you don't leave WQ sitting there fullscreen +overnight if you have automatic defragging. + + +Hang reported with zero sound volume +------------------------------------ +When sound is turned all the way down via the WQ menus, hangs have +been reported. + + +Joystick worked fine with earlier versions of WinQuake but not now +------------------------------------------------------------------ +The joystick was enabled by default in earlier versions of +WinQuake, but quite a few people reported serious problems that +forced them to disable the joystick--even some people who didn't +have a joystick attached. Since most people don't have joysticks, +we've decided to disable the joystick by default, and let people +who do want to use it set joystick 1 in the console (WinQuake +remembers this setting, so this only needs to be done once). + + +WQ runs very slowly when it has the focus under NT +-------------------------------------------------- +In one case, WQ ran very slowly when it had the focus, but fast when +it didn't (obviously this is only visible in windowed modes). The +problem turned out to be that NT had a Sidewinder 3D Pro joystick +driver installed; when the driver was removed, things were fine. +If you see a similar problem, check whether WQ is detecting that +your system has a joystick when you don't think it should; if so, +try doing "joystick 0", or -nojoy on the command line, and see if +that fixes it. If so, there's something flaky in your system +joystick setup. + + +Joystick doesn't seem calibrated properly +----------------------------------------- +WQ relies on the information about your joystick stored in the +system registry. If the joystick seems miscalibrated, run the +joystick applet and recalibrate and see if that fixes things. + + +Playdemo fails across multiple levels +------------------------------------- +If "record" is used to record a client-side demo, bad things will +happen on playback via playdemo if a level change is recorded. +(Timedemo works fine.) This is unfortunate, but WinQuake +internals make this not fixable without a good chance of +breaking something more important, so it'll have to stay this way. + + +Alt-Tab fullscreen only works sometimes +--------------------------------------- +I know it seems that way, but actually the trick is that on Win95 +it only works if you let go of Tab before you let go of Alt. +This is due to a Windows quirk involving what key sequences are +passed along, so you'll have to work around it by remembering to +let go of Tab first. + + +MS-DOS windows get scrunched on Alt-Tab +--------------------------------------- +This is a quirk of Windows; when you run WinQuake in a low-res +mode, sometimes when you exit WinQuake or Alt-Tab back to the +desktop, any open MS-DOS windows will be scrunched down to the +size of the low-res mode. There is no known workaround. + + +Dprint in progs doesn't work +---------------------------- +Dprint means "developer print," so it only works if the developer +console variable is set to 1. It was a bug in earlier versions that +it worked even when developer was set to 0. + + +Some DirectDraw modes flicker badly and look wrong +-------------------------------------------------- +Page flipping doesn't work properly in some modes on some +systems, particularly when using some DirectDraw modes. You +can work around this by setting the console variable +vid_nopageflip to 1, then setting the desired mode (note +that the vid_nopageflip setting does not take effect until +the next mode set after the setting is changed). Bear in +mind, though, that the vid_nopageflip setting is remembered +until it is explicitly changed again, meaning that once you +change it, it thereafter applies to all modes, even if you +exit and restart WinQuake. + + +The Windows key doesn't do anything fullscreen on Win95 +------------------------------------------------------- +True. This is a minor bug we haven't figured out how to fix yet. +You'll have to use Ctrl-Esc, Alt-Tab, or Alt-Esc to switch away. + + +My default mode is windowed, but WQ goes fullscreen first +--------------------------------------------------------- +For internal reasons, WQ has to pick a single mode to always +initialize when it starts up, before it sets whatever default you've +selected. We've chosen fullscreen mode, because that's the way most +people will play. If this is a problem for you, however, you can +run WQ with the -startwindowed command-line parameter. + + +Some high-resolution video modes flicker or fail to initialize +-------------------------------------------------------------- +We think these problems are all fixed, but if not, they have to +do with triple-buffering in some modes on some DirectDraw drivers. +If you encounter this problem, either don't use the problem modes +or try using the -notriplebuf command-line parameter to turn off +triple buffering. Note, though, that turning off triple-buffering +can reduce performance in some modes, so do this only if needed. + + +Right-click doesn't work right on minimized WinQuake +---------------------------------------------------- +If you right-click on minimized WinQuake on the task bar, the +Close selection in the right-click menu doesn't work; you have +to restore WQ before you can exit it. Also, the cursor vanishes +over the right-click menu, although it still works. + + +The screen briefly blanks when you exit WQ +------------------------------------------ +We're trying to fix this, but it's not harmful, just a mite ugly. + + +QBENCH doesn't work with WinQuake +--------------------------------- +We've had a report that QBENCH doesn't work with WinQuake, but +haven't had a chance to look into it yet. + + +MWAVE sound loses focus +----------------------- +We've had a report that on a ThinkPad with MWAVE sound, WQ loses +sound focus (and thus sound) every few seconds. + + +Desktop doesn't reset to proper resolution on WQ exit +----------------------------------------------------- +We've had a report that on exiting WQ, the desktop didn't reset +to the proper dimensions. This may be a bug with the Matrox +drivers, but we're not sure. If it's a problem and newer +drivers don't fix it, you can run -dibonly, which solves the +problem but can cost some performance. + + +Palette goes bad periodically on #9 Imagine card +------------------------------------------------ +There's only one report of this, so maybe it's a flaky board, +or maybe it's a driver bug. Newer drivers might help. + + +System with Packard Bell sound card III crashes on CapsLock +----------------------------------------------------------- +This appears to be the result of buggy DirectSound drivers; +-wavonly makes the problem go away. + + +Dvorak keyboard mapping ignored +------------------------------- +WQ is hardwired for QWERTY. + + +Cursor messed up after running WQ +--------------------------------- +This is a Windows driver bug; the driver isn't restoring the +cursor properly on return from fullscreen WQ to the desktop. +Try newer drivers. + + +Dedicated server runs very slowly while typing at console +--------------------------------------------------------- +When you type at a dedicated server's console, the game runs +very slowly for everyone who's connected. + + +Ctrl-Alt-Del on NT sometimes doesn't allow return to WQ +------------------------------------------------------- +This happens on some machines while running WQ fullscreen. +If you experience this problem, the only workaround is not +to press Ctrl-Alt-Del while fullscreen; Alt-Tab away first. + + +Many fast Alt-Tabs on Win95 sometimes disable WQ input +------------------------------------------------------ +If you Alt-Tab fast lots of times on Win95 with WQ running +fullscreen, sometimes you end up in fullscreen WQ, with the +game not accepting any keyboard input (so there's no way to +exit). The only workaround is to not do lots of fast +Alt-Tabs (why you'd want to, I'm not sure). + + + +---------------------------------- +| A bit about how WQ video works | +---------------------------------- + +WQ has the built-in ability to draw into windows (both normal, framed +desktop windows and fullscreen, borderless windows). It also has +built- in support for VGA 320x200 graphics, and supports DirectDraw, +VESA VBE 2.0 and VESA VBE/AF (Accelerator Functions) graphics modes, +if those are available. + +WQ does not require DirectDraw, but in order for DirectDraw modes to +be available, you must have DirectDraw installed; some systems come +with it preinstalled, but if it's not on your system, you can download +it from http://www.microsoft.com/mediadev/download/directx.exe (the +exact URL may vary), and install it. + +WQ does not require VESA VBE, but in order for VESA VBE modes to be +available, your graphics card must be VESA VBE 2.0 or VBE/AF +compliant; a VESA driver can either be built into the BIOS of your +graphics card, or loadable via software. If you don't have a VESA VBE +driver, Scitech Display Doctor, available from Scitech Software, will +update most graphics cards to VESA VBE 2.0 and VBE/AF. + + +SciTech Display Doctor +---------------------- +If you are having problems with your video drivers, or if you would +like to take a shot at improving your video performance in WQ, you may +want to try out SciTech Display Doctor (SDD). SDD works on just about +any graphics card and it can do several things that can make WQ run +better on your system: + +1. It will update your graphics card to be compatible with VESA VBE +2.0 and VESA VBE/AF (Accelerator Functions). These modes will usually +give you the best performance in WQ (which is often but not always +faster than your current performance). + +2. It creates low-resolution modes on your graphics card. +Low-resolution video modes (such as 320x240, 400x300 and 512x384) +allow you to adjust the level of detail in WQ so you can get the best +balance between performance and image quality. + +The latest version of SciTech Display Doctor can be obtained from the +following locations: + +www: http://www.scitechsoft.com +ftp: ftp.scitechsoft.com +CIS: GO SCITECH +AOL: Keyword SciTech + +SciTech can be contacted at: + +email: info@scitechsoft.com + +SciTech Software, Inc. +505 Wall Street +Chico, CA 95926-1989 +916-894-8400 +916-894-9069 FAX + + +Video modes supported in Win95 +------------------------------ +What all this means is that on Win95, WQ will always be able to run in +the following modes: + +1) in a window +2) fullscreen 320x200 VGA mode 0x13 +3) fullscreen high-resolution of some sort + +Category #3 can be any of several configurations. On Win95, if either +DirectDraw or VESA VBE modes are available, then all the DirectDraw +and VESA modes will be presented as high-res choices. (320x200 will +always default to VGA mode 0x13.) In the case that a given resolution +is supported by both DirectDraw and VESA, the VESA mode will be used. +(However, the command-line switch -nowindirect can turn off VESA modes +entirely.) If neither DirectDraw nor VESA modes are available, then +high-resolution modes will be provided by using fullscreen, borderless +windows in whatever resolutions the Windows driver supports, usually +starting at 640x480 and going up. + + +Video Modes Supported in Windows NT +----------------------------------- +NT is similar but not identical, because neither VESA VBE modes nor +VGA mode 0x13 are available. On NT, WQ will always be able to run in +the following modes: + +1) in a window +2) fullscreen high-resolution of some sort + +On NT, category #2 can be one of two configurations. If DirectDraw +modes are available, then those will be the high-res choices; +otherwise, fullscreen, borderless windows will be used in whatever +resolutions the driver supports, usually starting at 640x480 and going +up. Because there is normally no low-resolution mode such as 320x200 +or 320x240 on NT, a pseudo low-res mode is created by rendering at +320x240, then stretching the image by doubling it in each direction +while copying it to a 640x480 screen. However, stretching performance +depends on the driver, and can be slow, so sometimes 640x480 is +actually faster than 320x240 on NT. + +The bottom line here is that you can generally just use the Video menu +and pick one of the modes and be happy. In some cases, though, you +may need to use command-line switches (described next) to get the +types of modes you want. One useful tip is to go into the console and +do vid_describemodes, which lists all the modes WQ makes available on +your machine given the command-line switches you've used. Each mode +is followed by the name of the internal WQ driver that supports it, so +you can tell which modes are DirectDraw, VESA, and so on, as follows: + +WINDOWED: WQ runs in a normal window +FULLSCREEN DIB: fullscreen borderless window +FULLSCREEN VGA8.DRV: VGA 320x200 mode +FULLSCREEN DDRAW8.DRV: DirectDraw mode +FULLSCREEN LINEAR8.DRV: VESA VBE 2.0+ mode +FULLSCREEN ACCEL8.DRV: VESA VBE/AF (Accelerator Functions) mode + (note that WQ does not take advantage of + VBE/AF acceleration; so far as WQ is + concerned VBE/AF is the same as normal VBE) + +You can use vid_mode from the console to set any of these modes. So, +for example, if you see that there are two 320x200 modes (such as one +VGA mode 0x13, normally mode 3, and one VESA mode, normally mode 4), +you can choose the VESA mode, which will often be faster, with +vid_mode 4. (You can make it the default by setting +_vid_default_mode_win to the mode number.) + +There's more to the windowed modes than you might think. 320x240 is +just what you’d expect, but 640x480 is actually rendered at 320x240 +and stretched up to 640x480, because most machines can’t handle the +performance demands of real 640x480 rendering. Likewise, 800x600 is a +stretched 400x300. Actually, though, vid_mode 2 (the 800x600 mode) is +a user-configurable mode. By setting the following console variables, +you can change the characteristics of vid_mode 2: + +vid_config_x: width of mode 2 window + +vid_config_y: height of mode 2 window + +vid_stretch_by_2: whether to render at half-resolution in each +direction and stretch up to the specified size in mode 2, or render at +full resolution. + +After setting these variables in the console, do a vid_forcemode 2, +and you’ll have the window you specified. Note that after making +these changes, the new resolution will show up as the third windowed +mode in the Video menu. + +If you don't have WQ mouse play enabled in windowed mode, you can also +go from windowed to fullscreen mode simply by clicking on the maximize +button. The mode switched to is controlled by the vid_fullscreen_mode +console variable, and defaults to mode 3. + +Other video console commands include: + +vid_fullscreen: switch to the mode specified by the +vid_fullscreen_mode console variable. + +vid_windowed: switch to the mode specified by the vid_windowed_mode +console variable. + +Vid_fullscreen and vid_windowed can be bound to keys, so it's possible +to flip between windowed and fullscreen with a single key press. + +Also, vid_minimize minimizes the WinQuake window if and only if +WinQuake is running in a windowed mode. You can bind a key to +the commands "vid_windowed; wait; vid_minimize" to minimize WQ +regardless of whether you're running in windowed or fullscreen mode. + +You can turn off page flipping by setting the console variable +vid_nopageflip to 1, then setting a new mode. (Note that the +vid_nopageflip setting does not take effect until the next mode set.) +Some systems run faster with page flipping turned off; also, page +flipping does not work properly on some adapters, and vid_nopageflip +is a workaround for this. Note that vid_nopageflip is a persistent +variable; it retains its setting until it is explicitly changed again, +even across multiple WinQuake sessions. + +The vid_forcemode console command sets the specified mode, even if +it's the same as the current mode (normally the mode set only happens +if the new mode differs from the current mode). This is generally +useful only if you've modified the characteristics of video mode 2 +(the configurable window) while you're in mode 2, and want to force +the new characteristics to take effect. + +Whenever you switch to running WinQuake in a window, the window is +placed at the same location it was in the last time WinQuake ran +in a window. You can reset the window position to the upper left +by using the -resetwinpos command-line switch. The window position +is stored in the vid_window_x and vid_window_y console variables. + + + +------------------------------- +| Video command-line switches | +------------------------------- + +The full list of video-related command-line switches is: + +-dibonly: WQ will use only windows (both normal, framed windows on the +desktop and fullscreen, borderless windows), not any direct hardware +access modes such as DirectDraw or VESA modes, or even VGA 320x200 +mode. This is the closest thing to a guaranteed-to-run fullscreen +mode WQ has. + +-nowindirect: WQ will not try to use VESA VBE 2.0 modes, or VBE/AF +1.0 or later modes. Note that if there are both DirectDraw and VESA +modes for a given resolution, WQ will normally use the VESA mode; +-nowindirect allows DirectDraw modes to be the preferred choice for +all resolutions except 320x200. This can be useful if WQ is crashing +because of a buggy VESA driver. + +-nodirectdraw: WQ will not try to use DirectDraw modes. This can be +useful if WQ is crashing because of a buggy DirectDraw driver. + +-novbeaf: WQ will not try to use VBE/AF 1.0 or later modes. + +-startwindowed: WQ will come up in a windowed mode, without going +fullscreen even during initialization. + +-noforcevga: normally, WQ uses VGA mode 0x13 for the default 320x200 +mode, even if a DirectDraw or VESA 320x200 mode exists. However, +DirectDraw and VESA modes can be considerably faster than mode 0x13, +because they can set up a linear framebuffer with higher memory +bandwidth. If you specify -noforcevga, the default 320x200 mode in +the menu will be a DirectDraw or VESA mode if one exists. This has no +effect on modes selected via the console variable vid_mode, and if +320x200 is already your video mode, -noforcevga doesn't do anything +until you use the menu to select another mode, then select 320x200 +again. (So if your default mode is 320x200 and you then specify +-noforcevga, switch away to some other mode and then back to 320x200 +to get the potentially faster 320x200 mode.) The downside to this +switch is that DirectDraw and VESA modes can cause problems in some +systems, due to driver bugs or hardware incompatibilities; if you +experience problems with this switch, don't use it. + +-noautostretch: don't stretch windowed modes selected with +-startwindowed to double resolution. + +-nofulldib: don't use fullscreen, borderless windows, even if there +are no DirectDraw or VESA modes available. + +-allow360: allow listing of 360-wide modes in the video mode menu. +These are normally filtered out to make sure the menu doesn't get too +full, which could cause high-res modes not to be displayed. + +-notriplebuf: prevent triple-buffered page flipping (rather than double- +buffered). This may result in slower performance, but is a workaround +if you encounter problems with flicker or initialization failure, which +could possibly happen in some modes with some DirectDraw drivers. + + + +---------------------------------- +| A bit about how WQ sound works | +---------------------------------- + +WQ can use either DirectSound or Windows wave output to generate +sound. If DirectSound is available, it is used; if not, if wave sound +is available it is used; and if neither is available, there is no +sound. DirectSound results in the best sound quality, and also the +lowest-latency sound; use it if you can, because you will be happier +with the results. (Note, though, that no NT sound drivers yet support +DirectSound.) Wave sound will often have high latency, lagging the +events that generate sound by hundreds of milliseconds on some +machines. + +You can tell what kind of sound WQ uses on your system by looking at +the startup portion of the console; you will see either "DirectSound +initialized" or "Wave sound initialized" (neither message is printed +if there's no sound). Any sound failure messages will also be printed +in the startup portion of the console. + +Note that WQ generates sound only when it is the active app, the one +with the input focus. + + + +------------------------------- +| Sound command-line switches | +------------------------------- + +The full list of sound-related command-line switches is: + +-wavonly: don’t use DirectSound, but use wave sound if available. +Note that wave sound is generally faster than DirectSound, but has +considerably greater latency. This switch is redundant on NT, because +all sound output on current NT drivers is wave sound. + +-nosound: don’t output any sound. + +-primarysound: use DirectSound primary buffer output. This is +generally faster than normal secondary buffer output, but does not +work in some systems, and produces odd sound glitches on minimization +and focus switching in other systems. Use it at your own risk, and +please do not report sound bugs if you're using this switch. + +-snoforceformat: WQ will not try to force the sound hardware to 11 +KHz, 16 bits per sample. This may be useful if DirectSound is failing +for no apparent reason, but generally WQ will produce better sound and +better performance if this switch is not used. + + + +----------------------- +| Notes on networking | +----------------------- + +The winsock TCP/IP driver will not cause a dial-up internet connection +to automatically start up when Quake is started. If you start Quake +with it inactive, the connection will be activated when you either try +to connect to a server or search for local servers. + +The local IP address will not always be known at startup. If it is +currently unknown the menu will display "INADDR_ANY". This will be +replaced with the real address when it is known. The IP address will +become known when you try to connect to a server, you search for local +servers, or you start a server. + +For multi-homed machines (machines with more than one network adapter +and IP adress), you can force WinQuake to bind to a specific IP +address. There is a command line option "-ip" that takes an IP +address as its parameter. + + + +---------------------- +| Notes on the mouse | +---------------------- + +If DirectInput is installed and functioning, WinQuake can use it for +mouse input, but does not do so automatically because DirectInput does +not work properly on all systems. DirectInput can be enabled via the +command-line switch -dinput. If DirectInput is not available or is +not enabled, WinQuake uses the normal Windows mouse APIs instead. +DirectInput provides slightly smoother motion; also, it tends to be +more responsive to fast spinning motions, and we recommend that you use +it if it works properly on your system. You can determine if WQ uses +DirectInput on your system when you use -dinput by checking for +"DirectInput initialized" in the startup console text. If not, you +might try installing DirectX 3 (note, though, that as I write this +there is no released DirectInput support for Windows NT, only Win95). + + + +----------------------------------- +| Log of changes to documentation | +----------------------------------- + +*** WinQuake 0.994 *** + +Fixed bug where in some cases involving IPX, whenever a new person +entered the game, a current player got dumped. + +Added DirectInput mouse support, and the -dinput command-line to +enable it. + +Added -notriplebuf to disable triple buffering to work around +possible problems with some modes on some DirectDraw drivers. + +Added remembering last window position, and restoring that, rather +than centering the window, whenever WinQuake runs in a window. +Can be reset with the -resetwinpos command-line switch. + +Added the vid_minimize command, which minimizes WinQuake if and only +if the current mode is windowed. + +Made it so WinQuake no longer gets suspended when Alt-Tab is used to +switch away from a fullscreen session. The means you can Alt-Tab +away from fullscreen WinQuake without losing a connection to a +Quake server. + +Added vid_nopageflip console variable to turn off page flipping, and +documented page flipping problems this can be used to work around. + +Documented that Del-Ctrl-Alt (in that order) causes WinQuake to +fault on Win95. + +Fixed the winsock TCP/IP driver so it will not cause a dial-up +internet connection to automatically start up when Quake is started. +If you start Quake with the internet connection already active, there +will be no difference. If you start Quake with it inactive, the +connection will be activated when you either try to connect to a +server or search for local servers. + +The local IP address will not always be known at startup now. If it +is currently unknown the menu will display "INADDR_ANY". This +will be replaced with the real address when it is known. The IP +address will become known when: you try to connect to a server, +you search for local servers, or you start a server. + +For multi-homed machines (machines with more than one network +adapter and IP adress), you can now force WinQuake to bind to a +specific IP adress. There is a new command line option "-ip" that +takes an IP address as its parameter. + +Added vid_fullscreen_mode and ability to select that mode by +clicking on the maximize button. Added two commands: +vid_fullscreen to switch to vid_fullscreen_mode, and +vid_windowed to switch to vid_windowed mode. + +Changed joystick default to disabled; now it only works if the +joystick cvar is set to 1; however, this setting now remains in +effect permanently. Added joystick documentation below. + +Documented dprint only works if developer set to 1. + +Documented scrunching of MS-DOS windows on Alt-Tab. + +Documented that NT versions earlier to 4.0 are not supported. + +Added DirectInput support for devices such as First Person +Gaming's Assassin controller. All buttons should now +be configurable in WinQuake. + +Fixed bug where when low-res fullscreen DIB modes selected from +the menu sometimes ran very slowly or produced garbled displays. + +Fixed bug where 1.06 and earlier save files couldn't be loaded +by WinQuake. + +Removed "Net play pauses every few seconds" bug; it was determined +not to be a bug, just an artifact of network play. + +Noted that even when BIOSes do have VESA 2.0 built-in, it's often +so buggy that WinQuake crashes in faster configurations, and that +SciTech Display Doctor is the easiest way to get reliable VESA +support. + +Added note on Alt-Tab only working if Tab released first. + + +*** WinQuake 0.992 *** + +Implemented force_centerview. + +Fixed backspace bug in dedicated console. + +Made "player entering game" messages and "say" messages visible +in dedicated console. + +Added description of -heapsize (how to change default memory +allocation). + +Added description of "net play pauses every few seconds" bug. + +Added description of "playdemo fails across multiple levels" bug. + +Added hooks for QHost; however, WinQuake won't work with QHost +until a new version of QHost 3.0, which uses the hooks, is +released. QHost 3.0 will not work with WinQuake. + +Fixed bug where savegame descriptions weren't always terminated +properly. + +Fixed bug where running -dedicated reset part of config.cfg to +defaults. + + +*** WinQuake 0.991 *** + +Fixed problem with pre-1.07 (DOS) clients connecting to WinQuake. + +Got rid of "Starting Quake..." dialog when running -dedicated. + +Added -novbeaf switch to turn off VBE/AF support in case of problems, +and updated documentation. + +Corrected SciTech's U.S. Mail address in documentation. + +Added joystick bug decriptions and workarounds. + + + +------------------ +| Special thanks | +------------------ + +Special thanks for help with WinQuake to: + +James Barnes +Kendall Bennett +Raymond Chen +John Colleran +Andrew Goossen +Mike Harrington +Chris Hecker +Todd Laney +Scott Ludwig +...and all the beta testers! + +====================================================================== +End of Document 3/21/97 +====================================================================== diff --git a/engine/code/zone.c b/engine/code/zone.c new file mode 100644 index 0000000..e30d7f8 --- /dev/null +++ b/engine/code/zone.c @@ -0,0 +1,935 @@ +/* +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. + +*/ +// Z_zone.c + +#include "quakedef.h" + +#define DYNAMIC_SIZE 0xc000 + +#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_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); + new->user->data = (void *)(new+1); + } + else + { +// Con_Printf ("cache_move failed\n"); + + Cache_Free (c->user); // tough luck... + } +} + +/* +============ +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); // didn't move out of the way + 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 ); // reclaim the space +} + + +/* +============ +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) +{ + 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); +} + + + +/* +============== +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 ); + } + + 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); +} + diff --git a/engine/code/zone.h b/engine/code/zone.h new file mode 100644 index 0000000..7655ad9 --- /dev/null +++ b/engine/code/zone.h @@ -0,0 +1,131 @@ +/* +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. + +*/ +/* + 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); + +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/engine/docs/COMEXP.TXT b/engine/docs/COMEXP.TXT new file mode 100644 index 0000000..06bc4af --- /dev/null +++ b/engine/docs/COMEXP.TXT @@ -0,0 +1,487 @@ + COMMERCIAL EXPLOITATION LICENSE AGREEMENT FOR QUAKE + + This Commercial Exploitation License Agreement for QUAKE +(the "Agreement") is between Id Software, Inc., a Texas +Corporation, (hereinafter "Id Software") and Licensee (as described +on the signature page hereof) and is made effective beginning on +the date of last signature hereto (the "Effective Date"). + + R E C I T A L S + + WHEREAS, Id Software is the owner and developer of the +computer software game entitled QUAKE; + + WHEREAS, Id Software desires to license certain +non-exclusive rights regarding QUAKE to Licensee; and + + WHEREAS, Licensee desires to receive a license for such +rights. + + T E R M S A N D C O N D I T I O N S + + NOW, THEREFORE, for and in consideration of the mutual +premises contained herein and for other good and valuable +consideration, the receipt and sufficiency of which is hereby +acknowledged, the undersigned parties do hereby agree as follows: + + 1. DEFINITIONS. As used in this Agreement, the parties +hereto agree the words set forth below shall have the specified +meanings: + + a. "Authorized Copy" shall mean one (1) copy of the + Subject Game actually purchased by Licensee from an + Id Software approved retailer; and + + b. "Subject Game" shall mean the full registered + version of QUAKE on a CD-ROM and shall not mean the + shareware or any other version. + + 2. GRANT OF RIGHTS. Id Software hereby grants to +Licensee and Licensee hereby accepts, subject to the provisions and +conditions hereof, a world-wide (except as otherwise provided +herein), non-exclusive, non-transferable, and non-assignable +license to: + + a. publicly display an Authorized Copy in exchange for + rental payment; + + b. run the Authorized Copy so that it will accept + network/modem connections in exchange for payments + from end-users who also must have actually purchased + an Authorized Copy; and + + c. otherwise commercially exploit an Authorized Copy, + except that Licensee shall not copy, reproduce, + manufacture or distribute the Authorized Copy. + + 3. RESERVATION OF RIGHTS AND PROHIBITIONS. Id Software +expressly reserves all rights not granted herein. Under no +circumstances shall Licensee copy, reproduce, manufacture or +distribute (free of charge or otherwise) the Authorized Copy or the +Subject Game. Licensee shall not reverse engineer, decompile, +disassemble, modify or alter the Authorized Copy. Licensee is not +receiving any rights hereunder regarding the Trademark or any +artwork, sound, music or other element of the Subject Game. + + 4. OWNERSHIP. Title to and all ownership rights in and +to the Subject Game, and the QUAKE Trademark (the "Trademark") and +the copyrights, trademarks, patents and other intellectual property +rights related thereto shall remain with Id Software which shall have +the exclusive right to protect the same by copyright or otherwise. +Licensee shall have no ownership rights in or to the Subject Game or +the Trademark and Licensee shall not own any intellectual property +rights regarding the Authorized Copy, including, without limitation, +the copyright regarding the Authorized Copy. Licensee acknowledges +that it only has a limited license to use the Authorized Copy, as +specified in that certain QUAKE Enduser License contained within the +Authorized Copy and as specified in this Agreement. + + 5. TERM AND TERMINATION. + + a. The term of this Agreement and the license granted +herein begins on the Effective Date and shall expire on a date one +(1) calendar year from the Effective Date. + + b. Either party may terminate this Agreement, for any +reason or no reason, on thirty (30) days written notice to the +other party. Termination will be effective on the thirtieth (30th) +day following delivery of the described notice. Notwithstanding +anything to the contrary herein, this Agreement shall immediately +terminate, without the requirement of any notice from Id Software +to Licensee, upon the occurrence of any of the following: (a) if +Licensee shall file a petition in bankruptcy or make an assignment +for the benefit of creditors, or if any bankruptcy proceeding or +assignment for benefit of creditors, shall be commenced against +Licensee and not be dismissed within sixty (60) days after the date +of its commencement; (b) the insolvency of Licensee; (c) the +cessation by Licensee of its business; or (d) the cessation by +Licensee, without the prior written consent of Id Software of the +distribution, manufacture, and sale responsibilities embodied +herein. Further, Id Software may elect to terminate this Agreement +upon the occurrence of any of the following: (1) if Licensee's +business operations are interrupted for forty (40) consecutive +calendar days; or (2) if each of two Id Software audit inspections +during any eighteen (18) month period demonstrates an +understatement by Licensee of Royalty payments due Id Software for +the six (6) month period immediately preceding each such inspection +of five percent (5%) or more. Upon the occurrence of such +terminating event, and the election of Id Software, if necessary, +to cause such termination, this Agreement and any and all rights +thereunder shall terminate without prejudice to any rights or +claims Id Software may have, and all rights hereunder shall +thereupon terminate, revert to and be vested in Id Software. + + 6. EFFECT OF TERMINATION OR EXPIRATION. Termination or +expiration of this Agreement, either by Id Software or +automatically, shall not create any liability against Id Software. +Upon expiration or earlier termination of this Agreement, Licensee +shall have no further right to exercise the rights licensed +hereunder or otherwise acquired in relation to this Agreement. + + 7. INDEMNIFICATION. Licensee hereby agrees to +indemnify, hold harmless and defend Id Software and Id Software's +predecessors, successors, assigns, officers, directors, +shareholders, employees, agents, representatives, licensees, +sublicensees, distributors, attorneys and accountants +(collectively, the "Id Related Parties") from and against any and +all damages, claims, losses, causes of action, liabilities, +lawsuits, judgments and expenses (including, without limitation, +reasonable attorneys' fees and expenses) arising from, relating to +or in connection with a breach of this Agreement by Licensee and +arising from, relating to or in connection with the Licensee's use +or non-use of the Authorized Copy (collectively, the "Claims"). Id +Software agrees to notify Licensee of any such Claims within a +reasonable time after Id Software learns of same. Licensee, at its +own expense, shall defend Id Software and the Id Related Parties +from any and all Claims. Id Software and the Id Related Parties +reserve the right to participate in any defense of the Claims with +counsel of their choice, and at their own expense. In the event +Licensee fails to provide a defense, then Licensee shall be +responsible for paying the attorneys' fees and expenses incurred by +Id Software and the Id Related Parties regarding the defense of the +Claims. Id Software and the Id Related Parties, as applicable, +agree to reasonably assist in the defense of the Claims. No +settlement by Licensee of any Claims shall be valid unless Licensee +receives the prior written consent of Id Software and the Id +Related Parties, as applicable, to any such settlement. + + 8. CONFIDENTIALITY. It is understood and agreed that +any proprietary information of Id Software that may from time to +time be made available or become known to Licensee is to be treated +as confidential, is to be used solely in connection with Licensee's +performance under this Agreement, and is to be disclosed only to +employees of Licensee who have a need for access. Such proprietary +information shall include, but not be limited to, trade secrets, +release information, financial information, personnel information, +and the like. Reasonable measures shall be taken by Licensee to +protect the confidentiality of Id Software's proprietary +information and any memoranda or papers containing proprietary +information of Id Software's that Licensee may receive are to be +returned to Id Software upon request. Licensee's obligations and +duties under this paragraph shall survive expiration or earlier +termination of this Agreement. Licensee shall obtain from its +employees an undertaking in a form which may be supplied by Id +Software, and which is subject to Id Software's prior written +approval, not to use or disclose to any third party any information +or knowledge concerning the business of Id Software which may be +communicated to such employees. + + 9. LIMITATION OF LIABILITY. ID SOFTWARE EXPRESSLY +DISCLAIMS ALL WARRANTIES NOT PROVIDED BY ID SOFTWARE HEREUNDER. +UNDER NO CIRCUMSTANCES SHALL ID SOFTWARE BE LIABLE TO LICENSEE FOR +ACTUAL, SPECIAL, INCIDENTAL, CONSEQUENTIAL OR PUNITIVE DAMAGES OR +ANY OTHER DAMAGES, WHETHER OR NOT ID SOFTWARE RECEIVES NOTICE OF +ANY SUCH DAMAGES. + + 10. COMPLIANCE WITH APPLICABLE LAWS. In performing +under this Agreement, Licensee agrees to comply with all applicable +laws, [including, without limitation, 22 U.S.C., 2778 and 22 +U.S.C. C.F.R. Parts 120-130 (1995)] regulations, ordinances and +statutes, including, but not limited to, the import/export laws and +regulations of the United States and its governmental and +regulatory agencies (including, without limitation, the Bureau of +Export Administration and the U.S. Department of Commerce) and all +applicable international treaties and laws. Further, Licensee +shall defend, indemnify and hold harmless Id Software from any and +all sales tax, tariffs and/or duties in connection with Licensee's +performance hereunder. + + 11. SPECIFIC UNDERTAKINGS BY LICENSEE. In addition to +the obligations of Licensee otherwise set forth in this Agreement, +during the term of this Agreement, and thereafter where specified, +Licensee agrees that: + + a. It will not attack the title of Id Software to the +Subject Game or the Trademark and any copyright, patent or +trademark or other intellectual property right related thereto and +it will not attack the validity of the license granted hereunder +during the term hereof or thereafter; and + + b. It will promptly inform Id Software of any +unauthorized use of the Authorized Copy, the Subject Game and the +Trademark and any portions thereof and reasonably assist Id +Software in the enforcement of any rights Id Software may have +against such unauthorized users. + + 12. FINANCIAL OBLIGATIONS AND ACCOUNTING. + + a. Payment of Royalties. Licensee agrees to pay Id +Software a royalty ("Royalty") at the rate of twelve and one-half +percent (12.5%) of Net Income. The term "Net Income" shall mean +all revenue received by Licensee from the commercial use of the +Authorized Copy, less only Licensee's actual, documented costs +relating directly to such use. A Royalty shall only be due for +those months in which Licensee's gross revenue from QUAKE +distribution exceeds U.S. Five Thousand Dollars ($5,000.00) and in +such months Licensee shall pay a full Royalty on all revenue +received. + + b. Rendition of Statements. Licensee shall account to +Id Software with regard to transactions hereunder within forty-five +(45) days following the conclusion of each calendar quarter. +Licensee hereby represents and warrants that such statements of +account to be prepared shall be true and correct. The accounts +shall show in summary form the appropriate calculations relating to +the computation of Royalties, if any. The statements shall also +show the gross revenue received by Licensee per month. The +Royalties payable to Id Software hereunder shall be remitted with +the particular statement indicating such amount to be due. All +statements hereunder shall be deemed rendered when deposited, +postage prepaid, in the United States mail, addressed to Id +Software at Id Software's address set forth on the signature page +hereof. + + c. Books of Account and Audits. Licensee shall keep +books of account relating to the commercial use of the Authorized +Copy on the basis of generally accepted accounting principles and +shall maintain such books of account for a period of at least two +(2) years after the expiration or earlier termination of this +Agreement; provided, however, that Licensee shall not be required +to keep such records longer than seven (7) years from their date of +origination. Id Software may, upon reasonable notice and at its +own expense, audit the applicable records at Licensee's office, in +order to verify statements rendered hereunder. Any such audit +shall take place during reasonable business hours and in such +manner so as not to interfere with Licensee's normal business +activities. Id Software agrees that such information inspected +and/or copied on behalf of Id Software hereunder shall be used only +for the purpose of determining the accuracy of the statements, and +shall be revealed only to such officers, directors, employees, +agents and/or representatives of Id Software as necessary to verify +the accuracy of the statements. If in an audit of Licensee's books +and records it is determined that there is a short fall of ten +percent (10%) or more in Royalties reported for any calendar +quarter, in addition to payment of such short fall and interest as +may be due, as provided herein, Licensee shall reimburse Id +Software for the full out-of-pocket costs of the audit including +reasonable travel costs and expenses; provided, however, that the +amount of reimbursement paid by Licensee shall not exceed U.S. +Fifteen Thousand Dollars ($15,000.00) for any audit. + + d. Payment of the Royalty. Licensee assumes all risks +associated with fluctuations in foreign currency exchange rates. +Licensee shall pay and agrees to pay all sums due Id Software in +United States Dollars. With respect to Royalties due for +commercial use outside the United States, other currencies shall be +exchanged at the expense of Licensee into United States Dollars +using the bid price quoted at the Citibank, N.A. of New York, New +York, for the purchase of United States Dollars at the close of +business on the last day of the calendar quarter during which any +amounts accrue. Payment of the Royalties shall be made in Dallas +County, Texas. + + e. Interest. If Id Software does not receive the +applicable Royalty payment on or before the due date of such +payment, Licensee agrees to pay and shall pay interest on Royalties +owed to Id Software from such date as specified in the following +sentence at a rate per annum equal to the Index Rate. For purposes +of clarification, the interest will begin to accrue on the first +(1st) day following the due date of the Royalty payment, unless the +Royalty payment is paid timely. The "Index Rate" shall be the +prime rate as published in The Wall Street Journal's "Money Rates" +table. If multiple prime rates are quoted in the table, then the +highest prime rate will be the Index Rate. In the event that the +prime rate is no longer published in the "Money Rates" table, then +Id Software will choose a substitute Index Rate which is based upon +comparable information. The applicable interest rate will be +determined and take effect on the first day of each month. + + NOTHING HEREIN SHALL BE CONSTRUED AS A REQUEST OR DEMAND BY +ID SOFTWARE OF INTEREST AT A RATE HIGHER THAN ALLOWED BY APPLICABLE +LAW. IT IS THE INTENT OF THE PARTIES HERETO THAT NO INTEREST BE +CHARGED HEREUNDER WHICH EXCEEDS THE MAXIMUM RATE ALLOWED BY +APPLICABLE LAW. IF THE RATE REFERENCED ABOVE EXCEEDS THE MAXIMUM +RATE ALLOWED BY APPLICABLE LAW, THEN THE INTEREST RATE MADE +APPLICABLE HEREIN SHALL BE THE MAXIMUM RATE ALLOWED BY APPLICABLE +LAW. + + 13. SUBLICENSE. Licensee shall not be entitled to +sublicense any of its rights under this Agreement. + + 14. GOODWILL. Licensee recognizes the great value of +the goodwill associated with the Subject Game and the Trademark, +and acknowledges that such goodwill, now existing and hereafter +created, exclusively belongs to Id Software and that the Trademark +has acquired a secondary meaning in the mind of the public. + + 15. REMEDIES. In the event of a breach of this +Agreement by Id Software, Licensee's sole remedy shall be to +terminate this Agreement. In the event of a breach by Licensee of +this Agreement, Id Software may pursue the remedies to which it is +entitled under applicable law, including, but not limited to, +termination of this Agreement. Licensee agrees that its failure to +comply with the terms of this Agreement upon expiration or earlier +termination hereof or Licensee's unauthorized use of the Authorized +Copy may result in immediate and irreparable damage to Id Software +for which there is no adequate remedy at law, and in the event of +such failure by Licensee, Id Software shall be entitled to +injunctive relief. Pursuit of any remedy by Id Software shall not +constitute a waiver of any other right or remedy of Id Software +under this Agreement or under applicable law. Termination of this +Agreement shall not be a pre-condition to Id Software pursuing its +other remedies for breach. + + 16. LICENSEE'S WARRANTIES. Licensee warrants and +represents that it has full legal rights to enter into this +Agreement and to perform its obligations hereunder and that it will +comply, at all times during the terms of this Agreement, with all +applicable laws, as set forth hereinabove. + + 17. BANKRUPTCY. If Licensee's liabilities exceed its +assets, or if Licensee becomes unable to pay its debts as they +become due or if Licensee files for voluntary bankruptcy, or is +placed in bankruptcy which is not dissolved or dismissed after +thirty (30) days from the petition filing date, or if Licensee +becomes insolvent, or makes an assignment for the benefit of its +creditors or an arrangement pursuant to any bankruptcy laws or if +Licensee discontinues its business or if a receiver is appointed +for its business, this Agreement shall automatically terminate, +without notice, and become null and void; provided, however, all +duties of Licensee upon termination or expiration of this Agreement +shall continue in full force and effect. + + 18. ENTIRE AGREEMENT AND ASSIGNMENT. This Agreement +constitutes the entire understanding between Licensee and Id +Software regarding the Subject Game. Each and every clause of this +Agreement is severable from the whole and shall survive unless the +entire Agreement is declared unenforceable. No prior or present +agreements or representations shall be binding upon any of the +parties hereto unless incorporated in this Agreement. No +modification or change in this Agreement shall be valid or binding +upon the parties unless in writing, executed by the parties to be +bound thereby. This Agreement shall bind and inure to the benefit +of Id Software, its successors and assigns, and Id Software may +assign its rights hereunder, in Id Software's sole discretion. +This Agreement is personal to Licensee, and Licensee shall not +sublicense, assign, transfer, convey nor franchise its rights +granted hereunder. + + 19. CHOICE OF LAW, VENUE AND SERVICE OF PROCESS. This +Agreement shall be construed in accordance with the laws of the +State of Texas and applicable U.S. federal law and all claims +and/or lawsuits in connection with this Agreement must be brought +in Dallas County, Texas. Licensee hereby agrees that service of +process by certified mail to the address set forth below, with +return receipt requested, shall constitute valid service of process +upon Licensee. If for any reason Licensee has moved or cannot be +validly served, then Licensee appoints the Secretary of State of +the state of Texas to accept service of process on Licensee's +behalf. + + 20. EXCUSED PERFORMANCE. Neither party shall be deemed +to be in default of any provision of this Agreement nor be liable +for any delay, failure in performance or interruption of service, +resulting directly or indirectly from acts of God, civil or +military authority, civil disturbance, military action, war, +strikes, other catastrophes or any other similar cause beyond its +reasonable control. Written notice to the non-affected party of any +such condition shall be given by the affected party within ten (10) +days of the event. + + 21. DELIVERY OF NOTICES, AND DELIVERY OF PAYMENTS. +Unless otherwise directed in writing by the parties, all notices +given hereunder and all payments made hereunder shall be sent to +the addresses set forth on the signature page hereof. All +notices, requests, consents and other communications under this +Agreement shall be in writing and shall be deemed to have been +delivered on the date personally delivered or on the date deposited +in the United States Postal Service, postage prepaid, by certified +mail, return receipt requested, or telegraphed and confirmed, or +delivered by electronic facsimile and confirmed. Any notice to Id +Software shall also be sent to its counsel: D. Wade Cloud, Jr., +Hiersche, Martens, Hayward, Drakeley & Urbach, P.C., 15303 Dallas +Parkway, Suite 700, LB 17, Dallas, Texas 75248. + + 22. NO PARTNERSHIP, ETC. This Agreement does not +constitute and shall not be construed as constituting a partnership +or joint venture between Id Software and Licensee. Neither party +shall have any right to obligate or bind the other party in any +manner whatsoever, and nothing herein contained shall give, or is +intended to give, any rights of any kind to any third persons. + + 23. COUNTERPARTS. This Agreement may be executed in +several counterparts, each of which will be deemed to be an +original, and each of which alone and all of which together, shall +constitute one and the same instrument, but in making proof of this +Agreement it shall not be necessary to produce or account for each +copy of any counterpart other than the counterpart signed by the +party against whom this Agreement is to be enforced. This +Agreement may be transmitted by facsimile, and it is the intent of +the parties for the facsimile of any autograph printed by a +receiving facsimile machine to be an original signature and for the +facsimile and any complete photocopy of the Agreement to be deemed +an original counterpart. + + 24. MEDIATION. If a dispute arises out of or relates to +this Agreement, or a breach of this Agreement, and if the dispute +cannot be settled through direct discussion, then the parties agree +to endeavor to settle the dispute in an amicable manner by +mediation, under the applicable provisions of Section 154.00 et +seq., Texas Civil Practices and Remedies Code, as supplemented by +the rules of the Association of Attorney Mediators. + + 25. SURVIVAL. The following provisions shall survive +the expiration or earlier termination of this Agreement: +paragraphs 4., 7., 8., and the audit rights of Id Software in +paragraph 12.c. + + 26. MISCELLANEOUS. + + a. All captions in this Agreement are intended solely +for the convenience of the parties, and none shall effect the +meaning or construction of any provision. + + b. The terms and conditions of this Agreement have been +negotiated fully and freely among the parties. Accordingly, the +preparation of this Agreement by counsel for a given party will not +be material to the construction hereof, and the terms of this +Agreement shall not be strictly construed against such party. + + By signing in the spaces provided below, the parties have +agreed to all of the terms and conditions set forth in this +Agreement. + + +AGREED: + +LICENSEE: + + +Signed:_______________________________ +Printed Name:_________________________ +Title:________________________________ +Address:______________________________ +______________________________________ +______________________________________ +Telephone #: _________________________ +Fax #:________________________________ +E-Mail Address:_______________________ +Date: ________________________________ + + +AGREED: + +ID SOFTWARE, INC. + + +Signed:_______________________________ +Printed Name:_________________________ +Title:________________________________ +Address:______________________________ +______________________________________ +______________________________________ +Telephone #: _________________________ +Fax #:________________________________ +E-Mail Address:_______________________ +Date: ________________________________ + + + +June 10, 1996 + + + +COMMERCIAL EXPLOITATION LICENSE AGREEMENT FOR QUAKE +(DWC:dw:3406.0299:dwc\doc:5017) + + diff --git a/engine/docs/HELP.TXT b/engine/docs/HELP.TXT new file mode 100644 index 0000000..ef79fbd --- /dev/null +++ b/engine/docs/HELP.TXT @@ -0,0 +1,119 @@ +TECH SUPPORT +Any of the information listed below could change. Check the id software +Web Site, at www.idsoftware.com, for updates. + +A. Tech Support Options +id Software does charge for technical support, but we strive to offer +this service at the lowest cost possible. Because volume on the support +lines dictate costs, we periodically adjust our rates for Voice Tech +Support. Check our web site for current pricing. + +Paying for Voice or Automated Support +1 -- You can get Voice Support using a major credit card for a one-time +shot. The system asks for your credit card number and expiration date, +then pre-authorizes your credit card for the tech support call. You will +only be billed for the number of minutes actually used. + +2 -- You can assign yourself a rechargeable PIN account. The system prompts +you for your credit card information, and assigns you a PIN account number. +You can use the PIN to access Voice Support, Automated Support and the +Game Hints Line. Once your account runs out, you can charge it up again. + +3 -- You may also charge up a PIN account using the number 1 (900) call-2-id. +Then call back at 1(800)ID-GAMES (1(800)434-3627), and use your new PIN to +receive all the support and hints you wish. + +4 -- id Software's Game Hints Line is accessible either using a PIN account +via 1 (800) ID-GAMES (see above), or by calling 1 (900) CALL2-ID, which +places the call on your phone bill. + + 1. Voice Support + Telephone -- 1 (800) id-games + + Lines Open from 12 noon to 10pm Central Time, 7 Days a + week ($1.75 per minute). Closed some holidays + + Please have the following information handy. + 1. Game title and version number. (The version + number can be found on the end text screen.) + 2. Your operating system, processor, processor + speed and amount of RAM. + 3. If you are having a sound, video or modem + problem, we need to know the device brand name + and model. + + 2. Automated Support + Telephone -- 1 (800) id-games + + Lines Open 24 hours a day, 365 days a year, or 366 days + in Leap years ($0.25 per minute) + + Please have pencil and paper handy. + + 3. E-mail Support + Just send your e-mail to support@idsoftware.com + + We will do our best to respond within 48 hours after + receiving your e-mail. + + When sending e-mail, cut and paste the following into your + e-mail message and fill in the blanks: + +Date: +Name: +Phone number: +E-mail address: (please include this, we redirect tons of mail) +Game Title: +Version #: +Operating system (eg., DOS 6.0 or Windows 95): +Computer type: +Processor type: +Processor speed: +Video card brand and model: (only if video problem) +Audio card brand and model: (only if audio problem) +Modem brand and model: (only if modem problem) +Network card brand and model: (only if netgame problem) +Network configuration (eg., NET.CFG file): (only if netgame problem) +Drivers, protocol stacks, and versions: (eg., lsl v2.14, exp16odi +v2.33, and ipxodi v3.01) (only if netgame problem) +If there were any error messages or fault information, report them +here: +Please state the problem you encountered: +Please state how to reproduce the problem: + + 4. Web Support + Found at www.idsoftware.com + + Our web support pages provide the same information that's + available via Automated Support, except it's free! + + 5. News Sites + For information, FAQ, or announcements: + rec.games.computer.quake.announce + For editing and hecking Quake-related files: + rec.games.computer.quake.editing + For general Quake discussion: + rec.games.computer.quake.misc + + 6. Game Hints Line + Telephone -- 1 (800) id-games or 1 (900) call-2-id + + Lines Open 24 hours a day, 365 days a year, or 366 days + in Leap years ($0.85 per minute) + You must be 18 years of age or have parental permission + to call 1 (900) call-2-id. + +B. In Europe + The help lines in Europe are open 7:30am - 5:00pm GMT, + Monday - Friday. + +English: +44 01923 209145 +German: +44 (0)1923 209151 +French: +44 (0)1923 209148 + +C. Problems + If you have an unfavorable experience using our services, please + send e-mail to 911@idsoftware.com. We would also like to hear + from you if you have something positive to share with us. Kindly + include your full name, address, phone number, and the problem + encountered or information you'd like to tell us about. diff --git a/engine/docs/LICINFO.TXT b/engine/docs/LICINFO.TXT new file mode 100644 index 0000000..f909e38 --- /dev/null +++ b/engine/docs/LICINFO.TXT @@ -0,0 +1,97 @@ +Here is a brief explanation of all the legal mumbo jumbo contained in the +various license agreements that may or may not be part of this package. + +(This document was designed to be a quick overview of our license terms. +You must refer to the full text of the license for a complete listing of +terms and conditions.) + +QUAKE SHAREWARE END USER LICENSE (slicnse.txt) or +What You Can and Cannot Do With the Shareware Version of Quake. + +CAN DO: +-- Play & Enjoy the single player game +-- Setup a shareware version based server on a not-for-profit basis + +CANNOT DO: +-- Run the game with user developed levels. +-- You may not commercially exploit the shareware version in any way + This specifically excludes retail distribution of the shareware + version. Do not call or e-mail to ask if you can be a retail + distributor of the shareware version -- the answer is no! +-- Commercially exploit any id copyrighted and/or trademarked property. + Example: Game names, logos, graphics, etc. + + +QUAKE REGISTERED VERSION END USER LICENSE (rlicnse.txt) or +What You Can and Cannot Do With the Registered Version of Quake. + +CAN DO: +-- Play & Enjoy the single player game +-- Setup a registered version based server on a not-for-profit basis +-- Develop new levels and/or level creation utilities. +-- Play the game and/or setup a Registered Version based server using + a user-developed level. + +CANNOT DO: +-- Commercially exploit the Registered Version of Quake in any way; + see commercially exploitation license info below. +-- Commercially exploit any id copyrighted and/or trademarked + property. + Example: Game names, logos, game graphics, etc. +-- Sell user-developed levels and/or tools + +COMMERCIAL EXPLOITATION LICENSE (comexp.txt -- accompanies Quake + registered version only) + +If you are interested in trying to make money using the registered version +of Quake (this sort of thing is not allowed using the shareware version) you +must sign our easy-to-digest Commercial Exploitation License. + +This is a royalty free license that allows you to run Quake for a profit +through a certain monthly gross profit range. If your Quake-related business +becomes successful the agreement brings id into the revenue stream. + +Basic terms of the commercial exploitation license: + +-- License grants a royalty free commercial exploitation right for the + registered version of Quake as a whole so long as Quake's monthly gross + revenue is below $5,000.00 + +-- License provides for a 12.5% royalty to be paid to id Software in months + where the licensee's Quake related monthly gross revenue is above $5,000.00 + +-- Royalty is based off net income. Net income is defined as Quake-related + gross income less Quake-related expenses. + +-- License expressly prohibits commercial exploitation via the sale (retail + or otherwise) of the shareware or registered versions of Quake. + +-- License expressly prohibits advertising/marketing use of our copyrighted + and/or trademarked properties. + +To get into bed with us on this deal you must print two (2) copies of the +document named comexp.txt. (You should find comexp.txt somewhere on the +registered version CD.) Sign/fill in the blanks of both copies where +indicated and mail both to: + + id Software + 18601 LBJ #666 + Mesquite, TX 75150 + Attn: ComExp License + +We will then countersign the documents and mail one back to you. + +Two items worth noting here: + +1. It is VERY IMPORTANT that the information you enter in the signature +block be legible. We prefer it if you enter the info into the blanks before +printing your two copies. If we cannot read your information we will not be +able to return the documents to you. + +2. The terms of this document are not subject to negotiation. If you cannot +live with the terms spelled out in the agreement do not engage in any +commercial exploitation of Quake and do not sign the document. + + + + diff --git a/engine/docs/MANUAL.TXT b/engine/docs/MANUAL.TXT new file mode 100644 index 0000000..bc674d6 --- /dev/null +++ b/engine/docs/MANUAL.TXT @@ -0,0 +1,1030 @@ +Table of Contents + I. THE STORY + A. Background + B. Prelude to Destruction + + II. INSTALLING QUAKE + A. Installation + B. README.TXT + C. MANUAL.TXT + D. TECHINFO.TXT + + III. THE BASICS OF PLAY + A. Goal of the Game + B. Skill + C. Episode + D. Getting About + E. Finding Things + + IV. CONTROLS + A. Keyboard Commands + B. The Main Menu + C. Console + D. Command Line + E. Cheat Codes + + V. THE GAME + A. The Screen + B. Messages + C Ending a Level + D. Ending a Dimension + + VI. YOUR NEW ENVIRONMENT + A. Firepower + B. Ammo + C. Power-ups + D. Bad Guys + E. Environmental Hazards and Effects + + VII. MULTIPLAYER ACTION + A. Cooperative + B. Deathmatch + C. Team Games + + VIII. COMMONLY ASKED QUESTIONS + + IX. TECH SUPPORT + A. Tech Support Options + B. In Europe + C. Problems + + X. LEVELS AND DESIGNERS + + XI. LEGAL BOILERPLATE +**************** +I. THE STORY +A. Background + You get the phone call at 4 a.m. By 5:30 you're in the secret + installation. The commander explains tersely, "It's about the Slipgate + device. Once we perfect these, we'll be able to use them to transport + people and cargo from one place to another instantly. + + "An enemy codenamed Quake, is using his own slipgates to insert death + squads inside our bases to kill, steal, and kidnap.. + + "The hell of it is we have no idea where he's from. Our top scientists + think Quake's not from Earth, but another dimension. They say Quake's + preparing to unleash his real army, whatever that is. + + "You're our best man. This is Operation Counterstrike and you're in + charge. Find Quake, and stop him ... or it ... You have full authority + to requisition anything you need. If the eggheads are right, all our + lives are expendable.." + +B. Prelude to Destruction + While scouting the neighborhood, you hear shots back at the base Damn, + that Quake bastard works fast! He heard about Operation Counterstrike, + and hit first. Racing back, you see the place is overrun. You are almost + certainly the only survivor. Operation Counterstrike is over. Except for + you. + + You know that the heart of the installation holds a slipgate. + Since Quake's killers came through, it is still set to his dimension. + You can use it to get loose in his hometown. Maybe you can get to the + asshole personally. You pump a round into your shotgun, and get moving. + +II. INSTALLING QUAKE +A. Installation + You must install Quake before you can play it. It will not run off the + CD-ROM. Place the CD-ROM into your drive, log on to that drive, and type + 'INSTALL'. If you have downloaded Quake via modem, simply go to the + directory you've placed Quake in, unzip it, and type 'INSTALL'. + +B. README.TXT + After you install Quake, you go right into the README.TXT file, which is + henceforth available in your Quake directory. This is a full listing of + Quake's technical parameters, and is constantly updated with new versions + of Quake. We strongly recommend that after you install Quake, you glance + through README.TXT. + + You may wish to print this file out, so you can have a copy of it on hand + while playing Quake. + +C. MANUAL.TXT + Also available in your Quake directory is a file labeled MANUAL.TXT. + This is the file you are now reading. + +D. TECHINFO.TXT + For those who are more technically inclined, or to fill out a bug report, + check out TECHINFO.TXT. Information on filling out a bug report is located + at the end of TECHINFO.TXT. + + +III. THE BASICS OF PLAY +A. Goal of the Game + Quake has two basic goals. First, stay alive. Second, get out of the + place you're in. The first level of each episode ends in a slipgate -- + these signify that you're entering another dimension. When you complete + an entire dimension (this takes six to eight levels), you'll find a + Rune and another slipgate, which returns you to the start. + +B. Skill + The start area has three short hallways. The one you go down selects + the Skill you wish to play at. + Easy -- This is meant for little kids and grandmas. + Medium -- Most people should start Quake at Medium skill. + Hard -- Here at id, we play Hard skill, and we think you should too, + once you're ready. + (Nightmare) -- This is so bad that the entry is hidden, so people + won't wander in by accident. If you find it, don't say we didn't warn + you. + +C. Episode + After the Skill halls, you're in a room with four exits. Each exit + leads to a different military complex, at the end of which is a + slipgate leading to a new dimension. If you have not registered, the + first episode, Dimension of the Doomed, is the only place you can go. + After registration, all four episodes are available. The other three + episodes, in order from second to fourth, are Realm of Black Magic, + Netherworld, and The Elder World. + +============================================================================= +== TIP -- From episode 1 to episode 4, the dimensions become progressively == +== more difficult. We suggest you play the episodes in the proper order to == +== get the maximum fun out of Quake. == +============================================================================= + +D. Getting About + The specific keys named below can be changed by using the Configure Keys + Menu. If you have renamed Run as the R key, for instance, then the Shift + key will not double your speed. + Walk + Use the arrow keys or the mouse. To walk steadily forward, hold down + the Forward key (up arrow or center mouse button). Turn left or right + with the left or right arrow keys or sliding your mouse to the left or + right. + Run + Hold down Run (the Shift key) to double your speed. + Jumping + Tap the Jump key (the space bar or Enter key). You jump further if + you're moving forward, and you jump higher if you're moving up a slope at + the time. You'll be surprised at the spots you can reach in a jump. You + can even avoid some attacks by jumping at the right time. + Swimming + When underwater, aim yourself in the direction you wish to go, and + move forward. You have full three-dimensional freedom. Unfortunately, + as in real life, you may lose your bearings while underwater. Use + jump (the space bar or Enter key) to kick straight up towards the + surface. Once on the surface, tread water by holding down jump. + To get out of the drink, swim towards the shore. Once there, use jump + to clamber up. If you're down a well or you can't get a grip, you may + not be able to climb out. There is always another way out, but you may + have to submerge to find it. + Shooting + Tap the Shoot key (the Ctrl key or left mousebutton) to fire. Hold it + down to keep firing. + Use + Quake has no "Use" function. To push a button or open a door, walk up + to it. To ride a platform up or down, step atop it. If a door won't open + or a platform won't lower, you may need to do something special to + activate it. + Picking up stuff + To pick up items, weapons, and power-ups, walk over them. If you can't + pick up something, it means you already have the maximum possible of + that thing. If it is armor, it means the stuff you're trying to get is + worse than what you now have. + +E. Finding Things + Buttons and Floorplates + Buttons activate with a touch, and floorplates must be stepped on. + If you see a distinctive-looking button in a spot you cannot reach, + it's probably a shootable button-- fire at it. + Doors + Most doors open at your approach. If one doesn't, seek a button, + floorplate, or key. + Secret Doors + Some doors are camouflaged. Almost all secret doors open when they are + shot or hit with an axe. The rest are opened by hidden pressure plates + or buttons. + Platforms + Most platforms only go up and down, while some follow tracks around + rooms or levels. When you step atop of a platform, it rises to its + full height, and usually only lowers when you step off. Some platforms + must be activated via button or pressure plate. + Pressure Plates & Motion Detectors + Invisible or visible sensors which open doors, unleash traps, warn + monsters, etc. + Uncovering Secrets + Secrets are hidden lots of ways. You might need to shoot a button, kill + a monster, walk through a secret motion detector, etc. + The Secret of Secrets + All secrets in Quake are indicated by clues. Don't waste your time + hacking at every wall. It's much more productive (and fun) to use your + brain and your eyes. Look up. An angled texture, a light shining under + a wall, a strange sound -- anything -- might be the clue. Something + prominent in a room might be decoration ... or it might be the clue. + +============================================================================= +== TIP -- Bouncing a grenade off a shootable button or secret door won't == +== open it, but if the grenade's explosion goes off nearby, this may == +== activate such secrets. == +============================================================================= + +IV. CONTROLS +A. Keyboard Commands + By using the key configuration option from the Main Menu, you can + customize the keyboard to suit your fancy, except for the Function keys, + the Escape key, and the ~ (tilde) key. + +FUNCTION KEYS +Help F1 +Save Game F2 +Load Game F3 +Options Menu F4 +Multiplayer Menu F5 +Quicksave F6 +Quickload F9 +Quit to operating system F10 +Screenshot F12 + +WEAPONS +Axe 1 +Shotgun 2 +Double Barrelled Shotgun 3 +Nailgun 4 +Supernailgun 5 +Grenade Launcher 6 +Rocket Launcher 7 +Thunderbolt 8 +Change to next weapon / + +MOVEMENT +Move / Turn arrow keys +Jump / Swim Space bar or Enter +Run Shift +Sidestep Left . or > +Sidestep Right , or < +Strafe * Alt +Swim Up D +Swim Down C + +OTHER CONTROLS +Main Menu Escape +Console ~ (tilde) +Look Up A or PgDn +Look Down Z or Del +Center View X or End +Mouse Look ** \ or center mouse button +Keyboard Look *** Ins + + * Turning right or left sidesteps instead while the Strafe key is pressed. + ** Sliding your mouse forward and back looks up and down while the Mouse + Look key is pressed. +*** The walk forward/backpedal arrows will look up and down while the + Keyboard Look key is pressed. + +B. The Main Menu + Tap the Escape key to pop up the Main Menu. While you are in the menu, + the game is paused. + Use the arrow keys to move the Quake icon up and down the menu. Place + the icon before the desired option, and tap the Enter key. To return to the + Main Menu, tap the Escape key again. To exit the menu and return to the + game, tap the Escape key when you are on the Main Menu. + + NEW GAME + Discards the game you're playing, and starts anew. + + MULTIPLAYER + Controls multiplayer game starting and details... + Name + Type your name or alias here, and all messages about you will use + this. So the computer says stuff like, "Josephine rides Bad Bill's + rocket." + Shirt Color + Lets you select your character's uniform color from 14 different + options (numbered 0-13). + Pants Color + As above, but your pants color also determines what team you're on, + if in team play. (After all, pants are more important than shirts.) + Communications Configuration + Takes you to a separate menu on which you can change communications + settings. + Com Port + Selects the COM Port to use for Communications. A null modem or + modem must be connected to this port. + Baud Rate + Selects the COM port baud rate (9600-57600bps). This is NOT the + same as setting the modem speed. The COM port speed must be AT + LEAST the same speed as the modem speed. + Device + Selects the type of connection, either direct (null-modem) or + modem. + Modem Init String + The Initialization string for the modem. + + Start a Multiplayer Game + If you want your machine to be the host for a multiplayer game + (Note: if you are starting a listen server, id Software strongly + recommends that the fastest machine act as the host! If you are + playing a game with more than 4 players, we suggest using a + dedicated server as the host!), select this option, and you'll get + the following menu ... + Begin Game + Starts up the game. Now all your friends have to do is log on, + using either "search for local network games" or "join a + running game at..." Multiplayer options (see below). + Maximum Players + You can have up to 16 players. You need at least 2, or it's not + "multiplayer", right? + Game Type + Toggles between cooperative and deathmatch. + Team Color Rules + Toggles between "none" and "no friendly fire". In the latter mode, + your shots won't injure someone wearing the exact same color + pants as you. + Skill + Chooses skill level. Only applicable in a cooperative game. + Frag Limit + From none to 100, in ten-frag increments. When someone reaches + the frag limit, by killing the 40th (or whatever) person, then + the game ends immediately, and final scores are printed. If your + frag limit is none, the game won't end till someone exits the + level or the time limit expires. + Time Limit + From none to 60 minutes, in 10 minute increments. When the time + limit is up, the game ends immediately, and final scores are + printed. If your time limit is none, the game won't end till + someone exits the level or the frag limit is reached. + Start Map + Lets you choose what map you'd like to play on. The top line + gives you the episode name, and the lower line is the level's + name. Note that all levels in Quake are fun to play, but the + episode Deathmatch Arena is composed of special levels that are + solely-designed for deathmatch play. Try them, you'll like them. + Search For Local Network Games + Has your computer look through your network. It will list all the + games it finds on the console, and you can choose to join one of + them by typing connect . + Join A Running Game At ... + Lets you join a game either by typing its net address (for a net + game) or your friend's modem phone number (for a modem game). + If necessary, ensure your modem and network connections are operative + by checking your Communications Configuration menu. + + SAVE + Brings up a list of saved games. Highlight the desired slot, and tap the Enter key. Each saved game is identified by the level's name, plus the + proportion of kills you have achieved so far. + LOAD + Brings up a list of saved games. Highlight the desired slot, and tap the + Enter key. + OPTIONS + Miscellaneous game options ... + Configure Keys + Permits you to customize Quake so every action is linked to the + button or key that you prefer. + First, move the cursor (via the arrow keys) to the action you + wish to change. Then tap the Enter key. Now press the key or + button you want to bind to that action. For instance, if you wish + to use the Alt key for Jump, move the cursor to Jump / Swim, tap + the Enter key, then press the Alt key. + Each action can have two different keys assigned to it. If you + already have two keys in an entry, you cannot add more from this + menu. + To clear the keys bound to an action, move the cursor to that + action and tap the Backspace or Delete key instead of the Enter + key. This will clear the keys formerly bound to that action, + leaving it blank. + You can bind any key to an action except Function keys, the + Escape key, and the ~ (tilde) key. "Weird" keys such as Scroll + Lock, Print Screen, etc. may or may not work, depending on your + machine, but why bother? + + Attack + Fires your weapon + Change Weapon + Switches to the weapon "above" the one you're now using. Wraps + around to the axe. + Jump / Swim Up + If you're on land, jumps. If you're underwater, kicks you + towards the surface. If you're right at the water's edge, pops + you up out of the water, if you combine it with forward + movement. + Walk Forward + Backpedal + Turn Left + Turn Right + Run + Press this while moving, and you move at double speed. + Step Left + Sidesteps (strafes) left + Step Right + Sidesteps (strafes) right + Sidestep + Press this when using turn left or turn right and you sidestep + (strafe) instead. + Look Up + Lets you angle your view upwards. Your view returns to + horizontal when you start walking forward. + Look Down + Lets you angle your view upwards. Your view returns to + horizontal when you start walking forward. + Center View + If you're looking up or down, returns your view to dead + center. + Mouse Look + Press this to allow your mouse to look up or down (by + sliding it forward and back), and to remain looking up or + down even if you move forward. + Keyboard Look + Press this to use your movement keys to look up or down. + Go To Console + Brings down the Console. Also possible by tapping the + ~ (tilde) key. + Reset To Defaults + Everything you've changed in the options menu is reset by + this option. Consider it an "Oops" key. + Screen Size + A slider which enlarges or shrinks your view area. All + Quake's sliders use the right and left arrow keys. + Brightness + Pretty much self-explanatory. Choose a brightness which + doesn't strain your eyes. + Mouse Speed + Adjusts mouse sensitivity. The further you set the slider + to the right, the quicker your mouse reacts. + Music Volume + Self-explanatory + Sound Effects Volume + Self-explanatory + Always Run + When this is selected, you do not need the Run key -- you + are always at double speed. + Invert Mouse Up / Down + This gives your mouse "airplane-style" controls. This means + that pushing the mouse forward "noses down", and pulling it + back "noses up". Some people prefer this control technique. + Lookspring + Returns your view immediately to straight ahead when you + release the look up / down key. Otherwise, you must move + forward for a step or two before your view snaps back. + Lookspring does not work while you are underwater. + Lookstrafe + If you are using the look up / down key, then this option + causes you to sidestep instead of turn when you try to move + left or right. + + HELP / ORDERING + Lists the default keyboard and mouse commands. Also contains the + information you need to register Quake. + QUIT + Exits Quake at once. + +============================================================================= +== TIP -- Quake saves your current key configuration when you quit, so == +== next time you play, you have the same configuration. == +============================================================================= + +C. Console + Tap the ~ (tilde) key to bring down the console. As with the Main Menu, + when the console is down, a singleplayer game is paused. A wide variety of + esoteric commands can be entered at the console. If your keyboard has no + ~ (tilde), the Options Menu (inside the Main Menu) has a "Console" option. + +D. Command Line + For special command line parameters, see README.TXT. + +E. Cheat Codes + id Software, as in our previous games, has removed all cheat codes from + Quake. + +V. THE GAME +A. The Screen + The large top part of the screen is the view area, in which you see + monsters and architecture. Immediately below is the Inventory, beneath + which is the Status Bar. You can enlarge the viewing area (tap the + key), + so much that it engulfs first the Inventory Bar and then the Status Bar. + The - key shrinks the view area. + + Inventory Bar + Lists ammo, weapons, deathmatch scores, and power-ups. + The active weapon is lit up. Each weapon has a number by it -- type + the appropriate number key to switch to that weapon. + In addition, this gives the amount of ammo you have of each type, + any keys you possess, and any power=ups currently active. Plus it shows + how many and which of the four Runes you possess. + In Deathmatch, it shows the top four scores in the game. + + Status Bar + A vital part of the screen. When your armor, hit points, or ammo get + low, the number turns red. + From left to right, the big numbers represent: Armor Points, Health, + and Ammo (of the current weapon). Icons show the Armor Type (green, + yellow, or red), your adorable face, and your Ammo Type). + + Score Bar + Hold down theTab key to replace the Status Bar with the Score Bar. + This lists the proportion of monsters you've killed, secrets you've + found, and time you've spent, along with the level name. + In Deathmatch, the Score bar lists the top six scorers, along with + their names. + +B. Messages + Quake talks to you from time to time. Some messages appear at the top of + the screen. These are non-critical, and tell you that you've picked up an + object, or you've died in an interesting fashion. Ignore these messages if + you please. + Certain messages appear inconveniently in the middle of your view. These + are always important, and you do not want to ignore them! + +D Ending a Level + Once you finish a level, you'll find a slipgate or a distinctive archway + leading to the next level. Pass through to emerge onto a new level. + You start the new level with the same armor, weapons, and ammo you had at + the end of the previous one. If a power-up was active at the end of the + previous level, it is now, sadly, gone. Make the best of it. If your hit + points were over 100 or under 50, they are altered to 100 or 50, + respectively. Otherwise, your hit points are unchanged. + +D. Ending a Dimension + Once you've finished all the levels in a particular dimension, you return + to the starting hall. New dimensions are started from scratch -- you, your + shotgun, and axe. + +VI. Your New Environment +A. Firepower + You are blessed with eight different Means o' Mass Destruction. Each has + its place in a balanced diet. + + Axe + The last resort. Face it -- going toe-to-toe with the uglies in Quake + demonstrates all the good sense of a man parachuting into an alligator + farm. + + Shotgun + The basic gun, to which all other guns compare favorably. + + Double-barrelled Shotgun + A worthy weapon with three minor drawbacks: first, it uses up 2 shells + per blast; second, it's slow; third, its shot pattern is very loose at + long range. But in general, once you find this puppy, the other shotgun + starts rusting from disuse. + + Nailgun + A two-barrel dingus that prickles bad guys with armor-piercing darts, + technically termed "nails". + + Supernailgun + The great equalizer. Four cyclic barrels that hose out spikes like + crazy. Pro: foes drop like flies. Con: eats ammo like popcorn. + + Grenade Launcher + Thumps neat exploding bombs into the air. You can even bounce a grenade + off the wall or floor.. When a grenade hits someone, it explodes. + If it misses, the bomb sits on the floor for a moment, then explodes. + Even though I sometimes bounce grenades into myself, this gun's still + my favorite. + + Rocket Launcher + For when a grenade positively, absolutely, has to be there on time. + + Thunderbolt + Try it. You'll like it. Use the same technique as watering your + rosebush. + + Switching Between Weapons + If you are firing a weapon and run out of ammo, Quake automatically + switches you to another weapon. It will never switch to the grenade + launcher or rocket launcher, however, for reasons that ought to be + obvious. So if you're firing away happily and suddenly switch to the + axe, it doesn't mean you're out of all ammo -- you may still have + grenades. But Quake requires you to select such dangerous + explosives on your own. + +============================================================================= +== TIP -- If you shoot the Thunderbolt underwater, it discharges all its == +== cells in every direction in a single gigantic KA-ZAP, with you at the == +== center. Don't try this at home. == +============================================================================= + +B. Ammo + The eight weapons use four types of ammo. Each ammo type comes in two + flavors -- small and large. The large boxes carry twice as much as the + small. + + Shells + For shotguns and double-barrelled shotguns. A small box holds 20. + + Flechettes + For nailguns and supernailgunss. A small box holds 25. + + Grenades + For grenade launchers and rocket launchers. A small crate holds 5. + + Cells + For Mr. Thunderbolt. A small battery has 6 charges, lasting a little + over a second. + +C. Power-ups + All power-ups except armor burn out after a while, so smoke 'em while you + got 'em. + + Armor + Comes in three flavors; green, yellow, and red, from weakest to most + powerful. + + Megahealth + Gives you 100 additional hit points. After a few seconds, all hit points + over 100 start slowing draining away, because it's too much for the human + frame to hold. Still, it's nice while it lasts. + + Biosuit + lets you breathe underwater and swim through slime without harm. Does + not protect against lava. + + Ring of Shadows + Renders you almost totally invisible. Only your eyes can be seen. + Monsters don't detect you unless you do something stupid. Like shoot. + + Pentagram of Protection + Renders you invulnerable. + + Quad Damage + Magnum upgrade! You now deliver four times the pain! + +============================================================================= +== TIP -- When quad damage is activated, use the grenade or rocket == +== launcher with care -- their bursts are four times as deadly to you, as == +== well as your enemies. == +============================================================================= + +D. Bad Guys + Quake critters are extremely tough, but you have the firepower to vent + your grievances on them anyway. Good hunting. + + Rottweiler + Bad, bad doggie! Play dead! -- blam! -- yipe! Good dog! + + Grunt + Goons with probes inserted into their pleasure centers; wired up so + when they kill someone, they get paroxysms of ecstasy. In essence, + customized serial killers. Easy to kill, and they tote shotgun shells. + It's like a little Christmas each time you blow a Grunt away! + + Enforcer (registered only) + Grunt, Mark Two. Recruits who are surlier and beefier than the rest get + outfitted in combat armor and built-in blasters. + + Knight + Canned meat. Open 'er up and see if it's still fresh. + + Death Knight (registered only) + This particular canned meat tends to open you up instead. + + Rotfish (registered only) + Disgusting little critters who dish it out, but can't take it. + + Zombie + Thou canst not kill that which doth not live. But you can blast it + into chunky kibbles. + + Scrag + Floats like a butterfly, stings like a bee. Ugly as hell. They're not + real tough, but like to bushwhack you. + + Ogre + What's worse than a cannibal monster eight feet tall? One with a + chainsaw. And a sack of grenades. + + Spawn (registered) + A merrily bouncing blob as dangerous to kill as to ignore. Blech. + + Fiend + In essence, organic buzzsaws, rife with pummeling power! + + Vore (registered) + A spideresque hybrid horror. Keep your eye on the energy pod he hurls. + + Shambler + Even other monsters fear him, so expect a clobbering. He shrugs off + explosions. Good luck. + +============================================================================= +== TIP -- Some weapons are better vs. particular monsters than others. If == +== a new monster seems real tough, switch weapons. == +============================================================================= + +E. Environmental Hazards and Effects + + Explosions + Radioactive containers are in some military bases. Shooting these + things unleashes a big boom, so be careful -- you may not want to + stand too close in a firefight. + Your own grenades and rockets cause explosions too, of course -- the + blast can hurt you if you're too close. + + Water + Safe enough unless you stay under so long you start to drown. Come up + for air periodically to prevent this. + + Slime + Hurts you instantly and keeps on hurting. Stay out of slime unless you + have a very good reason to take a dip. + + Lava + If you're quick and the lava's shallow, you might escape before you're + burnt to a crisp, but don't bet on it. + + Traps + Quake has many different traps. Don't be paranoid, because traps aren't + really very common, but be aware of their existence. Traps can't be + classified because they come in many varieties -- monsters in ambush, + spike shooters, crushing walls, trapdoors, etc. + + Teleporters + These are distinctive in appearance and emit a unique sound. When you + step into a teleporter, you're instantly transported to another + teleporter, or atop a teleport pad. If you teleport directly right atop + of somebody else, he or she is killed instantly. + +============================================================================= +== TIP -- Monsters are smart enough not to activate their own traps, but == +== if you activate the traps, the monsters can get caught by them. == +============================================================================= + +VII. Multiplayer Action + Quake can be even more fun when you're playing with friends than when + you're playing by yourself. + When you are using the console or Main Menu in multiplayer, the game does + not pause. Irresponsible players and monsters can freely shoot you, and + your only recourse is bloodthirsty vengeance. + The Talk function is useful here. When you talk, the message appears at + the top of all players' screens, preceded by the speaker's name. + To talk, press 'T' and start typing your message. Press ENTER to set + the message to everyone. + To set up, run, or join a multiplayer game, use the Main Menu Multiplayer + option. README.TXT contains details that may be useful if your network or + modem need special configurations. + +A. Cooperative + In a co-op game, you and your friends work together to finish the level. + When one person exits, everyone else exits too, wherever they might be. If + you are killed in co-op, you reappear at the start area, and have to catch + up to your buddies. Use Talk to find out where they are. See the + Multiplayer options on the Main Menu for more info. + +B. Deathmatch + In a deathmatch, play is totally cutthroat. No monsters exist, and when + you are killed, you reappear in a random spot. After you pick up an item, + it respawns (i.e. pops back into existence) after a while. (Some items + take longer to respawn than others.) Every time you kill someone, you get + a Frag. The person with the most Frags wins, so wreak slaughter amongst + your pals! + If you kill yourself, whether intentionally or by accident, you lose a + Frag. This includes drowning, getting crushed, and so forth. See the + Multiplayer options on the Main Menu for more info. + +C. Team Games + Team play is a cool combination of co-op and deathmatch. Each team picks + a "uniform" and everyone on that team changes their color to the team + color. The team with the most Frags wins. See README.TXT or the Main Menu + for details. + +============================================================================= +== TIP -- if you have the Team Color Rules set to No Friendly Fire, your == +== weapons won't hurt other players wearing the same color pants as you. == +== (You can still have differently-colored shirts.) Your shots still wear == +== down their armor, and your own grenade and rocket explosions still hurt == +== YOU, just not them. == +============================================================================= + +VIII. Commonly Asked Questions + +Q. I'm stuck. How do I get through the level? +A. Take a stroll around and look for a place you haven't been yet. Sometimes +you have to kill a particular monster in order to progress, so exterminate +them all! + +Q. How can I find all the secrets? +A. Don't worry about it. You never have to find a secret to finish a level.. +Also, some secrets are intentionally hard to find. + +Q. I've cleared out the whole level, but my monster kill score isn't 100%. +Where are they hiding? +A. Some monsters hide inside secrets, or are released by them. You won't be +able to kill those monsters until you find their secrets. Also, some monsters +might lurk underwater. Good fishing. + +Q. Don't you worry that Quake teaches people that all problems can be solved +by the misuse of deadly force? +A. No. + +Q. Did I really see two monsters fighting each other? +A. Probably. Some monsters hate one another almost as much as they hate you. +You can use this to your advantage (exercise left up to the reader). + +Q. How do I prevent motion sickness when watching Quake? +A. If you're one of the unlucky sufferers from motion sickness in Quake, +we're sorry to say the answer seems to differs from person to person. Try +sitting closer to the screen, or further away. Dim the lights in your room, +or turn them up high. Adjust screen brightness up or down. Take a break from +Quake and rest your eyes every hour or so. One or more of these tricks, or a +combination, ought to work. + +Q. Are you guys Satan-worshipers? +A. No. + +IX. Tech Support + Any of the information listed below could change. Check the id software Web +Site, at www.idsoftware.com, for updates. + +A. Tech Support Options +id Software does charge for technical support, but we strive to offer this +service at the lowest cost possible. Because volume on the support lines +dictates costs, we periodically adjust our rates for Voice Tech Support. +Check our web site for current pricing. + +Paying for Voice or Automated Support + 1 -- You can get Voice Support using a major credit card for a one-time + shot. The system asks for your credit card number and expiration date, then + pre-authorizes your credit card for the tech support call. You will only be + billed for the number of minutes actually used. + + 2 -- You can assign yourself a rechargeable PIN account. The system + prompts you for your credit card information, and assigns you a PIN account + number. You can use the PIN to access Voice Support, Automated Support and + the Game Hints Line. Once your account runs out, you can charge it up + again. + + 3 -- You may also charge up a PIN account using the number + 1 (900) call-2-id. Then call back at 1 (800) id-games, and use your + new PIN to receive all the support and hints you wish. + +Voice Support +Telephone -- 1 (800) id-games + Lines Open from 12 noon to 10pm Central Time + 7 Days a week ($1.75 per minute maximum as of this printing) + Closed some holidays +Please have the following information handy. + 1. Game title and version number. (The version number can be found in the + lower right-hand corner of the console.) + 2. Your operating system, processor, processor speed and amount of RAM. + 3. If you are having a sound, video or modem problem, we need to know the + device brand name and model. + +Automated Support +Telephone -- 1 (800) id-games + Lines Open 24 hours a day, 365 days a year (366 in Leap year) + ($0.25 per minute) +Please have pencil and paper handy + +E-mail Support + Just send your e-mail to support@idsoftware.com + We will respond within 48 hours after receiving your e-mail. When sending + e-mail, cut and paste the following into your e-mail message and fill + in the blanks -- + +Date: +Name: +Phone number: +E-mail address: (please include this, we redirect tons of mail) +Game Title: +Version #: +Operating system (eg., DOS 6.0 or Windows 95): +Computer type: +Processor type: +Processor speed: +Video card brand and model: (only if video problem) +Audio card brand and model: (only if audio problem) +Modem brand and model: (only if modem problem) +Network card brand and model: (only if netgame problem) +Network configuration (eg., NET.CFG file): (only if netgame problem) +Drivers, protocol stacks, and versions: (eg., lsl v2.14, exp16odi +v2.33, and ipxodi v3.01) (only if netgame problem) +If there were any error messages or fault information, report them +here: +Please state the problem you encountered: +Please state how to reproduce the problem: + +Web Support + Found at www.idsoftware.com + Our web support pages provide the same information that's available via + Automated Support, except it's free! + +News Sites + For information, FAQ, or announcements, check out + rec.games.computer.quake.announce + + For editing and hecking Quake-related files, check out + rec.games.computer.quake.editing + + For general Quake discussion, check out + rec.games.computer.quake.misc + +Game Hints Line +Telephone -- 1 (800) id-games or 1 (900) call-2-id + Lines Open 24 hours a day, 365 days a year (366 in Leap year) + ($0.85 per minute) + +B. In Europe + Our help lines in Europe are open 7:30am - 5:00pm GMT, Monday - Friday. + + English: +44 01923 209145 + German: +44 (0)1923 209151 + French: +44 (0)1923 209148 + +C. Problems + If you have an unfavorable experience using our services, please send + e-mail to support@idsoftware.com. Kindly include your full name, + address, phone number, and the problem encountered. + +X. LEVELS & DESIGNERS + +*************************************** +The Beginning +start -- Welcome to Quake -- by John Romero +*************************************** +Dimension of the Doomed (shareware episode) +e1m1: Slipgate Complex -- by John Romero +e1m2: Castle of the Damned -- by Tim Willits +e1m3: The Necropolis -- by Tim Willits +e1m4: The Grisly Grotto -- by Tim Willits +e1m5: Gloom Keep -- by Tim Willits +e1m6: The Door To Chthon -- by American McGee +e1m7: The House of Chthon -- by American McGee +*************************************** +Realm of Black Magic +e2m1: The Installation -- by John Romero +e2m2: Ogre Citadel -- by John Romero +e2m3: Crypt of Decay -- by John Romero +e2m4: The Ebon Fortress -- by John Romero +e2m5: The Wizard's Manse -- by John Romero +e2m6: The Dismal Oubliette -- by John Romero +*************************************** +Netherworld +e3m1: Termination Central -- by John Romero +e3m2: The Vaults of Zin -- by American McGee +e3m3: The Tomb of Terror -- by American McGee +e3m4: Satan's Dark Delight -- by American McGee +e3m5: Wind Tunnels --by Tim Willits +e3m6: Chambers of Torment -- by American McGee & Tim Willits +*************************************** +The Elder World +e4m1: The Sewage System -- by Tim Willits +e4m2: The Tower of Despair --by Sandy Petersen +e4m3: The Elder God Shrine --by Sandy Petersen +e4m4: The Palace of Hate --by Sandy Petersen +e4m5: Hell's Atrium --by Sandy Petersen +e4m6: The Pain Maze --by Sandy Petersen +e4m7: Azure Agony --by Sandy Petersen +*************************************** +The End +end: Shub-Niggurath's Pit --by John Romero +*************************************** +The Deathmatch Arenas +dm1: Place of Two Deaths --by Tim Willits +dm2: Claustrophobopolis --by American McGee +dm3: The Abandoned Base --by John Romero +dm4: The Bad Place --by American McGee +dm5: The Cistern --by Tim Willits +dm6: The Dark Zone --by Tim Willits +*************************************** +??? +Ziggurat Vertigo --by American McGee +Underearth --by Tim Willits +The Haunted Halls -- by American McGee +The Nameless City -- by Sandy Petersen +*************************************** + +XI. Legal Boilerplate + Quake (tm) (c) id Software, Inc. All rights reserved. All trademarks are + the property of their respective companies. For full information on the + legal issues of owning and using Quake, please refer to the files + LICINFO.TXT and ORDER.TXT. + +The program you've purchased was produced through the effort of many people. +Don't make copies for others who have not paid for the right to the +registered version of Quake. To report copyright violations to the Software +Publishers Association, call 1 (800) 388-PIR8 or write: + + Software Publishers Association + Suite 901 + 1101 Connecticut Avenue NW + Washington, DC 20036 + +XII. MUSIC CREDITS + +Titles of Songs or Themes (C) 1996 TVT/Interscope Records. +All Rights Reserved. +Written by Trent Reznor (C) 1996 Leaving Hope/TVT Music. +ASCAP All Rights Reserved. + +Note: music is ONLY available on CD. See your local software retailer +or order Quake today at 1-800-idgames! + +XIII. Thanks + +id Software would like to give special thanks to: + +Sean Barrett +Raymond Chen +DJ Delorie +Andy Glew +Lance Hacking +Chris Hecker +Todd Laney +Terje Mathisen +Charles Sandmann +Jon Vondrak +Billy Zelsnack +The GameTech crew +Syntrillium Software for CoolEdit diff --git a/engine/docs/ORDER.TXT b/engine/docs/ORDER.TXT new file mode 100644 index 0000000..fb4598d --- /dev/null +++ b/engine/docs/ORDER.TXT @@ -0,0 +1,103 @@ +ORDERING INFO + To order the full version of Quake (or any other id Software +product) in North America, call our fulfillment center at 1-800-idgames +(1-800-434-3627). Except as noted by our operators, you can expect +Airborne Express afternoon delivery. The price for the full version +of Quake (available on PC CDROM only) is $45, plus $5 shipping, for a +total of $50. Our fulfillment center accepts Visa, Mastercard, and +American Express. You can also fax, mail, or email your order using +the attached forms. The fax number is (317) 361-3710 and the email +address is idsoftware@stream.com. To prepay and order with a check +by mail, send your check and the order form to: + + id Software + P.O. Box 4500 + Crawfordsville, IN 47933 + + To see an electronic catalog of our software, tshirts, hint books, and + other merchandise available, check out the Shopping Maul section of our + website at www.idsoftware.com. + +INTERNATIONAL ORDERS +Quake is available worldwide as a full retail product. To find out +which local stores carry Quake and other id products, contact the +following international affiliates: + +Europe Australia +GT Interactive Software Roadshow New Media +1712 583791 (U.K.) 1 902 962000 + +Taiwan Singapore +U.S. Summit Corporation Summit Co. (Singapore) Pte. Ltd. +706-0660 273-9988 + +Malaysia Honk Kong +Summit Co. (Malaysia) Sdn Bhd Tsun Tsun Trading Company +757-2244 571-4231 + +Thailand Israel/Jordan/Lebanon/Egypt +U.S. Summit Corp. (Overseas) Mirage Mulimedia +374-3956 972 3 510 5764 + +If you are in a territory that cannot access 1(800)idgames, and you +wish to order our products directly, you must place your order in +writing to the fax, mail, or email addresses listed above under +ORDERING INFO. + +International phone orders will NOT be accepted. Unfortunately, due +to international shipping costs, all international orders are sent +out via US Mail. This means we cannot guarantee timeliness of delivery +due to customs and other delays inherent to international shipping +______________________________________________________________________ + ORDER FORM -- USE THIS FORM TO FAX , MAIL OR EMAIL YOUR ORDER. + +id Software Order Center Date ______________ +PO BOX 4500 Phone: 1800 id games +Crawfordsville, IN 47933 Fax: (317) 361-3710 + idsoftware@stream.com + + +Product List and Prices in U.S. Currency: (check items) + +Quake (CD ROM only) $45 ____ +The Ultimate DOOM (Mac version available – must specify) $25 ____ +DOOM II (Mac version available – must specify) $40 ____ +Master Levels for DOOM II (CD ROM only) $25 ____ +Final DOOM (CD ROM only) $40 ____ +DOOM Hint Book $15 ____ +Original DOOM Tshirt (S,M.L.XL) $13 ____ +The Ultimate DOOM Tshirt (XXL only) $13 ____ +Final DOOM Tshirt $13 ____ +Heretic:Shadow of the Serpent Riders (CD ROM only) $40 ____ +Heretic Hint Book $15 ____ +Hexen:Beyond Heretic (Mac version available – must specify) $40 ____ +Hexen:Deathkings of the Dark Citadel (CD ROM only) $25 ____ +Hexen Hint Book $15 ____ +Hexen Tshirt (XXL only) $13 ____ +Wolfenstein 3D (PC CD only) $20 ____ +Commander Keen (3.5 disk only) $15 ____ + + Order total: $______ + +Name: Age (optional): + +Form of payment (check, money order, or credit card): + +Credit card number: Expiration Date: + +Exact mailing address:______________________________________ + _______________________________________ + _______________________________________ + _______________________________________ + +Phone: Fax: Email: + +Shipping: US orders-$5.00 first product/$2.00 each additional +(allow 3-5 business days) + +International shipping for prepaid orders are via US Mail, and +we cannot guarantee the time it will take to arrive. + +*Prices subject to change + + diff --git a/engine/docs/README.TXT b/engine/docs/README.TXT new file mode 100644 index 0000000..fc62729 --- /dev/null +++ b/engine/docs/README.TXT @@ -0,0 +1,456 @@ +Welcome to Quake! + +This file details how to get Quake running on your system and what to do +if you have problems. We would like to thank Gandalf Technologies, Inc and +MPath Interactive for the use of their technology. We would also like to +thank Trent Reznor and Nine Inch Nails for their tremendous contributions +to Quake's entire audio portion. + +The NIN logo is a Registered Trademark licensed to Nothing Interactive, Inc. +All Rights Reserved. + +Quake System Requirements +------------------------- +IBM PC and Compatibles +Pentium processor or better +VGA Compatible Display or better +8MB RAM minimum, 16MB recommended (16 MB required for running under Win95) +CD-ROM drive Required +MS-DOS 5.0 or better or Windows 95 (does NOT run under Windows NT) +Hard Drive (30MB for Shareware, 80 MB for Registered) + +*** IMPORTANT!: Quake requires a floating point processor. +Systems that do not have an FPU installed will not run Quake -- at all. + +*** IMPORTANT Video Adapter Note! *** +On some ATI Mach32 cards, Quake can come up with a garbled video display. +This is due to a problem with the card in which 320x200 mode isn't +initialized correctly. Workarounds include: + +1) If running from Windows, start Quake from an icon, or from a windowed +(not fullscreen) MS-DOS prompt. If Quake is already running and has +the garbled screen, press Alt-Enter twice to switch to the desktop and +back to fullscreen, and the screen will display properly. + +2) If running from DOS, either put the line + +vid_mode 1 + +in id1\autoexec.cfg, or, typing blind, press tilde ('~') to bring down +the console, type + +vid_mode 1 + +and the screen will display properly. + +======================================================================== +Here are the text files included with the shareware release of Quake and +what they are: + +README.TXT This file +TECHINFO.TXT Technical information on Quake's subsystems and + their advanced use. +MANUAL.TXT Text version of the printed game manual +LICINFO.TXT Info on the various license files included with Quake +SLICNSE.TXT Shareware Quake end-user license +ORDER.TXT How to order Quake +HELP.TXT How to get help with Quake + +Here are the text files included with the registered version of Quake and +what they are: + +README.TXT This file +TECHINFO.TXT Technical information on Quake's subsystems and + their advanced use. +MANUAL.TXT Text version of the printed game manual +LICINFO.TXT Info on the various license files included with Quake +RLICNSE.TXT Registered Quake end-user license +COMEXP.TXT Commercial exploitation agreement +ORDER.TXT How to order Quake +HELP.TXT How to get help with Quake + + +Running Quake +------------- + +DOS: To launch Quake from the DOS Prompt, go to the Quake directory and +simply type "QUAKE" . (no quotes) + +Windows 95: To launch Quake in single player mode, double click on the file +QUAKE.EXE From Windows Explorer. To run Quake in Multi-Player mode using +the TCP/IP protocol, first check your network settings to ensure the +protocol is installed, then double click on the Q95.BAT file to launch the +game. In this version (v0.91) there is a minor bug that will cause the +Q95.BAT file to exit the first time you run it, without running Quake. +Merely double-click on that file again and it will work. + +Audio Setup +----------- + +When using a Sound Card with Quake, there are a few setup steps which must +be taken. First, the "BLASTER" environment variable setting must be in your +autoexec.bat (or you can type it in manually from the MS-DOS command prompt). +Running the Sound Blaster utility diagnose.exe will automatically configure +your sound card and put this statement in your autoexec.bat file for you. +A typical blaster setting looks like this (although yours may vary): + +SET BLASTER=A220 I5 D1 H5 P330 T6 + +If you want to play the audio track from the CD-ROM while playing Quake, +you must ensure that the audio cable from the CD-ROM is connected to the +sound card. + +If you think your sound card is setup properly and it STILL doesn't work, +check to make sure that your BLASTER environment variable contains the +high DMA setting (H5 in the above example). + +If you don't get sound while trying to play the audio track, check to see +if a small cable goes from the back of your CD-ROM player directly to your +sound card. If the CD-ROM audio cable is connected to your sound board (or +the motherboard in some cases) and you STILL don't hear CD Audio coming from +your speakers, make sure the MIXER program has the CD volume turned up. +You will also need to run the CD-ROM driver MSCDEX.EXE. Here is an example +of the files you should see (yours probably will vary) listed in your +CONFIG.SYS and AUTOEXEC.BAT (explanation is in parentheses): + +CONFIG.SYS: + +DEVICE=C:\PROSCSI\CDROM.SYS /D:PROCD01 (CD-ROM driver) + +AUTOEXEC.BAT: + +SET BLASTER=A220 I5 D1 H5 P330 T6 (sound environment variable setting) +C:\WINDOWS\COMMAND\MSCDEX.EXE /D:PROCD01 /L:D (CD-ROM driver) + +=================================================== +UltraSound MAX and UltraSound PnP Support for Quake +=================================================== + +Before running Quake, make sure that your sound card works and your +environment variables are set correctly. + +Other UltraSound Cards (ACE & Classic) +-------------------------------------- +These drivers are not for the UltraSound ACE or UltraSound Classic +sound cards. We have heard mixed reports that MegaEm or SBOS +have a chance of working with the UltraSound Classic but there is a +short sound F/X delay. + +UltraSound PnP and PnP Pro +-------------------------- +You must make sure that you do NOT have IWSBOS or MegaEm loaded. + +Setup +----- +Quake will automatically detect that the UltraSound Max or PnP +are installed. It does this by looking at the SET INTERWAVE (PnP) +and SET ULTRA16 (Max) environment variables. + +Quake will use the settings found on the SET ULTRASND/ULTRA16 (Max) +and in the IW.INI (PnP) file to determine what port settings to use. + +Troubleshooting Windows 95 (DOS Box) +------------------------------------ +We recommend that you restart your computer in MS-DOS Mode. DOS Box +may or may not work, so use at your own risk. + +CD Audio Input +-------------- +If you have not already enabled CD audio output by default you will +need to enable it. For the UltraSound MAX you can run "ULTRINIT -EC". +For the UltraSound PnP you will need to enable the CD audio output +in Win'95 and then restart your computer into MS-DOS. + +=================================================== +Mouse Setup +----------- + +If you are going to use a mouse when playing Quake, you will need to load +your mouse driver. This should go in the AUTOEXEC.BAT file as well. Here +is an example: + +C:\LOGITECH\MOUSE\MOUSE.EXE (mouse driver) + + +Booting Clean +------------- + +If you are going to be running Quake with only 8 megabytes of RAM, it is best +to boot clean . You eliminate unwanted utilities or applications from taking +up valuable memory, without having to alter your regular AUTOEXEC.BAT and +CONFIG.SYS. Booting clean can be done in one of two ways. If you have +MS-DOS version 6.xx, booting clean is as simple a pressing the shift key +when you see the words "Starting MS-DOS". If you have MS-DOS ver 5.xx you +will need to make a system disk. + +To make a boot disk, type the following from the MS-DOS command prompt: + +FORMAT A: /S + +1. Make sure that this is a disk you wish to erase. +2. This disk absolutely HAS to be formatted in the A: drive. + +To use the system disk, place the disk in the A: drive and reset the +computer. + +NOTE: If your sound card requires a driver to be loaded, or you will be +using a mouse, or you will be using Quake's CD audio feature, the system +disk will need to have a CONFIG.SYS and AUTOEXEC.BAT that load the +appropriate drivers. + +Creating a Quake Shortcut + +As an alternative to making a Boot Disk, Windows 95 users can create a +Quake Shortcut. By double clicking onthis shortcut, Windows 95 will reboot +in MS-DOS mode and install only the desired drivers, giving you the same +results as using a Boot Disk. To create a Quake Shortcut, do the following: + +1. Using Explorer, right click and drag the file QUAKE.EXE, from the Quake + directory, to your desktop. Windows 95 will make an MS-DOS Icon titled + "Shortcut to quake". +2. Right click on the new icon, and from the menu that pops up, choose + "Properties". Then choose the "Program" tab at the top. +3. Now click on the "Advanced..." button near the bottom. The "Advanced + Program Settings" window should appear. +4. Select the "MS-DOS mode" check box and the "Specify a new MS-DOS + configuration" option button. +5. Now simply fill in the "CONFIG.SYS for MS-DOS mode:" and "AUTOEXEC.BAT + for MS-DOS mode:" boxes with the same sound, CD-ROM and mouse settings as + mentioned above in the Boot Disks section. +6. Click on "OK" when you are finished. If you wish, you can change your + Quake Shortcut Icon to something a little more exciting by clicking on + "Change Icon...". +7. To finish, click on "OK" again. + 8. You can rename your Quake Shortcut by right clicking on the shortcut + icon, choosing "Rename" and typing in the new name. + + +====================================================== +== Known Problems == +====================================================== + +Problem: Zombies sometime get stuck on the ground and connot get back up. +(You can still hear them, but you cannot kill them. This bug makes it +impossible to get 100% kills on whatever level it occurs on.) +Solution: There is no workaround for this bug. + +Problem: It is sometimes possible for the player to get stuck in a room or +in a wall. +Solution: If you get stuck, use the 'kill' console command. It is a good +idea to save your game often. + +Problem: View centering problems. Sometimes during a game, the view will not +center properly. The end result is the player view looking up torwards the +ceiling while walking. +Solution: Exit to the next level or use the 'kill' console command.. + + +====================================================== +== Troubleshooting == +====================================================== + +If Quake fails to start up, or has problems not addressed elsewhere in the +documentation, try the -safe command line switch, which disables a number +of parts of Quake that can be problems if there are hardware or configuration +problems. The -safe command line switch is equivalent to -stdvid, -nosound, +-nonet, and -nocdaudio together. Those four switches do the following: + +-stdvid: disables VESA video modes. + +-nosound: disables sound card support. + +-nonet: disables network card support. + +-nocdaudio: disables CD audio support. + +If -safe makes the problem go away, try using each of the switches +individually to isolate the area in which you're experiencing the problem, +then either correct the configuration or hardware problem or play Quake with +that functionality disabled. + +If you still have problems, try booting clean in conjunction with +the -safe command line parameter. For information on booting clean, refer +to the "Booting Clean" section above. + +If you experience page faults while running Quarterdeck's QDPMI DPMI server, +this is caused by a bug in QDPMI. Workarounds: Remove QDPMI from CONFIG.SYS, +issue the command QDPMI OFF before running QUAKE, or get the update patch +for QDPMI from Quarterdeck. You may be running QDPMI without knowing it if +you have QEMM installed, because it can be installed as part of the QEMM +installation. + + +Technical Support +----------------- + +If you are having trouble installing or running Quake you can receive +technical support by sending e-mailing to support@idsoftware.com. You can +also refer to our web page, www.idsoftware.com, or call 1-800-idgames. + +When sending support e-mail, cut and paste the following into your e-mail +message and fill in the blanks: + +Date: +Name: +Phone number: +E-mail address: (please include this, we redirect tons of mail) +Game Title: +Version #: +Operating system (i.e., DOS 6.0 or Windows 95): +Computer type: +BIOS date: +BIOS version: +Processor type: +Processor speed: +Do you program at school/work? +Do you provide tech. support at school/work? +Please state the problem you encountered: +Please state how to reproduce the problem: + +If program crashed with nasty undecipherable techno-garbage, please +look for the eight-digit hex number which comes after "eip=" +and write it down here: + +** NOTE: If you are sending a bug report, PLEASE refer to the TECHINFO.TXT +file for the correct form and procedures. + + +====================================================== +== Version History == +====================================================== +v1.01 -- Bugs fixed +------------------------------------------------------ +* Fixed modem code +* Fixed fraglimit & timelimit +* Added NOEXIT cvar (so no one can exit a level) +------------------------------------------------------ +v1.00 -- Bugs fixed +------------------------------------------------------ +* Gravis Ultrasound audio support (still has bugs) +* More deathmatch start spots on E1M6 and END +* Print server version and PROG CRC on connect +* -dedicated starts start.map if nothing else specified +* fixed lookspring function during net game +* fixed rare crash during long running dedicated server +------------------------------------------------------ +v0.94 -- Bugs fixed / Features added -- LIMITED BETA VERSION +------------------------------------------------------ +* Totally rewritten menus +* New lighting model with overbrighting +* Parsed lowercase BLASTER parms +* Better Sound Blaster shutdown code +* Rewrote BLASTER initialization +* Fixed DMA channel 0 bugs +* Added SBPro 8 stereo setup +* Fix delayed sound on 8 bit Sound Blasters +* Fixed speed key affecting angle-turning from keyboard +* Fixed "no such Alias frame" bugs +* Fixed Zombie not getting up bug +* Checked for very high joystick values, signalling a failed read +* Unstuck jumping Fiends and Spawn +* Fixed large BModels blinking out in complex areas +* Fixed s_localsound with no sound started +* Saved spawn parms in savegame +* Fixed screenshot save location +* Bind with no arguments no longer clears value +* Allow console in intermission / finale +* Fixed false gib messages +* Full-screen TAB scoreboard in DeathMatch +* Fixed "+playdemo " from command line +* Trapped overflow in sizebuf messages +* Moveup / movedown in water! +* Fixed-up Talk command +* Added unsupported crosshair option ("crosshair 1" from console) +* Colored chat messages with notify sound +* Fixed "connect during intermission" bug +* Changelevel while demos running no longer crashes +* Fixed changelevel with no map left up loading screen +* Fixed long names entered from the console causing crash +* Stopped demos changing while in the menus + +* Fixed modem initialization from menu +* Fixed serial reliable stream getting stalled +* Serial/modem code fixes + 16550a lost transmit buffer empty interrupts + fixed sometimes processing interrupts from com1 when using com2 + added com3/com4 support from menus + fixed first character of modem init not getting sent + saved serial/modem settings in config.cfg +* Fixed name and colors not always sent to server at startup +* Fixed "stopdemo" crashing the system when there wasn't a demo playing +* Added server's TCP/IP and IPX addresses (if available) to status command + +* In 0.92, an additional check for a usable VESA video mode was added; +the numpages field was verified to be greater than 0, and no mode was +supported that had numpages set to 0 (which indicates that there's not +enough video memory for that mode). ATI's VESA driver, m64vbe, +reports 0 for numpages, so VESA video modes that were available in 0.91 +were no longer available in 0.92. This extra numpages check has +been removed. + +----------------------------------------------------------------------- +v0.93 -- Never officially released; internal testing only. +----------------------------------------------------------------------- +v0.92 -- Bugs fixed +----------------------------------------------------------------------- +Typing long strings in the hostname or modem init field in the menus caused +crashes. + +Under Win95 IPX was detected but not functional, resulting in the game +exiting to DOS. + +If -nosound, got "S_LocalSound: can't cache" on every keypress in the menu. + +When vid_nopageflip was set to 1 in VESA modes, going underwater resulted in +only the upper left corner of the drawing area being updated. + +The single player scoreboard (tab) printed text incorrectly in all modes +greater than 320 pixels wide. + +On network connections that dropped packets, the reliable message stream +could get stopped up, resulting in frag counts and talk messages no longer +being delivered, although game movement continued. + +The com port settings from the menu were getting saved & restored but +not used. + +Direct serial connections did not work with slist. + +Quake now checks the vesa information for hardware incabable of page-flipping. + +Menu sound sometimes didn't play. + +Q95 (qlaunch.exe) frequently failed to execute on the first attempt. + +Q95 (quakeudp.dll) was running out of buffers when running a server. + +Teams were not being set according to pants colors. + + +Joystick notes +-------------- +Your joystick must be plugged in when Quake is launched. + +If you have a joystick plugged in, but don't want to use it in Quake +(it slows the game down a few percent), or you have weird hardware that +doesn't like being tested as a joystick add "-nojoy" to your Quake +command line. + +You can turn off joystick reading during the game by typing "joystick 0" at +the Quake command console. + +You MUST configure your buttons from the configure keys menu before they will +work. There is no default configuration. + +If your joystick or interface card improperly sets the third or fourth +joystick buttons, type "joybuttons 2" at the quake console or in your +.CFG file. + +The "mlook" button command now lets the joystick as well as the mouse control +pitch angles. + +The "sidestep" buttom command works on joysticks as with mice and keyboard +movement. + +The "invert mouse up/down" menu option also inverts the joystick pitch +direction. diff --git a/engine/docs/RLICNSE.TXT b/engine/docs/RLICNSE.TXT new file mode 100644 index 0000000..a3fdc35 --- /dev/null +++ b/engine/docs/RLICNSE.TXT @@ -0,0 +1,204 @@ +REGISTERED VERSION: QUAKE +LIMITED USE SOFTWARE LICENSE AGREEMENT + + This Limited Use Software License Agreement (the +"Agreement") is a legal agreement between you, the end-user, and Id +Software, Inc. ("ID"). By continuing the installation of this game +program, by loading or running the game, or by placing or copying +the game program onto your computer hard drive, you are agreeing to +be bound by the terms of this Agreement. If you do not agree to +the terms of this Agreement, promptly return the game program and +the accompanying items (including all written materials), along +with your receipt to the place from where you obtained them for a +full refund. + +ID SOFTWARE LICENSE + + 1. Grant of License. ID grants to you the limited +right to use one (1) copy of the enclosed or foregoing game program +(the "Software") on a single computer. You have no ownership or +proprietary rights in or to the Software or the written materials +accompanying the Software. For purposes of this section, "use" +means loading the Software into RAM, as well as installation on a +hard disk or other storage device. You may create a map editor, +modify maps and make your own maps (collectively referenced as the +"Permitted Derivative Works") for the Software. Permitted +Derivative Works may not be sold, whether by you or by any other +person or entity, but you may exchange the Permitted Derivative +Works at no charge amongst other end-users. The Software, together +with any archive copy thereof, shall be either returned to ID or +destroyed when no longer used in accordance with this Agreement, or +when the right to use the Software is terminated. You agree that +the Software will not be shipped, transferred or exported into any +country in violation of the U.S. Export Administration Act (or any +other law governing such matters) and that you will not utilize, in +any other manner, the Software in violation of any applicable law. + + 2. Commercial Use is Prohibited. Except as provided in +paragraph 5. hereinbelow in regard to the Software, under no +circumstances shall you, the end-user, be permitted, allowed or +authorized to commercially exploit the Software, any data +comprising the Software. Neither you nor anyone at your direction +shall do any of the following acts (any such acts shall be deemed +void and a breach of this Agreement) with regard to the Software, +or any portion thereof, such as a screen display or a screenshot: + + a. Rent the Software; + + b. Sell the Software; + + c. Lease or lend the Software; + + d. Offer the Software on a pay-per-play basis; + + e. Distribute, by electronic means or otherwise, the + Software for money or any other consideration; or + + f. In any other manner and through any medium + whatsoever commercially exploit the Software or use + the Software for any commercial purpose. + + 3. Additional Prohibited Uses. Neither you nor anyone +at your direction shall take the following action in regard to the +Software, or any portion thereof, such as a screen display or a +screenshot: + + a. Modify, disassemble, reverse engineer or decompile + the Software; + + b. Translate the Software; + + c. Reproduce the Software; + + d. Publicly display the Software; + + e. Prepare derivative works based upon the Software + (except Permitted Derivative Works); or + + f. Distribute, by electronic means or otherwise, the + Software. + + 4. Use of Other Material is Prohibited. Use, in any manner, of + the trademarks, such as Quake(tm) and the NIN(r) logo, logos, symbols, + art work, images, screen displays or screenshots, sound effects, music, + and other such material contained within, generated by or relating to + the Software is prohibited. + + 5. To Receive Permission to Commercially Exploit. If +you desire to commercially exploit the Software, you may execute +the Commercial Exploitation License Agreement for QUAKE (the +"License") contained within the QUAKE install package and forward +the original License to Id Software at the address noted therein. +Please note that ID may refuse your request and not sign the +License in ID's sole discretion. + + 6. Restrictions Apply to Third Parties. The +prohibitions and restrictions described herein apply to anyone in +possession of the Software and/or Permitted Derivative Works. + + 7. Copyright. The Software and all copyrights related +thereto (including all characters and other images generated by the +Software or depicted in the Software) is owned by ID and is protected +by United States copyright laws and international treaty provisions. +You must treat the Software like any other copyrighted material, +except that you may either (a) make one copy of the Software solely +for back-up or archival purposes, or (b) transfer the Software to a +single hard disk provided you keep the original solely for back-up or +archival purposes. You may not otherwise reproduce, copy or disclose +to others, in whole or in any part, the Software. You may not copy +the written materials accompanying the Software. The same +restrictions and prohibitions regarding your use of the Software as +provided in this Agreement apply to your use of the written materials +accompanying the Software. The written materials are owned by ID and +are protected by United States copyright laws and international +treaties. You agree to use your best efforts to see that any user of +the Software licensed hereunder complies with this Agreement. + + 8. Limited Warranty. ID warrants that if properly +installed and operated on a computer for which it is designed, the +Software will perform substantially in accordance with the +accompanying written materials for a period of ninety (90) days +from the date of purchase of the Software. ID's entire liability +and your exclusive remedy shall be, at ID's option, either (a) +return of the price paid or (b) repair or replacement of the +Software that does not meet ID's Limited Warranty. To make a +warranty claim, return the Software to the point of purchase, +accompanied by proof of purchase, your name, your address, and a +statement of defect, or return the Software with the above +information to ID. This Limited Warranty is void if failure of the +Software has resulted in whole or in part from accident, abuse, +misapplication or violation of this Agreement. Any replacement +Software will be warranted for the remainder of the original +warranty period or thirty (30) days from your receipt of the +replacement software, whichever is longer. This warranty allocates +risks of product failure between Licensee and ID. ID's product +pricing reflects this allocation of risk and the limitations of +liability contained in this warranty. + + 9. NO OTHER WARRANTIES. ID DISCLAIMS ALL OTHER +WARRANTIES, BOTH EXPRESS IMPLIED, INCLUDING BUT NOT LIMITED TO, +IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR +PURPOSE WITH RESPECT TO THE SOFTWARE AND THE ACCOMPANYING WRITTEN +MATERIALS. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL RIGHTS. +YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO +JURISDICTION. ID DOES NOT WARRANT THAT THE OPERATION OF THE +SOFTWARE WILL BE UNINTERRUPTED, ERROR FREE OR MEET LICENSEE'S +SPECIFIC REQUIREMENTS. THE WARRANTY SET FORTH ABOVE IS IN LIEU OF +ALL OTHER EXPRESS WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS, +EMPLOYEES, DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO +MAKE MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON +BEHALF OF ID. ADDITIONAL STATEMENTS SUCH AS DEALER ADVERTISING OR +PRESENTATIONS, WHETHER ORAL OR WRITTEN, DO NOT CONSTITUTE +WARRANTIES BY ID AND SHOULD NOT BE RELIED UPON. + + 10. Exclusive Remedies. You agree that your exclusive +remedy against ID, its affiliates, contractors, suppliers, and +agents for loss or damage caused by any defect or failure in the +Software regardless of the form of action, whether in contract, +tort, including negligence, strict liability or otherwise, shall be +the return of the purchase price paid or replacement of the +Software. This Agreement shall be construed in accordance with and +governed by the laws of the State of Texas. Copyright and other +proprietary matters will be governed by United States laws and +international treaties. IN ANY CASE, ID SHALL NOT BE LIABLE FOR +LOSS OF DATA, LOSS OF PROFITS, LOST SAVINGS, SPECIAL, INCIDENTAL, +CONSEQUENTIAL, INDIRECT OR OTHER SIMILAR DAMAGES ARISING FROM +BREACH OF WARRANTY, BREACH OF CONTRACT, NEGLIGENCE, OR OTHER LEGAL +THEORY EVEN IF ID OR ITS AGENT HAS BEEN ADVISED OF THE POSSIBILITY +OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. Some +jurisdictions do not allow the exclusion or limitation of +incidental or consequential damages, so the above limitation or +exclusion may not apply to you. + + 11. General Provisions. Neither this Agreement nor any +part or portion hereof shall be assigned, sublicensed or otherwise +transferred by you. Should any provision of this Agreement be held +to be void, invalid, unenforceable or illegal by a court, the +validity and enforceability of the other provisions shall not be +affected thereby. If any provision is determined to be +unenforceable, you agree to a modification of such provision to +provide for enforcement of the provision's intent, to the extent +permitted by applicable law. Failure of a party to enforce any +provision of this Agreement shall not constitute or be construed as +a waiver of such provision or of the right to enforce such +provision. If you fail to comply with any terms of this Agreement, +YOUR LICENSE IS AUTOMATICALLY TERMINATED. + + YOU ACKNOWLEDGE THAT YOU HAVE READ THIS AGREEMENT, THAT YOU +UNDERSTAND THIS AGREEMENT, AND UNDERSTAND THAT BY CONTINUING THE +INSTALLATION OF THE SOFTWARE, BY LOADING OR RUNNING THE SOFTWARE, OR +BY PLACING OR COPYING THE SOFTWARE ONTO YOUR COMPUTER HARD DRIVE, YOU +AGREE TO BE BOUND BY THIS AGREEMENT'S TERMS AND CONDITIONS. YOU +FURTHER AGREE THAT, EXCEPT FOR WRITTEN SEPARATE AGREEMENTS BETWEEN ID +AND YOU, THIS AGREEMENT IS A COMPLETE AND EXCLUSIVE STATEMENT OF THE +RIGHTS AND LIABILITIES OF THE PARTIES. THIS AGREEMENT SUPERSEDES ALL +PRIOR ORAL AGREEMENTS, PROPOSALS OR UNDERSTANDINGS, AND ANY OTHER +COMMUNICATIONS BETWEEN ID AND YOU RELATING TO THE SUBJECT MATTER OF +THIS AGREEMENT. + +June 21, 1996 + +REGISTERED VERSION: QUAKE LIMITED USE SOFTWARE LICENSE AGREEMENT Page 4 +(DWC:dw:3406.0024:DWC\doc:1164) + + diff --git a/engine/docs/SLICNSE.TXT b/engine/docs/SLICNSE.TXT new file mode 100644 index 0000000..057302b --- /dev/null +++ b/engine/docs/SLICNSE.TXT @@ -0,0 +1,175 @@ +SHAREWARE VERSION: QUAKE +LIMITED USE SOFTWARE LICENSE AGREEMENT + + This Limited Use Software License Agreement (the "Agreement") is a + legal agreement between you, the end-user, and id Software, Inc. + ("ID"). By continuing the installation of this game program, by + loading or running the game, or by placing or copying the game + program onto your computer hard drive, you are agreeing to be bound + by the terms of this Agreement. + +ID SOFTWARE LICENSE + + 1. Grant of License. ID grants to you the limited right to use + one (1) copy of the enclosed or foregoing Id Software game program + (the "Software"), which is the shareware version or episode one of + the game program. For purposes of this section, "use" means loading + the Software into RAM, as well as installation on a hard disk or + other storage device. You agree that the Software will not be + shipped, transferred or exported into any country in violation of + the U.S. Export Administration Act (or any other law governing such + matters) and that you will not utilize, in any other manner, the + Software in violation of any applicable law. + + 2. Commercial Use is Prohibited. Under no circumstances shall + you, the end-user, be permitted, allowed or authorized to + commercially exploit the Software, or any portion thereof, such + as a screen display or a screenshot. Neither you nor anyone at your + direction shall do any of the following acts: + + a. Rent the Software; + + b. Sell the Software; + + c. Lease or lend the Software; + + d. Offer the Software on a pay-per-play basis; + + e. Distribute the Software for money or any other + consideration; or + + f. In any other manner and through any medium + whatsoever commercially exploit the Software or use + the Software for any commercial purpose. + + 3. Additional Prohibited Uses. Neither you, nor anyone at your + direction, shall take the following action in regard to the + Software, or any portion thereof, such as a screen display or + a screenshot: + + a. Modify, disassemble, reverse engineer or decompile + the Software; + + b. Translate the Software; + + c. Reproduce the Software; + + d. Publicly display the Software; or + + e. Prepare derivative works based upon the Software. + + 4. Use of Other Material is Prohibited. Use, in any manner, of + the trademarks, such as Quake(tm) and the NIN(r) logo, logos, symbols, + art work, images, screen displays or screenshots, sound effects, music, + and other such material contained within, generated by or relating to + the Software is prohibited. + + 5. Restrictions Apply to Third Parties. The prohibitions and + restrictions described herein apply to anyone in possession of + the Software. + + 6. Permitted Distribution. So long as this Agreement + accompanies the Software at all times, ID grants to Providers the + limited right to distribute, free of charge, except normal access + fees, and by electronic means only, the Software; provided, however, + the Software must be so electronically distributed only in a + compressed format. The term "Providers," as used in the foregoing + sentence, shall mean persons whose business it is to provide + services on the Internet, on commercial online networks, or on the + BBS. Anyone who receives the Software from a Provider shall be + limited to all the terms and conditions of this Agreement. Further, + ID grants to you, the end-user, the limited right to distribute, + free of charge only, the Software as a whole. + + 7. Copyright. The Software is owned by ID and is protected by + United States copyright laws and international treaty provisions. + You must treat the Software like any other copyrighted material, + except that you may make copies of the Software to give to other + persons. You may not charge or receive any consideration from any + other person for the receipt or use of the Software. You agree to + use your best efforts to see that any user of the Software licensed + hereunder complies with this Agreement. + + 8. Limited Warranty. ID warrants that if properly installed and + operated on a computer for which it is designed, the Software will + perform substantially in accordance with its designed purpose for a + period of ninety (90) days from the date the Software is first + obtained by an end-user. ID's entire liability and your exclusive + remedy shall be, at ID's option, either (a) return of the retail + price paid, if any, or (b) repair or replacement of the Software + that does not meet ID's Limited Warranty. To make a warranty claim, + return the Software to the point of purchase, accompanied by proof + of purchase, your name, your address, and a statement of defect, or + return the Software with the above information to ID. This Limited + Warranty is void if failure of the Software has resulted in whole + or in part from accident, abuse, misapplication or violation of this + Agreement. Any replacement Software will be warranted for the + remainder of the original warranty period or thirty (30) days, + whichever is longer. This warranty allocates risks of product + failure between Licensee and ID. ID's product pricing reflects this + allocation of risk and the limitations of liability contained in + this warranty. + + 9. NO OTHER WARRANTIES. ID DISCLAIMS ALL OTHER WARRANTIES, + EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A pARTICULAR PURPOSE + WITH RESPECT TO THE SOFTWARE AND THE ACCOMPANYING WRITTEN MATERIALS, + IF ANY. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL RIGHTS. YOU + MAY HAVE OTHERS WHICH VARY FROM JURISDICTION TO JURISDICTION. ID + DOES NOT WARRANT THAT THE OPERATION OF THE SOFTWARE WILL BE + UNINTERRUPTED, ERROR FREE OR MEET LICENSEE'S SPECIFIC REQUIREMENTS. + THE WARRANTY SET FORTH ABOVE IS IN LIEU OF ALL OTHER EXPRESS + WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS, EMPLOYEES, + DISTRIBUTORS, AND DEALERS OF ID ARE NOT AUTHORIZED TO MAKE + MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON BEHALF + OF ID. ADDITIONAL STATEMENTS SUCH AS DEALER ADVERTISING OR + PRESENTATIONS, WHETHER ORAL OR WRITTEN, DO NOT CONSTITUTE WARRANTIES + BY ID AND SHOULD NOT BE RELIED UPON. + + 10. Exclusive Remedies. You agree that your exclusive remedy + against ID, its affiliates, contractors, suppliers, and agents for + loss or damage caused by any defect or failure in the Software + regardless of the form of action, whether in contract,tort, + including negligence, strict liability or otherwise, shall be the + return of the retail purchase price paid, if any, or replacement of + the Software. This Agreement shall be construed in accordance with + and governed by the laws of the State of Texas. Copyright and other + proprietary matters will be governed by United States laws and + international treaties. IN ANY CASE, ID SHALL NOT BE LIABLE FOR LOSS + OF DATA, LOSS OF PROFITS, LOST SAVINGS, SPECIAL, INCIDENTAL, + CONSEQUENTIAL, INDIRECT OR OTHER SIMILAR DAMAGES ARISING FROM BREACH + OF WARRANTY, BREACH OF CONTRACT, NEGLIGENCE, OR OTHER LEGAL THEORY + EVEN IF ID OR ITS AGENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. Some jurisdictions do + not allow the exclusion or limitation of incidental or consequential + damages, so the above limitation or exclusion may not apply to you. + + 11. General Provisions. Neither this Agreement nor any part or + portion hereof shall be assigned or sublicensed, except as described + herein. Should any provision of this Agreement be held to be void, + invalid, unenforceable or illegal by a court, the validity and + enforceability of the other provisions shall not be affected thereby. + If any provision is determined to be unenforceable, you agree to a + modification of such provision to provide for enforcement of the + provision's intent, to the extent permitted by applicable law. Failure + of a party to enforce any provision of this Agreement shall not + constitute or be construed as a waiver of such provision or of the + right to enforce such provision. If you fail to comply with any terms + of this Agreement, YOUR LICENSE IS AUTOMATICALLY TERMINATED. + + YOU ACKNOWLEDGE THAT YOU HAVE READ THIS AGREEMENT, YOU UNDERSTAND + THIS AGREEMENT, AND UNDERSTAND THAT BY CONTINUING THE INSTALLATION + OF THE SOFTWARE, BY LOADING OR RUNNING THE SOFTWARE, OR BY PLACING + OR COPYING THE SOFTWARE ONTO YOUR COMPUTER HARD DRIVE, YOU AGREE TO + BE BOUND BY THIS AGREEMENT'S TERMS AND CONDITIONS. YOU FURTHER + AGREE THAT, EXCEPT FOR WRITTEN SEPARATE AGREEMENTS BETWEEN ID AND + YOU, THIS AGREEMENT IS A COMPLETE AND EXCLUSIVE STATEMENT OF THE + RIGHTS AND LIABILITIES OF THE PARTIES. THIS AGREEMENT SUPERSEDES + ALL PRIOR ORAL AGREEMENTS, PROPOSALS OR UNDERSTANDINGS, AND ANY + OTHER COMMUNICATIONS BETWEEN ID AND YOU RELATING TO THE SUBJECT + MATTER OF THIS AGREEMENT. + +June 21, 1996 + +SHAREWARE VERSION: QUAKE LIMITED USE SOFTWARE LICENSE AGREEMENT +(DWC:dw:3406.0024:DWC\doc:1163) diff --git a/engine/docs/TECHINFO.TXT b/engine/docs/TECHINFO.TXT new file mode 100644 index 0000000..31c0501 --- /dev/null +++ b/engine/docs/TECHINFO.TXT @@ -0,0 +1,1901 @@ +Welcome to the Quake Technical Information file! + +TABLE OF CONTENTS +----------------- +Introduction to the Console.............. +Video Subsystem Documentation............ +Sound Subsystem Documentation............ +CD Audio Subsystem Documentation......... +Network Subsystem Documentation.......... +Modem Strings............................ +Win95 Documentation...................... +Key Binding and Aliases.................. +Quake Keys and Common Commands........... +Making a Config File..................... +Demos.................................... +Reporting Quake Bugs..................... + + +========================================== +== Introduction to the Console == +========================================== + +Throughout this document, examples of commands are given, all of which +are typed in at the console. To bring up the console, press the tilde ('~') +key or press ESC to bring up the menu, select Options, and select Console... +from the options menu. To exit the console, press ESC. + +The console provides a way to change console variables and also accepts +commands that change game settings such as movement keys, video mode, as +well as providing an interface for key binding and command aliasing (more +on that later). + +The console also has a command history with which you can browse through +previous commands. Use the up and down arrows to navigate through the +command history and press to re-issue a command. + +Partially typing a command and then pressing the TAB key will complete the +currently typed text with the first matching console variable or command. +(Yes, this is a good way to look for console commands.) + +To review previous actions by page, use the PGUP and PGDN keys. + + +========================================== +== Video Subsystem Documentation == +========================================== + +The Video Modes menu +-------------------- + +Video modes can most easily be selected from the the Video Modes menu, which +is brought up by selecting the Video Options choice in the Options menu. +All the resolutions that Quake can support on the current computer are +displayed. + +Please note that higher-resolution modes require correspondingly more +system memory in order for Quake to run, and that some high-resolution +modes may not be available when running Quake on 8 Mb machines. Such +modes are not listed in the Video Modes menu. Please do not report +video modes that do not appear in the Video Modes menu as bugs; either +those modes are not supported by your video adapter, or there is not +enough system memory for Quake to support those modes. + +The video modes listed in the Video Modes menu can be tested, set, and made +the default mode for Quake from the Video menu, as follows: + +* The arrow keys can be used to move the blinking indicator to any of the +modes listed in the Video menu. + +* Pressing the 'T' key tests the mode the blinking indicator points to, by +setting the mode, leaving it set for 5 seconds, and returning to the previous +mode. This lets you verify that your computer does in fact support that +mode. We highly recommend that you always test modes with 'T' before setting +them permanently by pressing the Enter key, in case some sort of hardware or +software glitch causes a mode to function incorrectly and produce a garbled +screen. It is unlikely but possible that testing or setting a mode will +cause your computer to hang or crash; if this happens, there is a serious +hardware or software bug, and you should not attempt to select that mode +again. + +* Pressing the Enter key sets the mode the blinking indicator points to, +leaving it set so Quake will then run in that mode. We suggest that you +test a mode by pressing the 'T' key before setting it by pressing the Enter +key. Note that a selection made with the Enter key remains in effect only +until Quake is exited (or a new mode is set). You must explictly make a mode +the default mode by pressing the 'D' key in order to automatically set that +mode when you start Quake up in the future. + +* Pressing the 'D' key makes the current mode the default mode that Quake +starts up with. Note that the current mode is the mode that's displayed in +white in the mode list, not necessarily the mode that the blinking indicator +points to. The current default mode is listed in the description of the 'D' +key at the bottom of the Video Modes menu. + +* Pressing Esc exits the Video Modes menu. + +Please see "Bug Reporting," below, for information on how to report any +problems you encounter. + + +Video modes from the console: Quick start +------------------------------------------ + +More comprehensive but more complex video control is available through the +Quake console. This section describes the commands necessary to perform +basic mode setting through the console (this is similar to what can be +accomplished through the Video Modes menu), and following sections describe +console video control in detail. + +To see all the video modes that are available, bring up the console (either +press tilde ('~'), or press Esc to bring up the menu, select Options, and +select Console... from the Options menu). + +From the console, type vid_describemodes to see all available modes. +Type vid_mode to set a mode, where is the mode number +listed for the desired mode by vid_describemodes. Higher-resolution modes +generally require more extra system memory in order to run, and many are +not available in 8 Mb systems; modes that are supported by the video +adapter but are currently unavailable due to system memory limitations +will still show up in the mode list from vid_describemodes, but will +have "**" in place of a mode number. (Such modes will not show up at +all in the Video Modes menu.) If you try to set a mode for which +there is insufficient system memory, you will receive a message to that +effect, and the video mode will remain unchanged. + + +More detail +----------- + +This version of Quake supports software drawing in a variety of +video modes. It does not support any 3-D hardware accelerators. +Video modes that are built into Quake are: + +320x200, 360x200, 320x240, 360x240, 320x350, 360x350, 320x400, +360x400, 320x480, 360x480 + +However, the higher-resolution modes on this list require additional +memory, and may not be available in 8 Mb systems. + +In addition, all VESA 2.0 256-color linear framebuffer modes +supported by the video adapter are supported. Further information +about VESA 2.0 is provided below. + + +Video mode reporting and selection +---------------------------------- + +Quake assigns each available video mode a mode number, which can +then be used to query information about the mode or to select the +mode. The first 11 mode numbers are always as follows: + +0: 320x200 +1: 320x200 +2: 360x200 +3: 320x240 +4: 360x240 +5: 320x350 +6: 360x350 +7: 320x400 +8: 360x400 +9: 320x480 +10: 360x480 + +You will notice that modes 0 and 1 are both 320x200; mode 1 is a +Mode X-style version, which may someday allow support of page +flipping for cleaner graphics, but right now it's just slower with +no advantages, so use mode 0 for 320x200 resolution. Modes 2-10 +are all higher resolution than mode 0, and look very nice, but are +also all slower than mode 0. Mode 0 is the fastest of the 11 +built-in modes. + +In addition to the built-in modes, Quake checks for the presence +of a VESA version 2.0 driver. If such a driver is detected, the +driver is queried for all 8-bit-per-pixel linear framebuffer (LFB) +modes that are supported; also, if no LFB 320x200 mode is available, +a banked 320x200 VESA mode is queried for. All such modes are added +to the mode list starting at mode 11. The available modes will vary +depending on adapter, graphics chipset, amount of video memory, and VESA +2.0 driver. The higher the resolution, the lower the performance, and +the higher-resolution modes will often be too slow for good gameplay +on most machines. (Also, higher-resolution modes often need more memory +than is available in an 8 Mb system.) The screen can be sized down to +improve performance in higher-resolution modes, but then of course the +effective resolution of Quake is reduced. + +At the same resolution, VESA LFB modes are often faster than the non-VESA +modes 0-10, because adapters often have faster memory access in LFB modes. + +If a given VESA mode can support page flipping, then it defaults to page- +flipped operation. A VESA mode can be forced to non-page-flipped operation +by setting the vid_nopageflip console variable to 1, then setting the mode + (note that vid_nopageflip takes operation on the next, not the current, mode +set, and note that it then stays in effect permanently, even when Quake is +exited and restarted, unless it is manually set back to 0). If there is not +enough memory for two pages in a VESA mode, or if the +adapter doesn't support page flipping, then the mode will automatically +be non-page-flipped. Page flipping can have higher visual quality, but may +be either faster or slower, depending on the graphics adapter and other +hardware. (See the discussion of the Pentium Pro, below, for a +discussion of why page flipping can be faster but is sometimes much slower +on that processor.) Page-flipped modes use less system memory than non- +page-flipped modes. + +Quake's VESA support, including VESA driver detection, can be disabled by +using the -stdvid command-line switch, and can also be disabled, along with +sound, network, and other hardware support, by the -safe command-line switch. + +The maximum resolution supported by Quake is 1280x1024. Modes with higher +resolutions will not be reported by vid_describemodes, and cannot be set. + +There is no support for any 3-D accelerator boards in this version of Quake. +Coming soon. + +Quake always starts up in mode 0, and modes 0-10 are always available, given +enough system memory. + + +A note on modes reported in the Video Modes menu +------------------------------------------------ + +The vid_describemodes console command lists all modes with +resolution less than or equal to 1280x1024 that are +supported by the video adapter, although modes for which there +is not enough system memory have "**" for the mode number. VGA, +Mode X-style, and VESA 2.0 modes are listed separately, so a +single resolution can be listed as many as three times, once for +each hardware mode that supports it. For example, mode 0 is +VGA mode 0x13, which supports 320x200 resolution, and mode 1 is +320x200 Mode X-style mode. Quake looks identical in both +modes, although it usually runs faster in mode 0. + +The Video Modes menu is much simpler. Only modes with resolution +less than or equal to 1280x1024 that are both supported by the +hardware and for which there is sufficient system memory are +listed. Further, a given resolution is listed only once. If a +given resolution is available in multiple hardware modes, then +selecting that resolution will select the appropriate hardware mode +as follows: + +If the mode is 320x200, then VGA mode 0x13 is selected, and +equivalent Mode X and VESA modes are ignored; + +Otherwise, the VESA version of the mode is used. + +You can always see what video mode is selected from the console by typing +the command: + +vid_mode + +command. + +None of this has any effect on selecting modes through the +console, where all the different versions of each mode are +listed, and the desired version can be selected by using the +appropriate mode number. + + +How to get VESA 2.0 support +--------------------------- + +Some video adapters have VESA 2.0 support in ROM. Other video +adapters come with loadable VESA 2.0 TSRs. In the absence of either +of these, UniVBE, a shareware product from SciTech, provides VESA 2.0 +support for most video adapters. The latest version of UniVBE can be +obtained from the following locations: + +www: http://www.scitechsoft.com +ftp: ftp.scitechsoft.com +CIS: GO SCITECH +AOL: Keyword SciTech + +SciTech can be contacted at: + +email: sales@scitechsoft.com + +SciTech Software +5 Governors Lane, Suite D +Chico, CA +95926-1989 + +The current version at this writing is UniVBE 5.2. This version +supports many more adapters than previous versions, and adds +a number of useful low- and medium-resolution modes, such as 400x300 +and 512x384. + + +Video-related commands +---------------------- + +vid_describecurrentmode + lists the description for the current video mode. + +vid_describemode + lists the description for the specified video mode, where is as + reported by vid_describemodes. + +vid_describemodes + lists descriptions for all available video modes. + +vid_mode + sets the display to the specified mode, where is as reported by + vid_describemodes. + +vid_nopageflip <1|0> + when set to 1, VESA mode sets will always select non-page-flipped + operation. When set to 0, VESA mode sets will select page-flipped + operation whenever possible. All non-VESA modes are always + non-page-flipped. The setting of vid_nopageflip is remembered + when Quake is exited (by being saved in config.cfg), and is reloaded + when Quake is restarted, so once vid_nopageflip is set to 1, all + VESA modes set in all Quake sessions after that point be will non-page- + flipped until vid_nopageflip is set to 0. Note that setting this + variable doesn't affect whether the current video mode is page-flipped, + but rather whether page-flipping can be used by future mode sets. + +vid_nummodes + reports the total number of modes available. + +vid_testmode + tries to switch Quake to the specified mode, then returns to the current + mode after 5 seconds. This allows you to try an untested mode without + ending up with a black screen if, for example, the monitor can't display + the mode properly. There may still be instances in which, due to VESA + driver or hardware bugs, the machine will hang in certain modes; + vid_testmode can't recover from these situations, but it can recover + from a blank or scrambled screen. + +vid_wait + sets the type of waiting that the video adapter should do, as follows: + 0: no waiting + 1: wait for vertical sync active + 2: wait for display enable active + +The default state of vid_wait depends on the video mode selected. +(_vid_wait_override can force vid_wait to 1, wait for vertical +sync; see the description of _vid_wait_override below.) +In built-in modes 0-10, the default is always 0, no waiting. You +can set vid_wait to 1 (wait for vertical sync) to eliminate shear +and tearing in these modes (so partially-completed frames are never +drawn, resulting in a rock-solid image). However, waiting for +vertical sync can result in substantial performance loss. + +In VESA modes, if the adapter is VGA compatible and there's enough +memory for three video pages, then triple-buffering is enabled and +vid_wait is set to 2, wait for display enable. There is little +performance loss to this sort of waiting. If the adapter is not +VGA compatible, or if there's only enough memory for double-buffering, +then vid_wait is set to 1 (wait for vertical sync). This can cause +significant loss of performance, but some sort of wait is generally +necessary to avoid occasional glitching of the screen when +page-flipping; we always choose the lowest-cost wait option that +seems to be safe to use. If there's only enough memory for one +page, or if vid_nopageflip 1 is in effect, then vid_wait is set to 0 +(no wait). As with modes 0-10, vid_wait 1 can be used to eliminate +shear, but at a performance cost. + +We have encountered problems with a few adapters in VESA modes when +vid_wait is set to 2 (wait for display enable). Apparently some adapters +just toggle display enable all the time, rather than only when pixels +are being sent to the screen; this can cause occasional glitches in +which the screen image jumps for one frame. You can fix this by +setting vid_wait to 1 (wait for vertical sync). We would have made +vid_wait 1 the default, but it's slower, and vid_wait 2 works on most +machines. + +The default setting for vid_wait can be changed from the console +at any time. If you are in a VESA mode that waits for vertical +sync and want to turn it off to get a speed-up, you can do so. +However, changing a vid_wait 1 default in a VESA mode may result +in problems. If vid_wait defaults to 1 (wait for vertical sync) +in a mode, and you force it to 2 (wait for display enable), the +machine may hang, because some VGA-incompatible adapters, such as +some ATI Mach64s, don't support the display enable status. If you +force vid_wait to 0 (no wait), then the screen may glitch periodically +if the page flips at a time that results in a bad flip address, +although some adapters work fine with no wait at all. + +If you force a new setting for vid_wait and encounter problems, DO +NOT send us a bug report! + +_vid_wait_override <1|0> + can be used to force wait for vertical sync in all modes. When + _vid_wait_override is set to 0, the type of waiting, if any, for + each video mode that's set thereafter is automatically set to + what appears to be the fastest safe state. However, it is + possible in some cases that automatic setting may result in some + screen glitching, and it is also true that shear can be + eliminated by waiting for vertical sync (although at a cost in + performance), so it may be desirable in some cases to override + the automatic wait selection and always wait for vertical sync. + This can be done by setting _vid_wait_override to 1. Once set, + this remains in effect through all succeeding mode sets, even + when Quake is exited and re-entered; the only way to keep Quake + from waiting for vertical sync once _vid_wait_override is set to + 1 is to set _vid_wait_override to 0. Note that changing + _vid_wait_override doesn't affect the current mode, but rather + takes effect on the next mode set. _vid_wait_override is initially + set to 0. + +_vid_default_mode + can be used to force Quake to start up in a particular mode. + The easiest way to select a default mode is by pressing the + 'D' key in the Video Modes menu, but you can alternatively + use _vid_default_mode to specify the mode in which you want + Quake to start up in future Quake sessions. _vid_default_mode + is initially set to 0. + + +Higher-quality perspective texture mapping +------------------------------------------ + +For maximum speed, perspective correction is performed only every 16 +pixels. This is normally fine, but it is possible to see texture ripples +in surfaces that are viewed at sharp angles. For more precise texture +mapping, set the console variable d_subdiv16 to 0. Doing this will result +in somewhat slower performance, however, and the difference in visual +quality will not normally be noticeable. + + +Known video problems and workarounds +------------------------------------ + +If you think you've encountered a bug, see "Bug Reporting," below. +As a general rule, go back to mode 0 if you have problems; mode 0 +should work properly in all cases. + +On some ATI Mach64 adapters, the palette is sometimes too dark in +some VESA modes, and is tinted oddly (too red, for example) in other +modes. The workaround is to use different modes, or modes 0-10. + +In modes 0-10, shear and tearing can occur as partially finished +frames are displayed. Workaround: set vid_wait to 1 (wait for +vertical sync); this can result in a substantial performance loss, +however. An alternative is to use a page-flipped VESA mode. + +In page-flipped VESA modes, occasional glitched frames may occur with some +VESA driver-hardware combinations. Workaround: set vid_wait to 1 (wait +for vertical sync) (you can set _vid_wait_override to 1 to make waiting +for vertical sync permanent for future Quake sessions), or use a different +mode. + +The VESA video drivers that come with some video adapters don't +support low-resolution modes such as 320x200; often, +nothing lower than 640x400 is supported. For example, +this is the case with some ATI adapters. There's nothing +Quake can do to provide low-resolution VESA modes in these +cases, because Quake simply supports whatever modes the VESA +driver chooses to report as supported. Unfortunately, 640x400 +is too high a resolution for really good performance unless you +have a very fast Pentium or a Pentium Pro, so on machines with +this sort of adapter, the VESA modes aren't very usable. +Workaround: Use UniVBE 5.2, which supports low-resolution modes +on a wide variety of adapters. Note that a few adapters simply can't +support low-resolution modes, in which case you'll have to stick with +the low-resolution VGA and Mode X modes that are built into Quake, +which run fine but may be somewhat slower than VESA modes. + +A few video adapters are almost but not fully VGA compatible, because +they don't support some unusual VGA video modes. In particular, a few +adapters don't support the 360-wide Mode X-style video modes that are +build into Quake (modes 2, 4, 6, 8, and 10), and display garbage in those +modes. Workaround: use different modes, such as 0, 3, 5, 7, 9, or any +VESA modes that are available. + +Under Win 95, the palette occasionally gets messed up when switching from +Quake to the desktop and back again. You can restore the palette by +bringing down the console (either press tilde ('~'), or press Esc to bring +up the menu, select Options, and select Console... from the Options menu), +and typing bf and pressing the enter key, to generate a background flash, +which sets the palette. Press Esc to exit the console. Alternatively, +setting the screen brightness, either from the Options menu or via the +gamma console variable, sets the palette. + +Under Win 95, if the system key (the key with the Win 95 flag on it) is +pressed while Quake is running fullscreen in a VESA mode, Win 95 may be +unable to switch back from the desktop to Quake, in which case it will +notify you of this, then terminate the Quake session. This is a quirk +of Win 95, and normally there is no workaround other than not to press +that key or not to use VESA modes. (Some people go so far as to remove +the system key from their keyboard.) However, you can +disable the system key for Quake with the following utility: + +http://www.microsoft.com/windows/download/doswinky.exe + +Switching away from Quake with Alt-Enter, Ctrl-Esc, Alt-Tab, or +Alt-Spacebar all work fine (except that if you disable the system key +with doswinky.exe, Ctrl-Esc will also be disabled). + + +Performance +----------- + +Quake's graphics should be adequately fast in mode 0 (320x200) on all +Pentium-class machines. If you feel Quake is running slowly, set the +showturtle console variable to 1; you will then see a turtle icon +appear in the upper left corner of the screen if the frame rate drops +below 10 frame/second. If you are getting the turtle, you are probably +not getting great gameplay. Performance can be improved in several ways: + +* size down the screen with the minus key + +* select a lower-resolution mode, if possible + +* use a VESA mode + +* if you're using a VESA mode and vid_wait is set to 1 (wait for +vertical sync) by default (you can check by typing vid_wait +in the console), you can try setting vid_wait to 0 or 2, as detailed +in the discussion of the vid_wait command above. Be aware that +risks of screen glitching or hung machines are associated with +overriding a default vid_wait 1 setting in VESA modes. + +To see how exactly fast Quake is running, bring up the console and type + +host_speeds 1 + +You will see a display at the top indicating total frame time in +milliseconds, and also server, graphics, and sound frame time in +milliseconds. (Note, though, that unless you also do + +snd_noextraupdate 1 + +sound time will actually show up as graphics time. However, +snd_noextraupdate 1 can cause sound to get choppy, so it's not +generally recommended.) + +Lower numbers are better. + +Type + +host_speeds 0 + +to turn off the frame time display. + + +Pentium Pro Performance +----------------------- + +The Pentium Pro is a very fast Quake platform, but has one weak spot; it is +by default very slow on writes to video memory. This means that in default +hardware configurations, you are usually much better off setting +vid_nopageflip to 1 if you use VESA modes, so drawing is done to system +memory instead of to video memory. Remember that you must set the mode +after setting vid_nopageflip to 1 in order to get vid_nopageflip to take +effect. (vid_nopageflip can sometimes be faster on a Pentium, too, but +not by nearly as much in general, and it's often slower.) + +The Pentium Pro has some special features that are not turned on by default, +but which can help Quake performance a LOT. These features can be enabled +by John Hinkley's program FASTVID, which can be obtained from +ftp://members.aol.com/JHinkley/fastvid.zip. Performance in 640x480 +mode on a Pentium Pro/150 nearly doubled after FASTVID was run; Quake +was very playable (and looked great!) at this resolution. + +There's the usual caution with FASTVID: It could conceivably make your +system run goofily, or who knows what. FASTVID is not a product of +id Software, and id makes no guarantees regarding FASTVID. In other words, +use FASTVID at your own risk. + +************************************************************************ +IMPORTANT NOTE: FASTVID works only on Pentium Pros!!! Please do NOT +contact either John Hinkley or id with problems concerning FASTVID on +Pentium or 486 machines. +************************************************************************ + + +Video Bug Reporting +------------------- + +If you encounter a video-related bug, please fill out the form found at the +end of this file and e-mail it to support@idsoftware.com. There are several +problems that are not bugs, and shouldn't be reported, including: + +* unavailability of some VESA modes; VESA modes are only supported by +Quake if they are 8-bpp, are LFB modes (except for 320x200), and are +no greater than 1280x1024 in resolution. If you have a VESA mode +that doesn't seem to be working properly, please contact the +manufacturer; we just use the information that the VESA driver +provides us with. + +* problems that occur when you change vid_wait from a default value +of 1 (wait for vertical sync) in VESA modes + +* sluggish performance on 486s + +* the known palette problem on some Mach64s. + +* the known palette problems switching from fullscreen to the desktop and +back under Win95. + +* the known problems switching back from the desktop in VESA modes after the +system (Windows flag) key has switched from fullscreen to the desktop. + +* video modes that are not listed in the Video Modes menu, or that are not +listed or are listed with "**" in the output from vid_describemodes; such +modes are either not supported by your video adapter, or cannot be supported +by Quake in the amount of memory your system has. High-resolution modes will +often not be available in 8 Mb systems. + +* 360-wide video modes that don't work although other resolutions do work + +* lack of low-resolution VESA modes; the availability of low-resolution modes +is the responsibility of the VESA driver. UniVBE 5.2 provides low-resolution +modes on most adapters. + +Apart from these, we would very much like to hear about any video +problems you encounter. + + +========================================== +== Sound Subsystem Documentation == +========================================== + +Quake's sound subsystem works only with Sound Blaster compatible sound +cards. For Quake to get the correct settings for DMA channel and PORT +address, you must set your BLASTER environment variable (or have it set for +you with the DIAGNOSE utility in your SB16 directory). If you do not have +the BLASTER environment variable set, your sound will not work. If your +sound card supports Sound Blaster compatibility, Windows 95 should set this +variable for you. + +Note: some sound cards do not have 100% Sound Blaster compatible +hardware, but emulate the Sound Blaster interface. Such cards may +display some inconsistencies relative to an actual sound blaster. +In particular, sound may be delayed on some cards. + +Note: it is possible for sound to get choppy if the frame rate +drops to a very low level, below 5 frames a second. A frame rate +that low will not provide a good gameplay experience, so if you +do experience choppy sound, your machine is almost certainly not +fast enough to run Quake satisfactorily in general. + +If (when) you see bugs, please use the form attached to the end +of these docs to submit a bug report. + +Sound Card Command Line Options, Commands, and Variables +================================================================== + +The commands and variables below work under any operating system. +Command-Line options are typed on the command line in most any place +but only in operating systems which support command line interfaces, +like DOS's COMMAND.COM, or NEXTSTEP's or Linux's csh, sh, or bash. +For example, under DOS, the NOSOUND option would be used like this: +"C:> quake -nosound". + +Command-Line Options +-------------------- + +NOSOUND + Syntax: -nosound + Description: This will prevent *any* sound code from being executed. If + you are having technical difficulty with the game and then try + running the game with this option and the problem goes away, then + the problem is probably somewhere in the sound code. + +SSPEED + Syntax: -sspeed + Description: This will ask the sound code to set the playback speed + within the constraints of the capabilities of the card. This is + 11025 Hz by default and usually from 8000 to 44100. Making this + faster requires more CPU horsepower, and has no actual benefits, + because the sounds only contain 11 KHz data. Making this slower + degrades sound quality, but improves performance and saves memory. + +Commands +-------- + +SOUNDINFO + Syntax: soundinfo + Description: This prints the "portable" information on your current + audio hardware setting in the game. It specifies whether there is + stereo output (0 or 1), the number of samples in the DMA buffer, the + current sample position (changes each time you run SOUNDINFO and + ranges from 0 to the number of samples), the number of sample bits, + the submission chunk (1 in DOS or Linux w/ mmaped sound, larger in + Linux w/o mmaped sound), playback speed in Hz, the DMA buffer address + in hexadecimal (usually 8 digits after the 0x, starting with 0xf00.. + in DOS, starting with 0x400.. in Linux, and less than 8 digits if the + hardware was not initialized successfully), and the number of + channels mixed in software (8 by default, changeable w/NUMCHANNELS + command). + +STOPSOUNDS + Syntax: stopsounds + Description: Stops any current looping sounds. + + +Sound Blaster Sound Card Command-Line Options and Commands +========================================================== + +The following applies to Sound Blaster cards or compatibles under DOS +or a DOS box. + +Commands +-------- + +SBINFO + Syntax: sbinfo + Description: This will print information on the Sound Blaster card + in the system. If the version is 4 or greater, then it is some + kind of Sound Blaster 16 or compatible. Version 2 is an 8 bit mono + sound blaster, Version 3 is an 8 bit stereo sound blaster pro. + The port is the I/O port sensed from the A variable in the BLASTER + environment variable. The DMA is the DMA channel and is confirmed in + hardware if the card is version 4 or higher. The mixer port can be + ignored. + + +========================================== +== CD Audio Subsystem Documentation == +========================================== + +Overview +======== +Quake is designed to play background music off of a CD-ROM. The Quake CD has +music tracks on it and each level has been assigned a track that will be +played. + +Win95 Users: Putting a CD other than the Quake CD into the drive when Quake +is already running will sometimes cause another Windows application to start +and switch you back to Windows with Quake running in the background. You +will probably want to stop whatever was started and switch back to Quake as +quickly as possible... especially if you are playing deathmatch. + + +Command Line Parameters +======================= +-nocdaudio + This will prevent the CD audio system from even attempting to initialize. + No CD commands or functions will be available. The game will just run + with no music. + +-cdmediacheck + This causes the game to periodically check to see if the CD has been + removed and a new one placed in the player. It is off by default since + this operation is very slow on some CD players and is not needed under + Win95. There is normally no reason to enable this option; it would + only be useful if you were going to be changing the CD from within the + game on a regular basis. + +Commands +======== +There is normally no reason you would need to use any of these commands. If +you are playing Quake with the Quake CD in your CD-ROM drive, the appropriate +music track will be played automatically. + +cd on + Re-enables the CD audio system after a "cd off" command. + +cd off + Shuts down the CD audio system. No more music will be played unless it + is re-enabled. + +cd reset + Causes the CD audio to re-initialize. This is useful if you change + CDs or insert the CD after you've already run Quake. + +cd play + Plays the specified track one time. + +cd loop + Plays the specified track. It will be repeated until either it is + manually stopped or another track is started. + +cd stop + Stops the currently playing track. + +cd resume + Will resume playback of a stopped track. + +cd eject + This is for CD players that do not have a manual eject button. + +cd remap ... + Allows you to switch what tracks are played. This is especially useful + if you want to play music other than that on the Quake CD. If the CD + audio system is told to play track 1, it will instead play the 1st + track you specified. For example: assuming a CD with 1 data track and + 8 music tracks, the command "cd remap 1 9 8 7 6 5 4 3 2" would leave + the data alone and play the audio tracks as if they had been placed on + the CD in the opposite order. + +cd info + Reports information such as the number and types of tracks on the current + CD, what track (if any) is currently playing, and the playback volume. + + +Variables +========= +bgmvolume + The background music volume. Valid values are 0.0 though 1.0. Changes + will normally be made using the options menu. + + Not all CD-ROM players support variable volume. The 0.0 to 1.0 value + translated to a value from 0 to 255 before it is passed to MSCDEX. How + this value is interpreted varies from drive to drive. The only thing + required by the MSCDEX specification is that 0 is off and anything else + is on. Some CD-ROM drives only have on and off so change to bgmvolume + will have have no effect on volume once it is on. + + +Messages +======== +CDAudio_Init: MSCDEX version 2.00 or later required. + MSCDEX was either not loaded, or is a version earlier than 2.00. + +CDAudio_Init: First CD-ROM drive will be used + MSCDEX reported that the system has more than one CD-ROM drive. + Quake will always use the first drive in this case. + +CDAudio_Init: Unable to allocate low memory. + We were unable to allocate the memory needed to communicate with MSCDEX. + Although the game can still run, this indicates a severe low memory + condition. + +CD Audio Initialized + Indicates that the CD audio system has successfully initialized. + +CDAudio_Play: Bad track number N. + We attempted to play a track number that that is outside the range of + tracks recorded on the CD currently in the CD-ROM drive. Probable causes + are that a CD other than Quake is in the player, or a custom level has + specified an invalid track number. + +CDAudio_Play: Can not play data. + A valid track was requested to be played, but it was a not an audio track. + The probable causes are the same as for a bad track number. + +CDAudio_Play: track N failed + A valid audio track was going to be played, but the play command to MSCDEX + returned an error. + +CDAudio: media changed + This is simply a notification. It can only occur if the "-cdmediacheck" + option was specified on the command line. + +CDAudio: Error - playback stopped N + An error occurred while the CD was playing audio. Playback has been + stopped and no further automatic play will be attempted; the game will + proceed without music. + +CDAudio_Init: No CD in player. + MSCDEX reported an error while Quake was attempting to get information + about the current CD. There is either no CD in the player, or it was + unable to get the track information. No automatic CD play will be + attempted; the game will proceed without music. + + +========================================== +== Network Subsystem Documentation == +========================================== + +Overview +======== + +Quake is a client/server game. You are always running over some type of +network. In a standalone game, you are using a loopback network; it just +passes messages back and forth in memory buffers. This readme is talking +about real networks and multiplayer deathmatches. There are three main +sections: commands, LANs, and Serial. + +Most normal configuration can be done via the game menus. + +There are two types of Quake servers: dedicated and listen. A listen server +is a machine that is used to play the game and also hosts the game for other +players. A dedicated server only hosts the game; it runs in text mode and +does not let anyone play on that machine. A single player game is really +just a 1 player listen server that doesn't listen for network connections. + +Dedicated vs Listen. I'll try to make this simple: it is always better to +use a dedicated server. Why? Fairness and playability. With a listen +server, the person on the server always has advantages. They will always be +the first person into a level, they will always have zero latency, and they +will get a server update on each and every frame. On a dedicated server +everyone gets equal treatment. Getting into the server is a first come, +first served proposition; latency is determined by each player's connection; +and everyone is sent the same number of updates. It's about as fair as life +gets. By the way, a good 486 machine works nicely as dedicated server. + +Another suggestion. Until there is a native Win95 version of Quake, IPX will +usually provide better gameplay on a local area network. This is due to the +delicate balancing act that is required to let a DOS program use the Win95 +TCP/IP stack. + +To start a Dedicated Server, you invoke Quake with the "-dedicated" +command-line parameter. When the server starts, you can type any command +that you would normally type in the Quake Console, such as "map e1m1" to +start the server on a specific map. This can be done from the command- +line as well by typing "quake -dedicated +map e1m1". If a value is entered +after "-dedicated", that is the amount of players allowed to connect, up +to a maximum of 16 players. A dedicated server will quit to the OS whenever +a fraglimit or timelimit is reached. Example: "quake -dedicated 16" will +start a 16-player dedicated server. + +To start a Listen Server, you invoke Quake with the "-listen" command- +line parameter, or use the Multiplayer menu in the game. Starting a listen +server from the command-line will allow you to handle more than 4 players, +as 4 is the limit when starting a game from the Multiplayer menu. If a +value is used after the "-listen", that is the maximum amount of players +allowed, up to 16 players. + +Command Line Parameters, Commands, and Variables +================================================ + +Command line parameters +----------------------- +-nolan + Disables IPX, TCP/IP, and serial support. + +-noudp + Disables support for TCP/IP. + +-udpport + Specifies a UDP port to be used other than the default of 26000. + +-noipx + Disables support for IPX. + +-ipxport + Specifies a IPX port to be used other than the default of 26000. + +-noserial + Disable serial support. + +-mpath + Enables support for code to use Win95's TCP/IP stack. Do NOT use this + under DOS! + +-listen [n] + Starts Quake ready to be a non-dedicated server for up to + players. If you do not specify a number after -listen it will + default to 8. The maximum allowed value is 16. + +-dedicated [n] + Starts Quake ready to be a dedicated server for up to players. + If you do not specify a number after -listen it will default to 8. + The maximum allowed value is 16. A dedicated Quake server stays in + text mode. This is the Quake console with most commands still + available; those that make no sense (like vid_mode) are ommitted. + +Console Variables +----------------- + +net_messagetimeout + Specifies how long Quake should wait for a message to arrive before + deciding the connection has died. The default is 3 minutes. For + reference, messages usually arrive at the rate of about 20 per second. + +hostname + This is the name for your server that will show up on an slist + (see below). The default value is "unnamed". + +sys_ticrate + Only used by dedicated servers. This determines the rate at which the + server will send out updates to the clients. The default value is 0.05 + (20 updatesper second). For servers where bandwidth is limited, using + modems or the internet for example, it is advisable to lower this value + to 0.1 (10 updates per second). This will have a very minor effect on + responsiveness, but will half to outbound bandwitdh required making the + modem players a lot happier. + + +Console commands +---------------- + +net_stats + This is for debugging. It displays various network statistics. + +slist + Looks for Quake servers on a local LAN (or over a null modem + cable). This will NOT go outside the local LAN (will not cross + routers). + + +LANs +==== + +Here are the LANs that are supported by the Quake test +release. For each one, you'll be told how to connect to a server +*if it is not on your local network*. If it is, you can use the +"slist" command and connect by hostname. See the main readme for +a discussion of the connect command. + +IPX +--- + +Quake has been run with Novell's ODI IPX stack under DOS, PDIPX with packet +drivers under DOS, and the Microsoft IPX stack in a Win95 DOS box. When +connecting to a server using IPX, you specify its network:nodeaddress (like +12345678:1234567890AB). If you are on the same network, you can just specify +the node address. If you are doing a connect command from the console, a +full IPX address must be enclosed in quotes. + +For example, the server's IPX address is "00FADE23:00aa00b9b5b2", you would +enter: connect "00FADE23:00aa00b9b5b2" + +Win95 TCP/IP +------------ + +Please see the Win95 section of this file for details about playing using +TCP/IP under Win95. + +Kali +---- + +To Quake, Kali appears to be IPX. Once you've got Kali up and running, run +Quake as if it was on an IPX network. + +Beame & Whiteside TCP/IP +------------------------ + +This is the only DOS TCP/IP stack supported in the test release. +It is not shareware...it's what we use on our network (in case you +were wondering why this particular stack). This has been "tested" +extensively over ethernet and you should encounter no problems +with it. Their SLIP and PPP have not been tested. When connecting +to a server using TCP/IP (UDP actually), you specifiy it's "dot notation" +address (like 123.45.67.89). You only need to specify the unique portion +of the adress. For example, if your IP address is 123.45.12.34 +and the server's is 123.45.56.78, you could use "connect 56.78". + +Playing over the Internet +------------------------- +Yes, you can play Quake over the Internet. How many people can be in +the game? That depends. How smooth will the game be? That depends. +There are just too many variables (bandwidth, latency, current load, +etc...) for us to make any kind of promises about Internet play. + + +Serial/Modem +============ + +The Quake serial driver supports two COM ports. Although they are referred +to as COM1 and COM2, you can configure them to use any normal hardware +COM port (1 thru 4 on most PCs). The com ports are used with interrupts, +so their IRQ may not be used for another purpose (such as a LAN adapter +or sound card). The IRQ may not be shared with another device either; +not even another COM port. A client can only be connected to one server +at a time, so multiple ports are really only useful on a server. +When using modems, the client must originate the call and the server +must answer. This holds true even for a two player, non-dedicated +server configuration. + +In the Multiplayer menu, the default modem string is "ATZ". If your modem +games are too slow, you can change this string to the appropriate one for +your modem as listed below in the "Modem Strings" section. + + +The COMx commands +----------------- + +Use the menus for serial play whenever possible. The console +interface is only for unusual configurations. It is much more +difficult to understand and use correctly. + +Those of you who do use the console commands for serial play need to +know that the menus always use the first Quake COM line (COM1); yes, +even for COM2. The names COM1 and COM2 here mean the first and second +serial ports, not necessarily the PC COM1 and COM2 ports (although those +are the default configurations). + +There are two commands to support serial/modem play for Quake. They +are: COM1 and COM2. Entering one of these commands with no arguments +will display the status of that serial port, similar to this: + +Settings for COM1 +enabled: true +connected: false +uart: 16550 +port: 3f8 +irq: 4 +baud: 57600 +CTS: ignored +DSR: ignored +CD: ignored +clear: ATZ +startup: +shutdown: ATH + +When used with arguments, these commands change the settings and +status of the COM ports. The possible arguments are listed below; +examples follow. + +enable | disable + "enable" means that your configuration is complete and you want to use + the COM port. "disable" is used to turn off a COM port, usually to + change its settings. The default (initial) state is disabled. + + +modem | direct + Use one of these two to let Quake know if you are using a modem or a + direct connection (also called a null modem). Quake uses this to know + if it needs to handles modem initialization strings, dialing sequences, + and hangup procedures. + +reset + This will reset the COM port to its default settings and state. + + +port +irq + These are used to set the I/O Port and IRQ that your serial port uses. + The default values are: port=3f8 irq=4 for COM1 and port=2f8 irq=3 for + COM2. Note that the port number is displayed in hexadecimal; to enter + it you would use something like "COM2 port 0x2f8"; the "0x" preceding + the "2f8" indicates that you are giving the value in hexadecimal + otherwise decimal is assumed. + + +baud + Sets the baud rate. Valid values for are: 9600, 14400, + 28800, 57600, and 115200. 57600 is the default. Please note that + this is the baud rate used for the uart, not your modem. It is + perfectly valid to use 57600 on a COM port that is connected to a + 28.8 modem. + +8250 | 16550 + Specifies the type of uart chip in your system. Normally this is + automatically detected, one of these need only be used if your chip + is incorrectly detected. + +clear +startup +shutdown + This allows you to specify the clear, startup, and shutdown strings + needed for a modem for playing Quake. If you've found values that + previously worked with Doom, use them here. If you are playing over + a null modem cable, leave these blank. + +-cts | +cts +-dsr | +dsr +-cd | +cd + These determine if certain serial control lines should be honored or + ignored. The "-" means you want that line ignored, the "+" means to honor + it. "cts" is an abbreviation for "clear to send", "dsr" for + "data set ready", and "cd" for "carrier detect". Do not change these + values unless you are absolutely positive you need to. The default is to + ignore all 3 lines. + +Quake always uses no parity, 8 data bits, and 1 stop bit; these +values can not be changed. The baud, port, irq, and uart type can +not be changed on an enabled port, you must disable it first. + + +Configuration examples +---------------------- +Example1: You have a machine with two serial ports you are going +to use as a Quake server. COM1 will be using a null modem cable and +COM2 will be connected to a 14.4 modem. You would use commands similar +(the startup string would almost certainly be different) to these: + +COM1 baud 57600 enable +COM2 baud 14400 modem startup AT\N0%C0B8 enable + + +Example2: You are going to use your machine to connect to a dial-up +Quake server with your 28.8 modem connected to COM2. You would +use a command something like this: + +COM2 baud 57600 modem startup AT\N0%C0B8 enable + +Note the baud rate is not the same as the modem speed. This allows +the modem-to-uart communications to occur at a higher rate than +the modem-to-modem communications. + +Connecting to a serial Quake server +----------------------------------- + +Connecting to a Quake server over a serial/modem connection is done +using the "connect" command. The command "connect 5551212" would try to +connect to a Quake server at the phone number 555-1212. Note: your local +phone company would probably appreciate it if you didn't try this number! + +If you are using a null modem cable, you can type "connect #". +Quake will then attempt to connect to the server. + + +Known problems / workarounds +============================ +Packet drivers with PDIPX - there is a bug that stops a server running on +this combination from responding to the slist command. Use the patched +version of PDIPX included with Quake to correct this problem. + +SLIST sees no servers - Some PCMCIA ethernet cards and PPP drivers will +not do the UDP broadcasts needed for the SLIST command (search for local +games from the menu) to function correctly. In these cases you must +connect to a Quake game using either its IP address or hostname +(DNS resolvable hostname, not the hostname variable in Quake). + +"BW_OpenSocket failed: 5" - This error is specific to the Beame and +Whitesdie TCP/IP stack. This stack uses DOS file handles as it's +socket handles. This error occurs when DOS runs out of file handles. +You need to increase the number specified by "FILES=" in the DOS +config.sys file. + +Severe lag using TCP/IP under Win95: + - Occasionaly when you first connect in to a Quake game using Win95 +TCP/IP you will experience severe lag and not be able to control your +player's actions. This usually clears up in 10 to 15 seconds. + - There is apparently a strange limbo state for Microsoft's File and +Print sharing. This has been seen when it was installed and then later +removed, but it still appears on the menus. For some unknown reason +this causes severe lag for a Quake game. You need to go back and make +sure that it is either completely installed or removed. + + +========================================== +== Modem Strings == +========================================== + +Boca M1440i (internal): +ATS48=0S37=9S46=136%C0%E0%M0&K0&Q0&R1&C1&D2\G0\N1N0 + +Boca 14.4k (internal): +AT&C0N0S37=9&K0W0&Q0S36=3S48=128%C0 + +Boca 14.4 Fax/Modem +AT S46=0 S37=9 N0 &Q0 &D2 &K4 + +Boca 14.4k (external): +AT &F S0=1 S36=0 &K0 &Q6N0S37=9 &D2 + +Boca 14.4k: +AT S46=0 S37=9 N0 &Q0 &D2 &K0 %C0 + +Cardinal 14.4k v.32bis, v.42bis Fax/Modem: +AT &F N0 S37=9 &Q0 &D2 \N1 + +Digicom Systems (DSI) (softmodem): +AT Z \N0 &D2 &K0 S48=48 + +Digicom Systems Scout Plus: +ATZ*E0*N3*M0*S0*F0&D2 + +Gateway Telepath: +AT &F S37=9 %C0 &K0 &Q6 \G0 + +Gateway Telepath 14.4k: +AT S46=0 S37=9 N0 &Q0 &D2 &K0 %C0 + +Gateway Telepath I: +AT S0=1 &N6 &K0 &M0 + +Gateway Telepath II: +AT S0=1 S37=9 %C0 &Q0 &K0 + +Generic v.32bis 14.4k Fax/Modem: +AT \N0 %C0 B8 + +Generic 14.4k Fax/Modem: +AT S46=0 S37=9 N0 &Q0 &D2 %C0 \G0 &K0 + +GVC 14.4k (internal): +AT &F B8 \Q0 + +Hayes 28.8k V.FAST Modem: +AT &Q6 &K S37=9 N %C0 \N0 + +Infotel 144I: +AT&Q0 S37=9 N0 &D2 + +Infotel 14.4: +&F0 \N1 &D2 S37=F8 + +Intel 14.4k: +AT \N0 %C0 \Q0 B8 + +Intel 14.4k (internal): +AT Z B8 Q1 \C0 \N1 %C0 \V "H + +Linelink 144e: +AT &F &D1 &K0 &Q6 S36=3 S46=136 %C0 +19200 + +Microcom AX: +&F \N1 \Q0 &D2 + +Microcom QX/4232bis: +AT %C0 \N0 + +Netcomm M7F: +AT &E &K0 B0 \V0 X4 &D2 \N1 \Q0 #J0 #Q9 %C0 + +Nokia ECM 4896M Trellis V.32: +AT Z %C0 /N0 + +Nuvotel IFX 14.4 (internal): +&F \N1 &D2 + +Practical Peripherals 14400FX v.32bis: +AT Z S46=0 &Q0 &D2 + +Practical Peripherals 14400FX v.32bis: +AT S46=0 &Q0 &K0 &D2 + +Supra: +AT &F0 S46=136 %C0 + +Supra (external): +AT &K &Q &D \N1 + +Supra 14.4k v.32bis: +AT &F S46=136 &Q0 &D2 + +Supra 14.4k v.32bis: +AT &K &Q &D \N1 + +Supra Fax Modem 14.4K v.32 bis +AT &F %C0 S48=7 Q0 V1 W1 + +Telepath 14.4k: +AT &F&M0&K0&N6&H0 S0=1 + +Twincomm DFi 14.4: +AT&F &Q0 %C0 S37=9 &D2 + +UDS V.3223: +&F \N1 \Q &D2 + +UDS Fastalk 32BX: +&F0 \N1 &D2 + +USR Courier v.32bis: +ATS0=1 S7=60 E1 Q0 V1 &C1 &D2 &H0 &K0 &M0 &N6 &A3 + +USR Courier HST/DS 16.8k: +First reset the modem in a communication program with AT&F&W +AT X4 B0 &A0 &B0 &H2 &I0 &K0 &M0 &N6a + +USR DS v.32bis v.42bis (external): +AT&m0&n6&a0&r1&h0&k0&i0&s0&b1x1 + +USR Sporster 9600: +AT&M0&K0&N6 + +USR Sportster V.34 28.8 (note: works best at 19200 baud): +AT &F &M0 &I0 &K0 &B0 &N0 + +USR Sportster 14.4k Fax/Modem USING ERROR CORRECTION: +AT S0=1 S7=60 E1 QO V1 &C1 &D2 &K0 &N6 &A3 + +USR Sportster 14.4k Fax/Modem (internal): +AT &F&M0&K0&N6&H0 + +USR Sportster 14.4k (internal): +AT &F &B1 &H0 &I0 &K0 &M0 &N6 &R1 + +USR Sportster 14.4k: +ATS0=1S7=60E1Q0V1&C1&D2&K0&N6&A3 + +USR Sportster 14.4k: +AT &F0 &K0 &M0 &N6 &H0 &I0 &B1 &R1 + +USR Sportster 14,000 Fax Modem: +AT S0=2 &N6 &K0 &M0 &I0 &H0 &R1 &A0 V1 X4 + +USR 14.4k: +AT &F&A0&K0&M0 + +USR 14.4k +AT &K0 &H0 &D0 &I0 &R1 + +USR 14.4k Dual Standard +ATB0&R1&B1&N6Q0X4&A0&D2&H0&I0&K0&M0M1 + +USR (model?): +&F E1 V1 X4 &C1 &D2 &N0 + +ViVa 14.4k: +AT&F&Q6\N0%C0&D2N0S37=9 + +ViVa modem (internal): +&F&Q6\N0%C0&D2N0S37=9 + +Zoltrix model 14/14 VE: +AT S0=Q0 V1 &C1 &D2 W2 &Q0 + +Zoom 14.4k VFX: +AT&Q6S37=9N0%C\N0 + +Zoom 14.4k VFX: +AT&Q6S37=11N0%C&K0 + +Zoom OEM Modem: +AT&Q6S37=9N0&K0 + +Zyxel U-1496E: +AT Z &N4 &K0 + + +========================================== +== Win95 Documentation == +========================================== + +Quake is a DOS application. However, it runs fine from the MS-DOS prompt +under Win95, so long as the Properties for the MS-DOS prompt are set up so +that Quake can run. (See "Set the MS-DOS Prompt Properties", below, for +information about setting MS-DOS Prompt Properties.) Quake will NOT run +under Windows NT. Following are some steps that can help Quake run better +under Win95. + + +Have enough memory +------------------ + +Quake requires at least 16 Mb of installed memory in order to run under +Win95. + + +Set the MS-DOS Prompt Properties +-------------------------------- + +If Quake won't run, the MS-DOS Prompt Properties may not be set correctly. +To set the Properties for the MS-DOS prompt, bring up a DOS session, and +either click on the MS-DOS icon in the upper left corner or press +Alt-Spacebar, then select Properties from the menu that comes up, and make +sure the following settings are correct. + +In the Program sheet of MS-DOS Prompt Properties, make sure the "Suggest +MS-DOS mode as necessary" is checked. + +In the Memory sheet of MS-DOS Prompt Properties, make sure all five fields +are "Auto". + +In the Screen sheet of MS-DOS Prompt Properties, set "Usage" to Full-screen. + +In the Misc sheet of MS-DOS Prompt Properties, uncheck the "Allow screen +saver" box, and check the "Always suspend" box. + + +Make sure there's enough free disk space +---------------------------------------- + +If you get error messages like "can't lock memory" under Win 95, or if you +get other weird, inexplicable errors, make sure you haven't run out of disk +space; delete some files if necessary. You can see how much disk space is +free by bringing up "My Computer" and clicking on the disk icon; the free +disk space will be shown at the bottom of the window. + + +Run fullscreen +-------------- + +Quake can run in a window under Win95--but it will run very slowly. You are +unlikely to get satisfactory performance unless you run Quake fullscreen. +Quake normally comes up fullscreen under Win95; if you have switched it back +to windowed mode, you can get that window back to fullscreen by clicking on +it and then pressing Alt-Enter. + + +Shut down other applications +---------------------------- + +Many Win95 apps and DOS apps run even when they're not the foreground +application. Such applications contend for system resources such as memory, +processor cycles, and sound hardware. If Quake seems to be running choppily, +if sound is garbled, or if the disk is going all the time, try shutting down +whatever other applications you have running. For example, some players +have reported that Quake does not run as well when the Office shortcut bar +is running. + + +Restore the palette if it gets garbled +-------------------------------------- + +Under Win 95, the palette occasionally gets messed up when switching from +Quake to the desktop and back again. You can restore the palette by +bringing down the console (either press tilde ('~'), or press Esc to bring +up the menu, select Options, and select Console... from the Options menu), +and typing bf and pressing the enter key, to generate a background flash, +which sets the palette. Press Esc to exit the console. Alternatively, +setting the screen brightness, either from the Options menu or via the +gamma console command, sets the palette. + + +Avoid the system key +-------------------- + +Under Win 95, if the system key (the key with the Win 95 flag on it) is +pressed while Quake is running fullscreen in a VESA mode, Win 95 may be +unable to switch back from the desktop to Quake, in which case it will +notify you of this, then terminate the Quake session. This is a quirk +of Win 95, and there is no workaround other than not to press that key +or not to use VESA modes. (Some people go so far as to remove the system +key from their keyboard.) Switching away from Quake with Alt-Enter, +Ctrl-Esc, Alt-Tab, or Alt-Spacebar all work fine. + + +Give Quake more and/or locked memory +------------------------------------ + +By default, Quake tries to allocate 8 Mb of unlocked memory for heap space +under Win 95. More memory helps Quake run faster; you can allocate more +memory for Quake under Win95 by setting the command-line switch + +-winmem x + +where x is the number of megabytes to allocate for Quake. If there's enough +memory in the system, the larger the number, up to about 16, the better the +performance. If, however, there isn't enough memory in the system, or many +other applications are running, the larger number can just cause Quake to +page to disk a lot, and can actually slow performance considerably. Also, +higher numbers can also cause Win 95 to take longer to start Quake and take +longer to return to the desktop afterward. If you have 32 Mb or more in your +machine, -winmem 16 should provide the best performance for Quake. If you +have less than 32 Mb, or a lot of applications running, then you will have +to experiment to find the best amount of memory to allocate for Quake. + +You may optionally instruct Quake to lock itself in memory by using the +command-line switch + +-winlock + +so it won't get paged out by other applications. This can avoid hitches when +parts of Quake get paged into and out of memory, and thus provide a smoother +playing experience. On the other hand, it can cause Quake to take longer to +start, and can make the return to the desktop take longer when Quake ends, +because Quake has been hogging a lot of memory. It is even possible, if most +of the memory in the system is locked by Quake, that it will take many +minutes to switch back to the desktop while Quake is running, so the system +will effectively be nearly frozen. Therefore, use -winlock with caution; +Quake is not as well-behaved a Win95 citizen when -winlock is specified, and +does not share resources particularly well. + +-winmem can be used in conjunction with -winlock; if -winmem specifies more +memory than is available to be locked, then Quake will lock as much memory +as possible. Being too aggressive about how much memory is locked can +actually slow Quake performance, because unlocked parts of the system like +system CD and sound code and data can then be forced to page, so if you do +lock memory, you will have to experiment to find the sweet spot, unless you +have 32 Mb or more of memory. + +-winlockunlock can be specified as an alternative to -winlock, to tell Quake +to lock its memory when it starts, then immediately unlock it. The +advantages of doing this are: 1) it forces all of Quake's pages into memory, +so no pages should need to be brought in as Quake runs, making for smoother +running at the start, and 2) it enables Quake to determine whether the +specified amount of memory (if -winmem is also specified) is available in the +machine, so you can be sure Quake won't try to allocate more heap space than +the the amount of physical memory that's actually available. Like -winlock, +-winlockunlock causes Quake to take quite a bit longer to start up, but it +has the advantage of making Quake a good Win95 citizen if you need to switch +back to the desktop, or have other apps running. + +In general, Quake will run fine without any of the -winxxx switches, but you +may find that one or more of them--particularly -winmem if you have more than +16 Mb--helps Quake performance on your machine. + +None of this is an issue under DOS itself (as oppsed to a DOS box under +Win95), because Quake just uses all the memory in the machine under DOS. + +By default, Quake tries to allocate 8 Mb of unlocked memory for heap space + + +Watch out for limbo subsystems +------------------------------ +Microsoft's File and Print sharing and IPX protocol stack have both been +known to cause strange problems when they are in a limbo state. The limbo +state is seems to be an uninstall that did not complete succesfully. Both +of these cause poor network play performance. If you are experiencing +severe lag, check the File and Print services. If you the warning "IPX +driver send failue: 04", check the IPX protocol stack. They need to be +either completely installed or removed; the problems only occur when they +get into this strange semi-installed state. + + +========================================== +== Key Binding and Aliases == +========================================== + +Pressing the tilde key ("~") will bring down the console (pressing the +tilde key or ESC while in the console will close the console). From the +console you can adjust your player controls, this is done by "binding" +keys to commands. The format for binding keys is as follows: + +bind + +Where is a valid key control and is a valid quake command. + +Example: +To bind the j key to the 'jump' command, you would type: +bind j +jump +and press enter. + +Non-printable keys such as 'page up' and buttons from the mouse/joystick are +bound in the same manner as printable characters. A list of bindable keys can +be found at the end of this file. + +Example: +To bind the page up key to the 'jump' command, you would type: +bind pageup +jump +and press enter. + +To bind the right mouse button to the attack command, you would type: +bind mouse2 +attack +and press enter. + +The alias command is used to create a reference to a command or list of +commands. When aliasing multiple commands, or commands that contain +multiple words (such as "fraglimit 50"), you must enclose all the commands +in quotation marks and separate each command with a semi-colon. + +Example of an alias that changes some Deathmatch server parameters: + +alias net_game "hostname my_server ; fraglimit 15 ; timelimit 15" +bind INS net_game + +Once the server is spawned (you must be the one running the -listen server), +you just push the Insert key to set the hostname, frag limit and time limit +of the server. So now the first person to 15 frags, or with the one with the +most frags in 15 minutes, wins. + +Another example would be to change to the Rocket Launcher, fire one rocket, +and change back to the Double Barrel Shotgun, when you press the "," key: + +alias rl_dbsg "impulse 7 ; +attack ; wait ; -attack ; impulse 3" +bind , rl_dbsg + +Aliasing is very powerful, allowing you great flexibility, so you should +experiment by aliasing different commands in various ways. + +A list of common commands can be found in the next section. + + +========================================== +== Quake Keys and Common Commands == +========================================== + +The following keys can be bound: + +A-Z 0-9 +*F1-F12 *TAB +ENTER SPACE +BACKSPACE UPARROW +DOWNARROW LEFTARROW +RIGHTARROW ALT +CTRL SHIFT +INS DEL +PGDN PGUP +HOME END +PAUSE SEMICOLON + +MOUSE1 (mouse button 1) +MOUSE2 (mouse button 2) +MOUSE3 (mouse button 3) + +*~ (tilde) + +* Can only be bound on the command line or in a .cfg file. + +The ESC key cannot be bound. + + +========================================== +== Making a Config File == +========================================== + +The commands (bindings and aliases) discussed above can be included into a +file containing all of your personal configurations, known as a "config" +file. This file can then be loaded during game play to enable all your +personal bindings and settings. + +To do this, use your favorite editor to create a new file, such as +"fragmstr.cfg". Your .cfg file MUST be located in the quake\id1 directory +or quake won't find it. Then after launching Quake, you would type "exec +fragmstr.cfg" and press enter, from the console. You can also exec you .cfg +file from the DOS command prompt by typing "quake +exec fragmstr.cfg". +When you exec a config file, it is the same as typing all the lines in your +config file into the console, only Quake does it for you. Here is an +example config file (c:\quake\id1\bear.cfg) and the meaning of all the +bindings, aliases and settings: + +-------------------------------cut here------------------------------------- +name player1 // Sets player name to player1 (lets your opponent + // know who fragged them) + +sensitivity 4 // Sets the mouse sensitivity to 4 + +scr_conspeed 5000 // Sets the console raise/lower speed + +lookspring 0 // Sets Mouse Look Spring to 0 (0=keep looking, + // 1=spring back, when mouse button is released) + +vid_mode 10 // Sets Video Mode to mode 10 (360X480 resolution) + +gamma .8 // Sets Gamma Correction to .8 (<1=Lighter, 1=normal + // and >1=darker) + +viewsize 70 // Sets the Screen View size to 70 degrees + +bind mouse1 +forward // Binds the left mouse button to Move Forward + +bind mouse3 +attack // Binds the middle mouse button to Fire + +bind mouse2 +mlook // Binds the right mouse button to Mouse Look + +bind HOME "save bear1" // Binds the Home Key to quick save, saves to + // bear1.sav + +bind ENTER +showscores // Binds the Enter key to show Deathmatch Scores + +bind SHIFT +speed // Binds the Shift key to Run + +bind CTRL +jump // Binds the Control key to Jump + +bind ; +mlook // Binds the ; key to Mouse Look also + +bind . +moveleft // Binds the . key to Strafe Left + +bind / +moveright // Binds the / key to Strafe Right + +color 3 4 // Makes Uniform Top green and Pants Red for Net play + +alias rl_dbsg "impulse 7 ; +attack ; wait ; -attack ; impulse 3" + +bind , rl_dbsg // Aliases single rocket attack command and binds + // it to the ',' key. +-------------------------------cut here------------------------------------- + + +========================================== +== Demos == +========================================== + +The standard Demos +------------------ + +Quake has 3 standard demos that start playing when you first run the game. +It will cycle through these demos until you start or join a game. + +Recording a Demo +---------------- +"record [track]" This starts up level and begins +recording a demo into a file name .dem. You can specify the +optional to choose a background music from the CD, otherwise the +default selection for that map will be played. + +Playing a Demo +-------------- +"playdemo " This command will open the file .dem and +play the demo. + +How to not play the standard demos at startup +--------------------------------------------- + +So you've seen the Necropolis demo 10 billion times now and really don't +ever want to see it again? Here's how. + +The easy way is to start Quake with a "+map" command. You could do +"quake +map start" and you'll start on the single player start level. +Or you could do "quake +map nonsense" and you'll wind up at the Quake +console since there is no map named nonsense. You can accomplish the +same thing with a "+connect" too. "+connect" by itself will look for +Quake servers on the local network, "+connect 192.12.34.56" or +"+connect host.timbuktu.edu" will try to connect the the specified +Quake server. + +There is another way to not show the demos; one that also keeps your +customizations in a seperate directory from the data files in the +Quake distribution. + +Do this in the quake directory (the directory where you installed Quake; +where you find "quake.exe" and "the id1" directory). Create a file named +"quake.rc". Its contents should be: + +exec default.cfg +exec config.cfg +exec autoexec.cfg +stuffcmds +menu_main + +Create a batch file to run Quake in the quake directory. "Q.BAT" is a good +name. It's contents should be: + +quake -game . %1 %2 %3 %4 %5 %6 %7 %8 %9 + +If you normally use the Q95 batch file, just add the "-game ." part to +that file. + +Now you can run "q" and quake will start off with the main menu displayed +instead of running the demos. + +You can also make a seperate subdirectory for this if you'd like. For +example, make a directory named "mine" in the quake directory. Create +the "quake.rc" file as specified above in this directory. Use +"-game mine" instead of "-game ." in your batch file. + +Important note: The directory specified by "-game" is where Quake will +look for config.cfg, load and save games, and record and play +demos. + + +========================================== +== Reporting Quake Bugs == +========================================== + +How to use the bug report: + +Where to send bug reports: +E-mail : support@idsoftware.com +FAX : 214-686-9288 + +There are two sections of information - primary and secondary. + +Primary information contains information such as date, your name, e-mail +address, etc. Secondary information is actual bug information. There are +a few different sections depending on what type of bug you revieced +(sound, video, etc). Only fill out and include information from the section +related to the type of bug you received. + +If possible, start Quake with the "-condebug" command line parameter +and try to reproduce the bug. Attach the "qconsole.log" file found in the +"id1" directory to the end of the bug report. If the bug is sound related, +while in Quake, execute the SOUNDINFO and SBINFO (DOS only) commands from +the console. + +Please attach a copy of your CONFIG.SYS and AUTOEXEC.BAT file to the end of +the report. + +Bugs submitted properly with this form will get attention. +Unformatted ones sent to personal accounts will be ignored. +If you see problems, please take the time to do this. + +If you do not have all of the information requested in the form, +don't worry. Send what you do have. + +Please include the version #. THe version # for Quake can be found in the +lower right hand corner of the console. To bring up the console, press the +tilde ('~') key. Press tilde ('~') again or ESC to exit. + +-------------------------------cut here------------------------------------- + + +============================================================================ +== Quake Bug Report - Primary information == +============================================================================ + +Date: +Name: +Phone number: +E-mail address: (please include this, we redirect tons of mail) +Game Title: +Version #: +Operating system (i.e., DOS 6.0 or Windows 95): +Computer type: +BIOS date: +BIOS version: +Processor type: +Processor speed: +Do you program at school/work? +Do you provide tech. support at school/work? +Please state the problem you encountered: +Please state how to reproduce the problem: + +If program crashed with nasty undecipherable techno-garbage, please +look for the eight-digit hex number which comes after "eip=" +and write it down here: + + +============================================================================ +== Quake Bug Report - Secondary information == +============================================================================ + +------------------------------ Video Related ------------------------------ + +Video Card Manufacturer: +Video Card Model: +Chipset Used: +BIOS Date: +(If using UniVBE, The above information can be found by running uvconfig) + +Did the problem occur while in a VESA mode? + +If so, what is the VESA driver and version? (eg., UniVBE 5.1a, +built into board BIOS, or manufacturer provided TSR) + +------------------------------ Sound Related ------------------------------ + +Audio card brand and model: + +If DOS or a DOS box, please run the command "set > set.txt" then +attach "set.txt" to the end of the report. + +----------------------------- Network Related ----------------------------- + +What type of network connection was established when the error occurred? +(modem, nullmodem, or network) +If modem, Modem brand and model: + +If network, Network card brand and model: + Network protocol/configuration: + +--------------------------------------------------------------------------- + + + + + + + + diff --git a/engine/docs/UQE Quake.pdf b/engine/docs/UQE Quake.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d3939c7cd5a6e7344be4437bb3c800d4bfaefd4f GIT binary patch literal 503181 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�mh!*7g8qlWMjW3hnJ* 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 z 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

=9Ma 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 ^CYS(-90+@l`{Vl6Pw8mL^N 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 xqVeRxkgPzHi*B2tB^34K-lA^d%6L3A{#{M*(h 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

bZKMuGJg#PF<&u8_Fm&l13||z0t+!Y4kG&8bghd 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 literal 0 HcmV?d00001 diff --git a/engine/fmod-4/inc/fmod.h b/engine/fmod-4/inc/fmod.h new file mode 100644 index 0000000..1e5b492 --- /dev/null +++ b/engine/fmod-4/inc/fmod.h @@ -0,0 +1,2473 @@ + +/* ============================================================================================ */ +/* FMOD Ex - Main C/C++ header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* This header is the base header for all other FMOD headers. If you are programming in C */ +/* use this exclusively, or if you are programming C++ use this in conjunction with FMOD.HPP */ +/* */ +/* ============================================================================================ */ + +#ifndef _FMOD_H +#define _FMOD_H + +/* + FMOD version number. Check this against FMOD::System::getVersion. + 0xaaaabbcc -> aaaa = major version number. bb = minor version number. cc = development version number. +*/ + +#define FMOD_VERSION 0x00044461 + +/* + Compiler specific settings. +*/ + +#if defined(__CYGWIN32__) + #define F_CDECL __cdecl + #define F_STDCALL __stdcall + #define F_DECLSPEC __declspec + #define F_DLLEXPORT ( dllexport ) +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) + #define F_CDECL _cdecl + #define F_STDCALL _stdcall + #define F_DECLSPEC __declspec + #define F_DLLEXPORT ( dllexport ) +#elif defined(__MACH__) || defined(__ANDROID__) || defined(__linux__) || defined(__QNX__) + #define F_CDECL + #define F_STDCALL + #define F_DECLSPEC + #define F_DLLEXPORT __attribute__ ((visibility("default"))) +#else + #define F_CDECL + #define F_STDCALL + #define F_DECLSPEC + #define F_DLLEXPORT +#endif + +#ifdef DLL_EXPORTS + #if defined(__MACH__) || defined(__ANDROID__) || defined(__linux__) || defined(__QNX__) + #define F_API __attribute__ ((visibility("default"))) + #else + #define F_API __declspec(dllexport) F_STDCALL + #endif +#else + #define F_API F_STDCALL +#endif + +#define F_CALLBACK F_STDCALL + +/* + FMOD types. +*/ + +typedef int FMOD_BOOL; +typedef struct FMOD_SYSTEM FMOD_SYSTEM; +typedef struct FMOD_SOUND FMOD_SOUND; +typedef struct FMOD_CHANNEL FMOD_CHANNEL; +typedef struct FMOD_CHANNELGROUP FMOD_CHANNELGROUP; +typedef struct FMOD_SOUNDGROUP FMOD_SOUNDGROUP; +typedef struct FMOD_REVERB FMOD_REVERB; +typedef struct FMOD_DSP FMOD_DSP; +typedef struct FMOD_DSPCONNECTION FMOD_DSPCONNECTION; +typedef struct FMOD_POLYGON FMOD_POLYGON; +typedef struct FMOD_GEOMETRY FMOD_GEOMETRY; +typedef struct FMOD_SYNCPOINT FMOD_SYNCPOINT; +typedef struct FMOD_ASYNCREADINFO FMOD_ASYNCREADINFO; +typedef unsigned int FMOD_MODE; +typedef unsigned int FMOD_TIMEUNIT; +typedef unsigned int FMOD_INITFLAGS; +typedef unsigned int FMOD_CAPS; +typedef unsigned int FMOD_DEBUGLEVEL; +typedef unsigned int FMOD_MEMORY_TYPE; + +/* +[ENUM] +[ + [DESCRIPTION] + error codes. Returned from every function. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] +] +*/ +typedef enum +{ + FMOD_OK, /* No errors. */ + FMOD_ERR_ALREADYLOCKED, /* Tried to call lock a second time before unlock was called. */ + FMOD_ERR_BADCOMMAND, /* Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). */ + FMOD_ERR_CDDA_DRIVERS, /* Neither NTSCSI nor ASPI could be initialised. */ + FMOD_ERR_CDDA_INIT, /* An error occurred while initialising the CDDA subsystem. */ + FMOD_ERR_CDDA_INVALID_DEVICE, /* Couldn't find the specified device. */ + FMOD_ERR_CDDA_NOAUDIO, /* No audio tracks on the specified disc. */ + FMOD_ERR_CDDA_NODEVICES, /* No CD/DVD devices were found. */ + FMOD_ERR_CDDA_NODISC, /* No disc present in the specified drive. */ + FMOD_ERR_CDDA_READ, /* A CDDA read error occurred. */ + FMOD_ERR_CHANNEL_ALLOC, /* Error trying to allocate a channel. */ + FMOD_ERR_CHANNEL_STOLEN, /* The specified channel has been reused to play another sound. */ + FMOD_ERR_COM, /* A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. */ + FMOD_ERR_DMA, /* DMA Failure. See debug output for more information. */ + FMOD_ERR_DSP_CONNECTION, /* DSP connection error. Connection possibly caused a cyclic dependancy. Or tried to connect a tree too many units deep (more than 128). */ + FMOD_ERR_DSP_FORMAT, /* DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. */ + FMOD_ERR_DSP_NOTFOUND, /* DSP connection error. Couldn't find the DSP unit specified. */ + FMOD_ERR_DSP_RUNNING, /* DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. */ + FMOD_ERR_DSP_TOOMANYCONNECTIONS,/* DSP connection error. The unit being connected to or disconnected should only have 1 input or output. */ + FMOD_ERR_FILE_BAD, /* Error loading file. */ + FMOD_ERR_FILE_COULDNOTSEEK, /* Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. */ + FMOD_ERR_FILE_DISKEJECTED, /* Media was ejected while reading. */ + FMOD_ERR_FILE_EOF, /* End of file unexpectedly reached while trying to read essential data (truncated data?). */ + FMOD_ERR_FILE_NOTFOUND, /* File not found. */ + FMOD_ERR_FILE_UNWANTED, /* Unwanted file access occured. */ + FMOD_ERR_FORMAT, /* Unsupported file or audio format. */ + FMOD_ERR_HTTP, /* A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. */ + FMOD_ERR_HTTP_ACCESS, /* The specified resource requires authentication or is forbidden. */ + FMOD_ERR_HTTP_PROXY_AUTH, /* Proxy authentication is required to access the specified resource. */ + FMOD_ERR_HTTP_SERVER_ERROR, /* A HTTP server error occurred. */ + FMOD_ERR_HTTP_TIMEOUT, /* The HTTP request timed out. */ + FMOD_ERR_INITIALIZATION, /* FMOD was not initialized correctly to support this function. */ + FMOD_ERR_INITIALIZED, /* Cannot call this command after System::init. */ + FMOD_ERR_INTERNAL, /* An error occured that wasn't supposed to. Contact support. */ + FMOD_ERR_INVALID_ADDRESS, /* On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) */ + FMOD_ERR_INVALID_FLOAT, /* Value passed in was a NaN, Inf or denormalized float. */ + FMOD_ERR_INVALID_HANDLE, /* An invalid object handle was used. */ + FMOD_ERR_INVALID_PARAM, /* An invalid parameter was passed to this function. */ + FMOD_ERR_INVALID_POSITION, /* An invalid seek position was passed to this function. */ + FMOD_ERR_INVALID_SPEAKER, /* An invalid speaker was passed to this function based on the current speaker mode. */ + FMOD_ERR_INVALID_SYNCPOINT, /* The syncpoint did not come from this sound handle. */ + FMOD_ERR_INVALID_VECTOR, /* The vectors passed in are not unit length, or perpendicular. */ + FMOD_ERR_MAXAUDIBLE, /* Reached maximum audible playback count for this sound's soundgroup. */ + FMOD_ERR_MEMORY, /* Not enough memory or resources. */ + FMOD_ERR_MEMORY_CANTPOINT, /* Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. */ + FMOD_ERR_MEMORY_SRAM, /* Not enough memory or resources on console sound ram. */ + FMOD_ERR_NEEDS2D, /* Tried to call a command on a 3d sound when the command was meant for 2d sound. */ + FMOD_ERR_NEEDS3D, /* Tried to call a command on a 2d sound when the command was meant for 3d sound. */ + FMOD_ERR_NEEDSHARDWARE, /* Tried to use a feature that requires hardware support. (ie trying to play a GCADPCM compressed sound in software on Wii). */ + FMOD_ERR_NEEDSSOFTWARE, /* Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. */ + FMOD_ERR_NET_CONNECT, /* Couldn't connect to the specified host. */ + FMOD_ERR_NET_SOCKET_ERROR, /* A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. */ + FMOD_ERR_NET_URL, /* The specified URL couldn't be resolved. */ + FMOD_ERR_NET_WOULD_BLOCK, /* Operation on a non-blocking socket could not complete immediately. */ + FMOD_ERR_NOTREADY, /* Operation could not be performed because specified sound/DSP connection is not ready. */ + FMOD_ERR_OUTPUT_ALLOCATED, /* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */ + FMOD_ERR_OUTPUT_CREATEBUFFER, /* Error creating hardware sound buffer. */ + FMOD_ERR_OUTPUT_DRIVERCALL, /* A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. */ + FMOD_ERR_OUTPUT_ENUMERATION, /* Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal. */ + FMOD_ERR_OUTPUT_FORMAT, /* Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). */ + FMOD_ERR_OUTPUT_INIT, /* Error initializing output device. */ + FMOD_ERR_OUTPUT_NOHARDWARE, /* FMOD_HARDWARE was specified but the sound card does not have the resources necessary to play it. */ + FMOD_ERR_OUTPUT_NOSOFTWARE, /* Attempted to create a software sound but no software channels were specified in System::init. */ + FMOD_ERR_PAN, /* Panning only works with mono or stereo sound sources. */ + FMOD_ERR_PLUGIN, /* An unspecified error has been returned from a 3rd party plugin. */ + FMOD_ERR_PLUGIN_INSTANCES, /* The number of allowed instances of a plugin has been exceeded. */ + FMOD_ERR_PLUGIN_MISSING, /* A requested output, dsp unit type or codec was not available. */ + FMOD_ERR_PLUGIN_RESOURCE, /* A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback or other DLLs that it needs to load) */ + FMOD_ERR_PRELOADED, /* The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. */ + FMOD_ERR_PROGRAMMERSOUND, /* The specified sound is still in use by the event system, wait for the event which is using it finish with it. */ + FMOD_ERR_RECORD, /* An error occured trying to initialize the recording device. */ + FMOD_ERR_REVERB_INSTANCE, /* Specified instance in FMOD_REVERB_PROPERTIES couldn't be set. Most likely because it is an invalid instance number or the reverb doesnt exist. */ + FMOD_ERR_SUBSOUND_ALLOCATED, /* This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. */ + FMOD_ERR_SUBSOUND_CANTMOVE, /* Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file. */ + FMOD_ERR_SUBSOUND_MODE, /* The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with. */ + FMOD_ERR_SUBSOUNDS, /* The error occured because the sound referenced contains subsounds when it shouldn't have, or it doesn't contain subsounds when it should have. The operation may also not be able to be performed on a parent sound, or a parent sound was played without setting up a sentence first. */ + FMOD_ERR_TAGNOTFOUND, /* The specified tag could not be found or there are no tags. */ + FMOD_ERR_TOOMANYCHANNELS, /* The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. */ + FMOD_ERR_UNIMPLEMENTED, /* Something in FMOD hasn't been implemented when it should be! contact support! */ + FMOD_ERR_UNINITIALIZED, /* This command failed because System::init or System::setDriver was not called. */ + FMOD_ERR_UNSUPPORTED, /* A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. */ + FMOD_ERR_UPDATE, /* An error caused by System::update occured. */ + FMOD_ERR_VERSION, /* The version number of this file format is not supported. */ + + FMOD_ERR_EVENT_FAILED, /* An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. */ + FMOD_ERR_EVENT_INFOONLY, /* Can't execute this command on an EVENT_INFOONLY event. */ + FMOD_ERR_EVENT_INTERNAL, /* An error occured that wasn't supposed to. See debug log for reason. */ + FMOD_ERR_EVENT_MAXSTREAMS, /* Event failed because 'Max streams' was hit when FMOD_EVENT_INIT_FAIL_ON_MAXSTREAMS was specified. */ + FMOD_ERR_EVENT_MISMATCH, /* FSB mismatches the FEV it was compiled with, the stream/sample mode it was meant to be created with was different, or the FEV was built for a different platform. */ + FMOD_ERR_EVENT_NAMECONFLICT, /* A category with the same name already exists. */ + FMOD_ERR_EVENT_NOTFOUND, /* The requested event, event group, event category or event property could not be found. */ + FMOD_ERR_EVENT_NEEDSSIMPLE, /* Tried to call a function on a complex event that's only supported by simple events. */ + FMOD_ERR_EVENT_GUIDCONFLICT, /* An event with the same GUID already exists. */ + FMOD_ERR_EVENT_ALREADY_LOADED, /* The specified project or bank has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. */ + + FMOD_ERR_MUSIC_UNINITIALIZED, /* Music system is not initialized probably because no music data is loaded. */ + FMOD_ERR_MUSIC_NOTFOUND, /* The requested music entity could not be found. */ + FMOD_ERR_MUSIC_NOCALLBACK, /* The music callback is required, but it has not been set. */ + + FMOD_RESULT_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_RESULT; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a point in 3D space. + + [REMARKS] + FMOD uses a left handed co-ordinate system by default. + To use a right handed co-ordinate system specify FMOD_INIT_3D_RIGHTHANDED from FMOD_INITFLAGS in System::init. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::set3DListenerAttributes + System::get3DListenerAttributes + Channel::set3DAttributes + Channel::get3DAttributes + Channel::set3DCustomRolloff + Channel::get3DCustomRolloff + Sound::set3DCustomRolloff + Sound::get3DCustomRolloff + Geometry::addPolygon + Geometry::setPolygonVertex + Geometry::getPolygonVertex + Geometry::setRotation + Geometry::getRotation + Geometry::setPosition + Geometry::getPosition + Geometry::setScale + Geometry::getScale + FMOD_INITFLAGS +] +*/ +typedef struct +{ + float x; /* X co-ordinate in 3D space. */ + float y; /* Y co-ordinate in 3D space. */ + float z; /* Z co-ordinate in 3D space. */ +} FMOD_VECTOR; + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a globally unique identifier. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::getDriverInfo +] +*/ +typedef struct +{ + unsigned int Data1; /* Specifies the first 8 hexadecimal digits of the GUID */ + unsigned short Data2; /* Specifies the first group of 4 hexadecimal digits. */ + unsigned short Data3; /* Specifies the second group of 4 hexadecimal digits. */ + unsigned char Data4[8]; /* Array of 8 bytes. The first 2 bytes contain the third group of 4 hexadecimal digits. The remaining 6 bytes contain the final 12 hexadecimal digits. */ +} FMOD_GUID; + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure that is passed into FMOD_FILE_ASYNCREADCALLBACK. Use the information in this structure to perform + + [REMARKS] + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + Members marked with [w] mean the variable can be written to. The user can set the value. + + Instructions: write to 'buffer', and 'bytesread' BEFORE setting 'result'. + As soon as result is set, FMOD will asynchronously continue internally using the data provided in this structure. + + Set 'result' to the result expected from a normal file read callback. + If the read was successful, set it to FMOD_OK. + If it read some data but hit the end of the file, set it to FMOD_ERR_FILE_EOF. + If a bad error occurred, return FMOD_ERR_FILE_BAD + If a disk was ejected, return FMOD_ERR_FILE_DISKEJECTED. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_FILE_ASYNCREADCALLBACK + FMOD_FILE_ASYNCCANCELCALLBACK +] +*/ +struct FMOD_ASYNCREADINFO +{ + void *handle; /* [r] The file handle that was filled out in the open callback. */ + unsigned int offset; /* [r] Seek position, make sure you read from this file offset. */ + unsigned int sizebytes; /* [r] how many bytes requested for read. */ + int priority; /* [r] 0 = low importance. 100 = extremely important (ie 'must read now or stuttering may occur') */ + + void *buffer; /* [w] Buffer to read file data into. */ + unsigned int bytesread; /* [w] Fill this in before setting result code to tell FMOD how many bytes were read. */ + FMOD_RESULT result; /* [r/w] Result code, FMOD_OK tells the system it is ready to consume the data. Set this last! Default value = FMOD_ERR_NOTREADY. */ + + void *userdata; /* [r] User data pointer. */ + + const void (*done)(FMOD_ASYNCREADINFO *info, FMOD_RESULT result); /* FMOD file system wake up function. Use instead of 'result' with FMOD_INIT_ASYNCREAD_FAST to get semaphore based performance improvement. Call this when user file read is finished. Pass result of file read as a parameter. */ +}; + + +/* +[ENUM] +[ + [DESCRIPTION] + These output types are used with System::setOutput / System::getOutput, to choose which output method to use. + + [REMARKS] + To pass information to the driver when initializing fmod use the extradriverdata parameter in System::init for the following reasons. + - FMOD_OUTPUTTYPE_WAVWRITER - extradriverdata is a pointer to a char * filename that the wav writer will output to. + - FMOD_OUTPUTTYPE_WAVWRITER_NRT - extradriverdata is a pointer to a char * filename that the wav writer will output to. + - FMOD_OUTPUTTYPE_DSOUND - extradriverdata is a pointer to a HWND so that FMOD can set the focus on the audio for a particular window. + - FMOD_OUTPUTTYPE_PS3 - extradriverdata is a pointer to a FMOD_PS3_EXTRADRIVERDATA struct. This can be found in fmodps3.h. + - FMOD_OUTPUTTYPE_GC - extradriverdata is a pointer to a FMOD_GC_INFO struct. This can be found in fmodgc.h. + - FMOD_OUTPUTTYPE_WII - extradriverdata is a pointer to a FMOD_WII_INFO struct. This can be found in fmodwii.h. + - FMOD_OUTPUTTYPE_ALSA - extradriverdata is a pointer to a FMOD_LINUX_EXTRADRIVERDATA struct. This can be found in fmodlinux.h. + - FMOD_OUTPUTTYPE_PULSEAUDIO - extradriverdata is a const char * representing the name of the application to appear in PulseAudio mixer GUIs. + + Currently these are the only FMOD drivers that take extra information. Other unknown plugins may have different requirements. + + Note! If FMOD_OUTPUTTYPE_WAVWRITER_NRT or FMOD_OUTPUTTYPE_NOSOUND_NRT are used, and if the System::update function is being called + very quickly (ie for a non realtime decode) it may be being called too quickly for the FMOD streamer thread to respond to. + The result will be a skipping/stuttering output in the captured audio. + + To remedy this, disable the FMOD Ex streamer thread, and use FMOD_INIT_STREAM_FROM_UPDATE to avoid skipping in the output stream, + as it will lock the mixer and the streamer together in the same thread. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setOutput + System::getOutput + System::setSoftwareFormat + System::getSoftwareFormat + System::init + System::update + FMOD_INITFLAGS +] +*/ +typedef enum +{ + FMOD_OUTPUTTYPE_AUTODETECT, /* Picks the best output mode for the platform. This is the default. */ + + FMOD_OUTPUTTYPE_UNKNOWN, /* All - 3rd party plugin, unknown. This is for use with System::getOutput only. */ + FMOD_OUTPUTTYPE_NOSOUND, /* All - All calls in this mode succeed but make no sound. */ + FMOD_OUTPUTTYPE_WAVWRITER, /* All - Writes output to fmodoutput.wav by default. Use the 'extradriverdata' parameter in System::init, by simply passing the filename as a string, to set the wav filename. */ + FMOD_OUTPUTTYPE_NOSOUND_NRT, /* All - Non-realtime version of FMOD_OUTPUTTYPE_NOSOUND. User can drive mixer with System::update at whatever rate they want. */ + FMOD_OUTPUTTYPE_WAVWRITER_NRT, /* All - Non-realtime version of FMOD_OUTPUTTYPE_WAVWRITER. User can drive mixer with System::update at whatever rate they want. */ + + FMOD_OUTPUTTYPE_DSOUND, /* Win32/Win64 - DirectSound output. (Default on Windows XP and below) */ + FMOD_OUTPUTTYPE_WINMM, /* Win32/Win64 - Windows Multimedia output. */ + FMOD_OUTPUTTYPE_WASAPI, /* Win32 - Windows Audio Session API. (Default on Windows Vista and above) */ + FMOD_OUTPUTTYPE_ASIO, /* Win32 - Low latency ASIO 2.0 driver. */ + FMOD_OUTPUTTYPE_OSS, /* Linux/Linux64 - Open Sound System output. (Default on Linux, third preference) */ + FMOD_OUTPUTTYPE_ALSA, /* Linux/Linux64 - Advanced Linux Sound Architecture output. (Default on Linux, second preference if available) */ + FMOD_OUTPUTTYPE_ESD, /* Linux/Linux64 - Enlightment Sound Daemon output. */ + FMOD_OUTPUTTYPE_PULSEAUDIO, /* Linux/Linux64 - PulseAudio output. (Default on Linux, first preference if available) */ + FMOD_OUTPUTTYPE_COREAUDIO, /* Mac - Macintosh CoreAudio output. (Default on Mac) */ + FMOD_OUTPUTTYPE_XBOX360, /* Xbox 360 - Native Xbox360 output. (Default on Xbox 360) */ + FMOD_OUTPUTTYPE_PSP, /* PSP - Native PSP output. (Default on PSP) */ + FMOD_OUTPUTTYPE_PS3, /* PS3 - Native PS3 output. (Default on PS3) */ + FMOD_OUTPUTTYPE_NGP, /* NGP - Native NGP output. (Default on NGP) */ + FMOD_OUTPUTTYPE_WII, /* Wii - Native Wii output. (Default on Wii) */ + FMOD_OUTPUTTYPE_3DS, /* 3DS - Native 3DS output (Default on 3DS) */ + FMOD_OUTPUTTYPE_AUDIOTRACK, /* Android - Java Audio Track output. (Default on Android 2.2 and below) */ + FMOD_OUTPUTTYPE_OPENSL, /* Android - OpenSL ES output. (Default on Android 2.3 and above) */ + FMOD_OUTPUTTYPE_NACL, /* Native Client - Native Client output. (Default on Native Client) */ + FMOD_OUTPUTTYPE_WIIU, /* Wii U - Native Wii U output. (Default on Wii U) */ + FMOD_OUTPUTTYPE_ASOUND, /* BlackBerry - Native BlackBerry asound output. (Default on BlackBerry) */ + FMOD_OUTPUTTYPE_AUDIOOUT, /* Orbis - Audio Out output. (Default on Orbis) */ + FMOD_OUTPUTTYPE_XAUDIO, /* Durango - XAudio2 output. */ + + FMOD_OUTPUTTYPE_MAX, /* Maximum number of output types supported. */ + FMOD_OUTPUTTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_OUTPUTTYPE; + + +/* +[DEFINE] +[ + [NAME] + FMOD_CAPS + + [DESCRIPTION] + Bit fields to use with System::getDriverCaps to determine the capabilities of a card / output device. + + [REMARKS] + It is important to check FMOD_CAPS_HARDWARE_EMULATED on windows machines, to then adjust System::setDSPBufferSize to (1024, 10) to compensate for the higher latency. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::getDriverCaps + System::setDSPBufferSize +] +*/ +#define FMOD_CAPS_NONE 0x00000000 /* Device has no special capabilities. */ +#define FMOD_CAPS_HARDWARE 0x00000001 /* Device supports hardware mixing. */ +#define FMOD_CAPS_HARDWARE_EMULATED 0x00000002 /* User has device set to 'Hardware acceleration = off' in control panel, and now extra 200ms latency is incurred. */ +#define FMOD_CAPS_OUTPUT_MULTICHANNEL 0x00000004 /* Device can do multichannel output, ie greater than 2 channels. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM8 0x00000008 /* Device can output to 8bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM16 0x00000010 /* Device can output to 16bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM24 0x00000020 /* Device can output to 24bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCM32 0x00000040 /* Device can output to 32bit integer PCM. */ +#define FMOD_CAPS_OUTPUT_FORMAT_PCMFLOAT 0x00000080 /* Device can output to 32bit floating point PCM. */ +#define FMOD_CAPS_REVERB_LIMITED 0x00002000 /* Device supports some form of limited hardware reverb, maybe parameterless and only selectable by environment. */ +#define FMOD_CAPS_LOOPBACK 0x00004000 /* Device is a loopback recording device */ +/* [DEFINE_END] */ + +/* +[DEFINE] +[ + [NAME] + FMOD_DEBUGLEVEL + + [DESCRIPTION] + Bit fields to use with FMOD::Debug_SetLevel / FMOD::Debug_GetLevel to control the level of tty debug output with logging versions of FMOD (fmodL). + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Debug_SetLevel + Debug_GetLevel +] +*/ +#define FMOD_DEBUG_LEVEL_NONE 0x00000000 +#define FMOD_DEBUG_LEVEL_LOG 0x00000001 /* Will display generic logging messages. */ +#define FMOD_DEBUG_LEVEL_ERROR 0x00000002 /* Will display errors. */ +#define FMOD_DEBUG_LEVEL_WARNING 0x00000004 /* Will display warnings that are not fatal. */ +#define FMOD_DEBUG_LEVEL_HINT 0x00000008 /* Will hint to you if there is something possibly better you could be doing. */ +#define FMOD_DEBUG_LEVEL_ALL 0x000000FF +#define FMOD_DEBUG_TYPE_MEMORY 0x00000100 /* Show FMOD memory related logging messages. */ +#define FMOD_DEBUG_TYPE_THREAD 0x00000200 /* Show FMOD thread related logging messages. */ +#define FMOD_DEBUG_TYPE_FILE 0x00000400 /* Show FMOD file system related logging messages. */ +#define FMOD_DEBUG_TYPE_NET 0x00000800 /* Show FMOD network related logging messages. */ +#define FMOD_DEBUG_TYPE_EVENT 0x00001000 /* Show FMOD Event related logging messages. */ +#define FMOD_DEBUG_TYPE_ALL 0x0000FFFF +#define FMOD_DEBUG_DISPLAY_TIMESTAMPS 0x01000000 /* Display the timestamp of the log entry in milliseconds. */ +#define FMOD_DEBUG_DISPLAY_LINENUMBERS 0x02000000 /* Display the FMOD Ex source code line numbers, for debugging purposes. */ +#define FMOD_DEBUG_DISPLAY_COMPRESS 0x04000000 /* If a message is repeated more than 5 times it will stop displaying it and instead display the number of times the message was logged. */ +#define FMOD_DEBUG_DISPLAY_THREAD 0x08000000 /* Display the thread ID of the calling function that caused this log entry to appear. */ +#define FMOD_DEBUG_DISPLAY_ALL 0x0F000000 +#define FMOD_DEBUG_ALL 0xFFFFFFFF +/* [DEFINE_END] */ + + +/* +[DEFINE] +[ + [NAME] + FMOD_MEMORY_TYPE + + [DESCRIPTION] + Bit fields for memory allocation type being passed into FMOD memory callbacks. + + [REMARKS] + Remember this is a bitfield. You may get more than 1 bit set (ie physical + persistent) so do not simply switch on the types! You must check each bit individually or clear out the bits that you do not want within the callback. + Bits can be excluded if you want during Memory_Initialize so that you never get them. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_MEMORY_ALLOCCALLBACK + FMOD_MEMORY_REALLOCCALLBACK + FMOD_MEMORY_FREECALLBACK + Memory_Initialize + +] +*/ +#define FMOD_MEMORY_NORMAL 0x00000000 /* Standard memory. */ +#define FMOD_MEMORY_STREAM_FILE 0x00000001 /* Stream file buffer, size controllable with System::setStreamBufferSize. */ +#define FMOD_MEMORY_STREAM_DECODE 0x00000002 /* Stream decode buffer, size controllable with FMOD_CREATESOUNDEXINFO::decodebuffersize. */ +#define FMOD_MEMORY_SAMPLEDATA 0x00000004 /* Sample data buffer. Raw audio data, usually PCM/MPEG/ADPCM/XMA data. */ +#define FMOD_MEMORY_DSP_OUTPUTBUFFER 0x00000008 /* DSP memory block allocated when more than 1 output exists on a DSP node. */ +#define FMOD_MEMORY_XBOX360_PHYSICAL 0x00100000 /* Requires XPhysicalAlloc / XPhysicalFree. */ +#define FMOD_MEMORY_PERSISTENT 0x00200000 /* Persistent memory. Memory will be freed when System::release is called. */ +#define FMOD_MEMORY_SECONDARY 0x00400000 /* Secondary memory. Allocation should be in secondary memory. For example RSX on the PS3. */ +#define FMOD_MEMORY_ALL 0xFFFFFFFF +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + These are speaker types defined for use with the System::setSpeakerMode or System::getSpeakerMode command. + + [REMARKS] + These are important notes on speaker modes in regards to sounds created with FMOD_SOFTWARE. + Note below the phrase 'sound channels' is used. These are the subchannels inside a sound, they are not related and + have nothing to do with the FMOD class "Channel". + For example a mono sound has 1 sound channel, a stereo sound has 2 sound channels, and an AC3 or 6 channel wav file have 6 "sound channels". + + FMOD_SPEAKERMODE_RAW + --------------------- + This mode is for output devices that are not specifically mono/stereo/quad/surround/5.1 or 7.1, but are multichannel. + Use System::setSoftwareFormat to specify the number of speakers you want to address, otherwise it will default to 2 (stereo). + Sound channels map to speakers sequentially, so a mono sound maps to output speaker 0, stereo sound maps to output speaker 0 & 1. + The user assumes knowledge of the speaker order. FMOD_SPEAKER enumerations may not apply, so raw channel indices should be used. + Multichannel sounds map input channels to output channels 1:1. + Channel::setPan and Channel::setSpeakerMix do not work. + Speaker levels must be manually set with Channel::setSpeakerLevels. + + FMOD_SPEAKERMODE_MONO + --------------------- + This mode is for a 1 speaker arrangement. + Panning does not work in this speaker mode. + Mono, stereo and multichannel sounds have each sound channel played on the one speaker unity. + Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + Channel::setSpeakerMix does not work. + + FMOD_SPEAKERMODE_STEREO + ----------------------- + This mode is for 2 speaker arrangements that have a left and right speaker. + - Mono sounds default to an even distribution between left and right. They can be panned with Channel::setPan. + - Stereo sounds default to the middle, or full left in the left speaker and full right in the right speaker. + - They can be cross faded with Channel::setPan. + - Multichannel sounds have each sound channel played on each speaker at unity. + - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + - Channel::setSpeakerMix works but only front left and right parameters are used, the rest are ignored. + + FMOD_SPEAKERMODE_QUAD + ------------------------ + This mode is for 4 speaker arrangements that have a front left, front right, rear left and a rear right speaker. + - Mono sounds default to an even distribution between front left and front right. They can be panned with Channel::setPan. + - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. + - They can be cross faded with Channel::setPan. + - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. + - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + - Channel::setSpeakerMix works but side left, side right, center and lfe are ignored. + + FMOD_SPEAKERMODE_SURROUND + ------------------------ + This mode is for 5 speaker arrangements that have a left/right/center/rear left/rear right. + - Mono sounds default to the center speaker. They can be panned with Channel::setPan. + - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. + - They can be cross faded with Channel::setPan. + - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. + - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + - Channel::setSpeakerMix works but side left / side right are ignored. + + FMOD_SPEAKERMODE_5POINT1 + ------------------------ + This mode is for 5.1 speaker arrangements that have a left/right/center/rear left/rear right and a subwoofer speaker. + - Mono sounds default to the center speaker. They can be panned with Channel::setPan. + - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. + - They can be cross faded with Channel::setPan. + - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. + - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + - Channel::setSpeakerMix works but side left / side right are ignored. + + FMOD_SPEAKERMODE_7POINT1 + ------------------------ + This mode is for 7.1 speaker arrangements that have a left/right/center/rear left/rear right/side left/side right + and a subwoofer speaker. + - Mono sounds default to the center speaker. They can be panned with Channel::setPan. + - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. + - They can be cross faded with Channel::setPan. + - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. + - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. + - Channel::setSpeakerMix works and every parameter is used to set the balance of a sound in any speaker. + + FMOD_SPEAKERMODE_SRS5_1_MATRIX + ------------------------------------------------------ + This mode is for mono, stereo, 5.1 and 6.1 speaker arrangements, as it is backwards and forwards compatible with + stereo, but to get a surround effect a SRS 5.1, Prologic or Prologic 2 hardware decoder / amplifier is needed or + a compatible SRS equipped device (e.g., laptop, TV, etc.) or accessory (e.g., headphone). + Pan behavior is the same as FMOD_SPEAKERMODE_5POINT1. + + If this function is called the numoutputchannels setting in System::setSoftwareFormat is overwritten. + + Output rate must be 44100, 48000 or 96000 for this to work otherwise FMOD_ERR_OUTPUT_INIT will be returned. + + FMOD_SPEAKERMODE_DOLBY5_1_MATRIX + ------------------------------------------------------ + This mode is for 5.1 speaker arrangements using a stereo signal, to get a surround effect a Dolby Pro Logic II + hardware decoder / amplifier is needed. + Pan behavior is the same as FMOD_SPEAKERMODE_5POINT1. + + If this function is called the numoutputchannels setting in System::setSoftwareFormat is overwritten. + + Output rate must be 32000, 44100 or 48000 for this to work otherwise FMOD_ERR_OUTPUT_INIT will be returned. + + FMOD_SPEAKERMODE_MYEARS + ------------------------------------------------------ + This mode is for headphones. This will attempt to load a MyEars profile (see myears.net.au) and use it to generate + surround sound on headphones using a personalized HRTF algorithm, for realistic 3d sound. + Pan behavior is the same as FMOD_SPEAKERMODE_7POINT1. + MyEars speaker mode will automatically be set if the speakermode is FMOD_SPEAKERMODE_STEREO and the MyEars profile exists. + If this mode is set explicitly, FMOD_INIT_DISABLE_MYEARS_AUTODETECT has no effect. + If this mode is set explicitly and the MyEars profile does not exist, FMOD_ERR_OUTPUT_DRIVERCALL will be returned. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setSpeakerMode + System::getSpeakerMode + System::getDriverCaps + System::setSoftwareFormat + Channel::setSpeakerLevels +] +*/ +typedef enum +{ + FMOD_SPEAKERMODE_RAW, /* There is no specific speakermode. Sound channels are mapped in order of input to output. Use System::setSoftwareFormat to specify speaker count. See remarks for more information. */ + FMOD_SPEAKERMODE_MONO, /* The speakers are monaural. */ + FMOD_SPEAKERMODE_STEREO, /* The speakers are stereo (DEFAULT). */ + FMOD_SPEAKERMODE_QUAD, /* 4 speaker setup. This includes front left, front right, rear left, rear right. */ + FMOD_SPEAKERMODE_SURROUND, /* 5 speaker setup. This includes front left, front right, center, rear left, rear right. */ + FMOD_SPEAKERMODE_5POINT1, /* 5.1 speaker setup. This includes front left, front right, center, rear left, rear right and a subwoofer. */ + FMOD_SPEAKERMODE_7POINT1, /* 7.1 speaker setup. This includes front left, front right, center, rear left, rear right, side left, side right and a subwoofer. */ + + FMOD_SPEAKERMODE_SRS5_1_MATRIX, /* Stereo compatible output, embedded with surround information. SRS 5.1/Prologic/Prologic2 decoders will split the signal into a 5.1 speaker set-up or SRS virtual surround will decode into a 2-speaker/headphone setup. See remarks about limitations.*/ + FMOD_SPEAKERMODE_DOLBY5_1_MATRIX, /* Stereo compatible output, embedded with surround information. Dolby Pro Logic II decoders will split the signal into a 5.1 speaker set-up. */ + FMOD_SPEAKERMODE_MYEARS, /* Stereo output, but data is encoded using personalized HRTF algorithms. See myears.net.au */ + + FMOD_SPEAKERMODE_MAX, /* Maximum number of speaker modes supported. */ + FMOD_SPEAKERMODE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SPEAKERMODE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These are speaker types defined for use with the Channel::setSpeakerLevels command. + It can also be used for speaker placement in the System::set3DSpeakerPosition command. + + [REMARKS] + If you are using FMOD_SPEAKERMODE_RAW and speaker assignments are meaningless, just cast a raw integer value to this type. + For example (FMOD_SPEAKER)7 would use the 7th speaker (also the same as FMOD_SPEAKER_SIDE_RIGHT). + Values higher than this can be used if an output system has more than 8 speaker types / output channels. 15 is the current maximum. + + NOTE: On Playstation 3 in 7.1, the extra 2 speakers are not side left/side right, they are 'surround back left'/'surround back right' which + locate the speakers behind the listener instead of to the sides like on PC. FMOD_SPEAKER_SBL/FMOD_SPEAKER_SBR are provided to make it + clearer what speaker is being addressed on that platform. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_SPEAKERMODE + Channel::setSpeakerLevels + Channel::getSpeakerLevels + System::set3DSpeakerPosition + System::get3DSpeakerPosition +] +*/ +typedef enum +{ + FMOD_SPEAKER_FRONT_LEFT, + FMOD_SPEAKER_FRONT_RIGHT, + FMOD_SPEAKER_FRONT_CENTER, + FMOD_SPEAKER_LOW_FREQUENCY, + FMOD_SPEAKER_BACK_LEFT, + FMOD_SPEAKER_BACK_RIGHT, + FMOD_SPEAKER_SIDE_LEFT, + FMOD_SPEAKER_SIDE_RIGHT, + + FMOD_SPEAKER_MAX, /* Maximum number of speaker types supported. */ + FMOD_SPEAKER_MONO = FMOD_SPEAKER_FRONT_LEFT, /* For use with FMOD_SPEAKERMODE_MONO and Channel::SetSpeakerLevels. Mapped to same value as FMOD_SPEAKER_FRONT_LEFT. */ + FMOD_SPEAKER_NULL = 65535, /* A non speaker. Use this with ASIO mapping to ignore a speaker. */ + FMOD_SPEAKER_SBL = FMOD_SPEAKER_SIDE_LEFT, /* For use with FMOD_SPEAKERMODE_7POINT1 on PS3 where the extra speakers are surround back inside of side speakers. */ + FMOD_SPEAKER_SBR = FMOD_SPEAKER_SIDE_RIGHT, /* For use with FMOD_SPEAKERMODE_7POINT1 on PS3 where the extra speakers are surround back inside of side speakers. */ + FMOD_SPEAKER_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SPEAKER; + + +/* +[ENUM] +[ + [DESCRIPTION] + These are plugin types defined for use with the System::getNumPlugins, + System::getPluginInfo and System::unloadPlugin functions. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::getNumPlugins + System::getPluginInfo + System::unloadPlugin +] +*/ +typedef enum +{ + FMOD_PLUGINTYPE_OUTPUT, /* The plugin type is an output module. FMOD mixed audio will play through one of these devices */ + FMOD_PLUGINTYPE_CODEC, /* The plugin type is a file format codec. FMOD will use these codecs to load file formats for playback. */ + FMOD_PLUGINTYPE_DSP, /* The plugin type is a DSP unit. FMOD will use these plugins as part of its DSP network to apply effects to output or generate sound in realtime. */ + + FMOD_PLUGINTYPE_MAX, /* Maximum number of plugin types supported. */ + FMOD_PLUGINTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_PLUGINTYPE; + + +/* +[DEFINE] +[ + [NAME] + FMOD_INITFLAGS + + [DESCRIPTION] + Initialization flags. Use them with System::init in the flags parameter to change various behavior. + + [REMARKS] + Use System::setAdvancedSettings to adjust settings for some of the features that are enabled by these flags. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::init + System::update + System::setAdvancedSettings + Channel::set3DOcclusion +] +*/ +#define FMOD_INIT_NORMAL 0x00000000 /* All platforms - Initialize normally */ +#define FMOD_INIT_STREAM_FROM_UPDATE 0x00000001 /* All platforms - No stream thread is created internally. Streams are driven from System::update. Mainly used with non-realtime outputs. */ +#define FMOD_INIT_3D_RIGHTHANDED 0x00000002 /* All platforms - FMOD will treat +X as right, +Y as up and +Z as backwards (towards you). */ +#define FMOD_INIT_SOFTWARE_DISABLE 0x00000004 /* All platforms - Disable software mixer to save memory. Anything created with FMOD_SOFTWARE will fail and DSP will not work. */ +#define FMOD_INIT_OCCLUSION_LOWPASS 0x00000008 /* All platforms - All FMOD_SOFTWARE (and FMOD_HARDWARE on 3DS and NGP) with FMOD_3D based voices will add a software lowpass filter effect into the DSP chain which is automatically used when Channel::set3DOcclusion is used or the geometry API. */ +#define FMOD_INIT_HRTF_LOWPASS 0x00000010 /* All platforms - All FMOD_SOFTWARE (and FMOD_HARDWARE on 3DS and NGP) with FMOD_3D based voices will add a software lowpass filter effect into the DSP chain which causes sounds to sound duller when the sound goes behind the listener. Use System::setAdvancedSettings to adjust cutoff frequency. */ +#define FMOD_INIT_DISTANCE_FILTERING 0x00000200 /* All platforms - All FMOD_SOFTWARE with FMOD_3D based voices will add a software lowpass and highpass filter effect into the DSP chain which will act as a distance-automated bandpass filter. Use System::setAdvancedSettings to adjust the center frequency. */ +#define FMOD_INIT_REVERB_PREALLOCBUFFERS 0x00000040 /* All platforms - FMOD Software reverb will preallocate enough buffers for reverb per channel, rather than allocating them and freeing them at runtime. */ +#define FMOD_INIT_ENABLE_PROFILE 0x00000020 /* All platforms - Enable TCP/IP based host which allows FMOD Designer or FMOD Profiler to connect to it, and view memory, CPU and the DSP network graph in real-time. */ +#define FMOD_INIT_VOL0_BECOMES_VIRTUAL 0x00000080 /* All platforms - Any sounds that are 0 volume will go virtual and not be processed except for having their positions updated virtually. Use System::setAdvancedSettings to adjust what volume besides zero to switch to virtual at. */ +#define FMOD_INIT_WASAPI_EXCLUSIVE 0x00000100 /* Win32 Vista only - for WASAPI output - Enable exclusive access to hardware, lower latency at the expense of excluding other applications from accessing the audio hardware. */ +#define FMOD_INIT_PS3_PREFERDTS 0x00800000 /* PS3 only - Prefer DTS over Dolby Digital if both are supported. Note: 8 and 6 channel LPCM is always preferred over both DTS and Dolby Digital. */ +#define FMOD_INIT_PS3_FORCE2CHLPCM 0x01000000 /* PS3 only - Force PS3 system output mode to 2 channel LPCM. */ +#define FMOD_INIT_DISABLEDOLBY 0x00100000 /* Wii / 3DS - Disable Dolby Pro Logic surround. Speakermode will be set to STEREO even if user has selected surround in the system settings. */ +#define FMOD_INIT_SYSTEM_MUSICMUTENOTPAUSE 0x00200000 /* Xbox 360 / PS3 - The "music" channelgroup which by default pauses when custom 360 dashboard / PS3 BGM music is played, can be changed to mute (therefore continues playing) instead of pausing, by using this flag. */ +#define FMOD_INIT_SYNCMIXERWITHUPDATE 0x00400000 /* Win32/Wii/PS3/Xbox/Xbox 360 - FMOD Mixer thread is woken up to do a mix when System::update is called rather than waking periodically on its own timer. */ +#define FMOD_INIT_GEOMETRY_USECLOSEST 0x04000000 /* All platforms - With the geometry engine, only process the closest polygon rather than accumulating all polygons the sound to listener line intersects. */ +#define FMOD_INIT_DISABLE_MYEARS_AUTODETECT 0x08000000 /* Win32 - Disables automatic setting of FMOD_SPEAKERMODE_STEREO to FMOD_SPEAKERMODE_MYEARS if the MyEars profile exists on the PC. MyEars is HRTF 7.1 downmixing through headphones. */ +#define FMOD_INIT_PS3_DISABLEDTS 0x10000000 /* PS3 only - Disable DTS output mode selection */ +#define FMOD_INIT_PS3_DISABLEDOLBYDIGITAL 0x20000000 /* PS3 only - Disable Dolby Digital output mode selection */ +#define FMOD_INIT_7POINT1_DOLBYMAPPING 0x40000000 /* PS3/PS4 only - FMOD uses the WAVEFORMATEX Microsoft 7.1 speaker mapping where the last 2 pairs of speakers are 'rears' then 'sides', but on PS3/PS4 these are mapped to 'surrounds' and 'backs'. Use this flag to swap fmod's last 2 pair of speakers on PS3/PS4 to avoid needing to do a special case for these platforms. */ +#define FMOD_INIT_ASYNCREAD_FAST 0x80000000 /* All platforms - Rather than setting FMOD_ASYNCREADINFO::result, call FMOD_ASYNCREADINFO::done to enable a semaphore based wait inside fmod, rather than the older method which can incur up to 10ms delay per read. */ +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + These definitions describe the type of song being played. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getFormat +] +*/ +typedef enum +{ + FMOD_SOUND_TYPE_UNKNOWN, /* 3rd party / unknown plugin format. */ + FMOD_SOUND_TYPE_AIFF, /* AIFF. */ + FMOD_SOUND_TYPE_ASF, /* Microsoft Advanced Systems Format (ie WMA/ASF/WMV). */ + FMOD_SOUND_TYPE_AT3, /* Sony ATRAC 3 format */ + FMOD_SOUND_TYPE_CDDA, /* Digital CD audio. */ + FMOD_SOUND_TYPE_DLS, /* Sound font / downloadable sound bank. */ + FMOD_SOUND_TYPE_FLAC, /* FLAC lossless codec. */ + FMOD_SOUND_TYPE_FSB, /* FMOD Sample Bank. */ + FMOD_SOUND_TYPE_GCADPCM, /* Nintendo GameCube/Wii ADPCM */ + FMOD_SOUND_TYPE_IT, /* Impulse Tracker. */ + FMOD_SOUND_TYPE_MIDI, /* MIDI. extracodecdata is a pointer to an FMOD_MIDI_EXTRACODECDATA structure. */ + FMOD_SOUND_TYPE_MOD, /* Protracker / Fasttracker MOD. */ + FMOD_SOUND_TYPE_MPEG, /* MP2/MP3 MPEG. */ + FMOD_SOUND_TYPE_OGGVORBIS, /* Ogg vorbis. */ + FMOD_SOUND_TYPE_PLAYLIST, /* Information only from ASX/PLS/M3U/WAX playlists */ + FMOD_SOUND_TYPE_RAW, /* Raw PCM data. */ + FMOD_SOUND_TYPE_S3M, /* ScreamTracker 3. */ + FMOD_SOUND_TYPE_SF2, /* Sound font 2 format. */ + FMOD_SOUND_TYPE_USER, /* User created sound. */ + FMOD_SOUND_TYPE_WAV, /* Microsoft WAV. */ + FMOD_SOUND_TYPE_XM, /* FastTracker 2 XM. */ + FMOD_SOUND_TYPE_XMA, /* Xbox360 XMA */ + FMOD_SOUND_TYPE_VAG, /* PlayStation Portable ADPCM VAG format. */ + FMOD_SOUND_TYPE_AUDIOQUEUE, /* iPhone hardware decoder, supports AAC, ALAC and MP3. extracodecdata is a pointer to an FMOD_AUDIOQUEUE_EXTRACODECDATA structure. */ + FMOD_SOUND_TYPE_XWMA, /* Xbox360 XWMA */ + FMOD_SOUND_TYPE_BCWAV, /* 3DS BCWAV container format for DSP ADPCM and PCM */ + FMOD_SOUND_TYPE_AT9, /* NGP ATRAC 9 format */ + FMOD_SOUND_TYPE_VORBIS, /* Raw vorbis */ + FMOD_SOUND_TYPE_MEDIA_FOUNDATION,/* Microsoft Media Foundation wrappers, supports ASF/WMA */ + + FMOD_SOUND_TYPE_MAX, /* Maximum number of sound types supported. */ + FMOD_SOUND_TYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SOUND_TYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These definitions describe the native format of the hardware or software buffer that will be used. + + [REMARKS] + This is the format the native hardware or software buffer will be or is created in. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createSound + Sound::getFormat +] +*/ +typedef enum +{ + FMOD_SOUND_FORMAT_NONE, /* Unitialized / unknown. */ + FMOD_SOUND_FORMAT_PCM8, /* 8bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCM16, /* 16bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCM24, /* 24bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCM32, /* 32bit integer PCM data. */ + FMOD_SOUND_FORMAT_PCMFLOAT, /* 32bit floating point PCM data. */ + FMOD_SOUND_FORMAT_GCADPCM, /* Compressed Nintendo 3DS/Wii DSP data. */ + FMOD_SOUND_FORMAT_IMAADPCM, /* Compressed IMA ADPCM data. */ + FMOD_SOUND_FORMAT_VAG, /* Compressed PlayStation Portable ADPCM data. */ + FMOD_SOUND_FORMAT_HEVAG, /* Compressed PSVita ADPCM data. */ + FMOD_SOUND_FORMAT_XMA, /* Compressed Xbox360 XMA data. */ + FMOD_SOUND_FORMAT_MPEG, /* Compressed MPEG layer 2 or 3 data. */ + FMOD_SOUND_FORMAT_CELT, /* Compressed CELT data. */ + FMOD_SOUND_FORMAT_AT9, /* Compressed PSVita ATRAC9 data. */ + FMOD_SOUND_FORMAT_XWMA, /* Compressed Xbox360 xWMA data. */ + FMOD_SOUND_FORMAT_VORBIS, /* Compressed Vorbis data. */ + + FMOD_SOUND_FORMAT_MAX, /* Maximum number of sound formats supported. */ + FMOD_SOUND_FORMAT_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SOUND_FORMAT; + + +/* +[DEFINE] +[ + [NAME] + FMOD_MODE + + [DESCRIPTION] + Sound description bitfields, bitwise OR them together for loading and describing sounds. + + [REMARKS] + By default a sound will open as a static sound that is decompressed fully into memory to PCM. (ie equivalent of FMOD_CREATESAMPLE) + To have a sound stream instead, use FMOD_CREATESTREAM, or use the wrapper function System::createStream. + Some opening modes (ie FMOD_OPENUSER, FMOD_OPENMEMORY, FMOD_OPENMEMORY_POINT, FMOD_OPENRAW) will need extra information. + This can be provided using the FMOD_CREATESOUNDEXINFO structure. + + Specifying FMOD_OPENMEMORY_POINT will POINT to your memory rather allocating its own sound buffers and duplicating it internally. + This means you cannot free the memory while FMOD is using it, until after Sound::release is called. + With FMOD_OPENMEMORY_POINT, for PCM formats, only WAV, FSB, and RAW are supported. For compressed formats, only those formats supported by FMOD_CREATECOMPRESSEDSAMPLE are supported. + With FMOD_OPENMEMORY_POINT and FMOD_OPENRAW or PCM, if using them together, note that you must pad the data on each side by 16 bytes. This is so fmod can modify the ends of the data for looping/interpolation/mixing purposes. If a wav file, you will need to insert silence, and then reset loop points to stop the playback from playing that silence. + With FMOD_OPENMEMORY_POINT, For Wii/PSP FMOD_HARDWARE supports this flag for the GCADPCM/VAG formats. On other platforms FMOD_SOFTWARE must be used. + + Xbox 360 memory On Xbox 360 Specifying FMOD_OPENMEMORY_POINT to a virtual memory address will cause FMOD_ERR_INVALID_ADDRESS + to be returned. Use physical memory only for this functionality. + + FMOD_LOWMEM is used on a sound if you want to minimize the memory overhead, by having FMOD not allocate memory for certain + features that are not likely to be used in a game environment. These are : + 1. Sound::getName functionality is removed. 256 bytes per sound is saved. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createSound + System::createStream + Sound::setMode + Sound::getMode + Channel::setMode + Channel::getMode + Sound::set3DCustomRolloff + Channel::set3DCustomRolloff + Sound::getOpenState +] +*/ +#define FMOD_DEFAULT 0x00000000 /* Default for all modes listed below. FMOD_LOOP_OFF, FMOD_2D, FMOD_HARDWARE */ +#define FMOD_LOOP_OFF 0x00000001 /* For non looping sounds. (DEFAULT). Overrides FMOD_LOOP_NORMAL / FMOD_LOOP_BIDI. */ +#define FMOD_LOOP_NORMAL 0x00000002 /* For forward looping sounds. */ +#define FMOD_LOOP_BIDI 0x00000004 /* For bidirectional looping sounds. (only works on software mixed static sounds). */ +#define FMOD_2D 0x00000008 /* Ignores any 3d processing. (DEFAULT). */ +#define FMOD_3D 0x00000010 /* Makes the sound positionable in 3D. Overrides FMOD_2D. */ +#define FMOD_HARDWARE 0x00000020 /* Attempts to make sounds use hardware acceleration. (DEFAULT). Note on platforms that don't support FMOD_HARDWARE (only 3DS, PS Vita, PSP, Wii and Wii U support FMOD_HARDWARE), this will be internally treated as FMOD_SOFTWARE. */ +#define FMOD_SOFTWARE 0x00000040 /* Makes the sound be mixed by the FMOD CPU based software mixer. Overrides FMOD_HARDWARE. Use this for FFT, DSP, compressed sample support, 2D multi-speaker support and other software related features. */ +#define FMOD_CREATESTREAM 0x00000080 /* Decompress at runtime, streaming from the source provided (ie from disk). Overrides FMOD_CREATESAMPLE and FMOD_CREATECOMPRESSEDSAMPLE. Note a stream can only be played once at a time due to a stream only having 1 stream buffer and file handle. Open multiple streams to have them play concurrently. */ +#define FMOD_CREATESAMPLE 0x00000100 /* Decompress at loadtime, decompressing or decoding whole file into memory as the target sample format (ie PCM). Fastest for FMOD_SOFTWARE based playback and most flexible. */ +#define FMOD_CREATECOMPRESSEDSAMPLE 0x00000200 /* Load MP2/MP3/IMAADPCM/CELT/Vorbis/AT9 or XMA into memory and leave it compressed. CELT/Vorbis/AT9 encoding only supported in the FSB file format. During playback the FMOD software mixer will decode it in realtime as a 'compressed sample'. Can only be used in combination with FMOD_SOFTWARE. Overrides FMOD_CREATESAMPLE. If the sound data is not one of the supported formats, it will behave as if it was created with FMOD_CREATESAMPLE and decode the sound into PCM. */ +#define FMOD_OPENUSER 0x00000400 /* Opens a user created static sample or stream. Use FMOD_CREATESOUNDEXINFO to specify format and/or read callbacks. If a user created 'sample' is created with no read callback, the sample will be empty. Use Sound::lock and Sound::unlock to place sound data into the sound if this is the case. */ +#define FMOD_OPENMEMORY 0x00000800 /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. Use FMOD_CREATESOUNDEXINFO to specify length. If used with FMOD_CREATESAMPLE or FMOD_CREATECOMPRESSEDSAMPLE, FMOD duplicates the memory into its own buffers. Your own buffer can be freed after open. If used with FMOD_CREATESTREAM, FMOD will stream out of the buffer whose pointer you passed in. In this case, your own buffer should not be freed until you have finished with and released the stream.*/ +#define FMOD_OPENMEMORY_POINT 0x10000000 /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. Use FMOD_CREATESOUNDEXINFO to specify length. This differs to FMOD_OPENMEMORY in that it uses the memory as is, without duplicating the memory into its own buffers. For Wii/PSP FMOD_HARDWARE supports this flag for the GCADPCM/VAG formats. On other platforms FMOD_SOFTWARE must be used, as sound hardware on the other platforms (ie PC) cannot access main ram. Cannot be freed after open, only after Sound::release. Will not work if the data is compressed and FMOD_CREATECOMPRESSEDSAMPLE is not used. */ +#define FMOD_OPENRAW 0x00001000 /* Will ignore file format and treat as raw pcm. Use FMOD_CREATESOUNDEXINFO to specify format. Requires at least defaultfrequency, numchannels and format to be specified before it will open. Must be little endian data. */ +#define FMOD_OPENONLY 0x00002000 /* Just open the file, dont prebuffer or read. Good for fast opens for info, or when sound::readData is to be used. */ +#define FMOD_ACCURATETIME 0x00004000 /* For System::createSound - for accurate Sound::getLength/Channel::setPosition on VBR MP3, and MOD/S3M/XM/IT/MIDI files. Scans file first, so takes longer to open. FMOD_OPENONLY does not affect this. */ +#define FMOD_MPEGSEARCH 0x00008000 /* For corrupted / bad MP3 files. This will search all the way through the file until it hits a valid MPEG header. Normally only searches for 4k. */ +#define FMOD_NONBLOCKING 0x00010000 /* For opening sounds and getting streamed subsounds (seeking) asyncronously. Use Sound::getOpenState to poll the state of the sound as it opens or retrieves the subsound in the background. */ +#define FMOD_UNIQUE 0x00020000 /* Unique sound, can only be played one at a time */ +#define FMOD_3D_HEADRELATIVE 0x00040000 /* Make the sound's position, velocity and orientation relative to the listener. */ +#define FMOD_3D_WORLDRELATIVE 0x00080000 /* Make the sound's position, velocity and orientation absolute (relative to the world). (DEFAULT) */ +#define FMOD_3D_INVERSEROLLOFF 0x00100000 /* This sound will follow the inverse rolloff model where mindistance = full volume, maxdistance = where sound stops attenuating, and rolloff is fixed according to the global rolloff factor. (DEFAULT) */ +#define FMOD_3D_LINEARROLLOFF 0x00200000 /* This sound will follow a linear rolloff model where mindistance = full volume, maxdistance = silence. Rolloffscale is ignored. */ +#define FMOD_3D_LINEARSQUAREROLLOFF 0x00400000 /* This sound will follow a linear-square rolloff model where mindistance = full volume, maxdistance = silence. Rolloffscale is ignored. */ +#define FMOD_3D_CUSTOMROLLOFF 0x04000000 /* This sound will follow a rolloff model defined by Sound::set3DCustomRolloff / Channel::set3DCustomRolloff. */ +#define FMOD_3D_IGNOREGEOMETRY 0x40000000 /* Is not affect by geometry occlusion. If not specified in Sound::setMode, or Channel::setMode, the flag is cleared and it is affected by geometry again. */ +#define FMOD_UNICODE 0x01000000 /* Filename is double-byte unicode. */ +#define FMOD_IGNORETAGS 0x02000000 /* Skips id3v2/asf/etc tag checks when opening a sound, to reduce seek/read overhead when opening files (helps with CD performance). */ +#define FMOD_LOWMEM 0x08000000 /* Removes some features from samples to give a lower memory overhead, like Sound::getName. See remarks. */ +#define FMOD_LOADSECONDARYRAM 0x20000000 /* Load sound into the secondary RAM of supported platform. On PS3, sounds will be loaded into RSX/VRAM. */ +#define FMOD_VIRTUAL_PLAYFROMSTART 0x80000000 /* For sounds that start virtual (due to being quiet or low importance), instead of swapping back to audible, and playing at the correct offset according to time, this flag makes the sound play from the start. */ + +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + These values describe what state a sound is in after FMOD_NONBLOCKING has been used to open it. + + [REMARKS] + With streams, if you are using FMOD_NONBLOCKING, note that if the user calls Sound::getSubSound, a stream will go into FMOD_OPENSTATE_SEEKING state and sound related commands will return FMOD_ERR_NOTREADY. + With streams, if you are using FMOD_NONBLOCKING, note that if the user calls Channel::getPosition, a stream will go into FMOD_OPENSTATE_SETPOSITION state and sound related commands will return FMOD_ERR_NOTREADY. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getOpenState + FMOD_MODE +] +*/ +typedef enum +{ + FMOD_OPENSTATE_READY = 0, /* Opened and ready to play. */ + FMOD_OPENSTATE_LOADING, /* Initial load in progress. */ + FMOD_OPENSTATE_ERROR, /* Failed to open - file not found, out of memory etc. See return value of Sound::getOpenState for what happened. */ + FMOD_OPENSTATE_CONNECTING, /* Connecting to remote host (internet sounds only). */ + FMOD_OPENSTATE_BUFFERING, /* Buffering data. */ + FMOD_OPENSTATE_SEEKING, /* Seeking to subsound and re-flushing stream buffer. */ + FMOD_OPENSTATE_PLAYING, /* Ready and playing, but not possible to release at this time without stalling the main thread. */ + FMOD_OPENSTATE_SETPOSITION, /* Seeking within a stream to a different position. */ + + FMOD_OPENSTATE_MAX, /* Maximum number of open state types. */ + FMOD_OPENSTATE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_OPENSTATE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These flags are used with SoundGroup::setMaxAudibleBehavior to determine what happens when more sounds + are played than are specified with SoundGroup::setMaxAudible. + + [REMARKS] + When using FMOD_SOUNDGROUP_BEHAVIOR_MUTE, SoundGroup::setMuteFadeSpeed can be used to stop a sudden transition. + Instead, the time specified will be used to cross fade between the sounds that go silent and the ones that become audible. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + SoundGroup::setMaxAudibleBehavior + SoundGroup::getMaxAudibleBehavior + SoundGroup::setMaxAudible + SoundGroup::getMaxAudible + SoundGroup::setMuteFadeSpeed + SoundGroup::getMuteFadeSpeed +] +*/ +typedef enum +{ + FMOD_SOUNDGROUP_BEHAVIOR_FAIL, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will simply fail during System::playSound. */ + FMOD_SOUNDGROUP_BEHAVIOR_MUTE, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will be silent, then if another sound in the group stops the sound that was silent before becomes audible again. */ + FMOD_SOUNDGROUP_BEHAVIOR_STEALLOWEST, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will steal the quietest / least important sound playing in the group. */ + + FMOD_SOUNDGROUP_BEHAVIOR_MAX, /* Maximum number of open state types. */ + FMOD_SOUNDGROUP_BEHAVIOR_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SOUNDGROUP_BEHAVIOR; + + +/* +[ENUM] +[ + [DESCRIPTION] + These callback types are used with Channel::setCallback. + + [REMARKS] + Each callback has commanddata parameters passed as int unique to the type of callback. + See reference to FMOD_CHANNEL_CALLBACK to determine what they might mean for each type of callback. + + Note! Currently the user must call System::update for these callbacks to trigger! + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Channel::setCallback + FMOD_CHANNEL_CALLBACK + System::update +] +*/ +typedef enum +{ + FMOD_CHANNEL_CALLBACKTYPE_END, /* Called when a sound ends. */ + FMOD_CHANNEL_CALLBACKTYPE_VIRTUALVOICE, /* Called when a voice is swapped out or swapped in. */ + FMOD_CHANNEL_CALLBACKTYPE_SYNCPOINT, /* Called when a syncpoint is encountered. Can be from wav file markers. */ + FMOD_CHANNEL_CALLBACKTYPE_OCCLUSION, /* Called when the channel has its geometry occlusion value calculated. Can be used to clamp or change the value. */ + + FMOD_CHANNEL_CALLBACKTYPE_MAX, /* Maximum number of callback types supported. */ + FMOD_CHANNEL_CALLBACKTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_CHANNEL_CALLBACKTYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + These callback types are used with System::setCallback. + + [REMARKS] + Each callback has commanddata parameters passed as void* unique to the type of callback. + See reference to FMOD_SYSTEM_CALLBACK to determine what they might mean for each type of callback. + + Note! Using FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED (on Mac only) requires the application to be running an event loop which will allow external changes to device list to be detected by FMOD. + + Note! The 'system' object pointer will be null for FMOD_SYSTEM_CALLBACKTYPE_MEMORYALLOCATIONFAILED callback. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setCallback + FMOD_SYSTEM_CALLBACK + System::update + DSP::addInput +] +*/ +typedef enum +{ + FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED, /* Called from System::update when the enumerated list of devices has changed. */ + FMOD_SYSTEM_CALLBACKTYPE_DEVICELOST, /* Called from System::update when an output device has been lost due to control panel parameter changes and FMOD cannot automatically recover. */ + FMOD_SYSTEM_CALLBACKTYPE_MEMORYALLOCATIONFAILED, /* Called directly when a memory allocation fails somewhere in FMOD. (NOTE - 'system' will be NULL in this callback type.)*/ + FMOD_SYSTEM_CALLBACKTYPE_THREADCREATED, /* Called directly when a thread is created. */ + FMOD_SYSTEM_CALLBACKTYPE_BADDSPCONNECTION, /* Called when a bad connection was made with DSP::addInput. Usually called from mixer thread because that is where the connections are made. */ + FMOD_SYSTEM_CALLBACKTYPE_BADDSPLEVEL, /* Called when too many effects were added exceeding the maximum tree depth of 128. This is most likely caused by accidentally adding too many DSP effects. Usually called from mixer thread because that is where the connections are made. */ + FMOD_SYSTEM_CALLBACKTYPE_THREADDESTROYED, /* Called directly when a thread is destroyed. */ + + FMOD_SYSTEM_CALLBACKTYPE_MAX, /* Maximum number of callback types supported. */ + FMOD_SYSTEM_CALLBACKTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_SYSTEM_CALLBACKTYPE; + + +/* + FMOD Callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_SYSTEM_CALLBACK) (FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACKTYPE type, void *commanddata1, void *commanddata2); + +typedef FMOD_RESULT (F_CALLBACK *FMOD_CHANNEL_CALLBACK) (FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *commanddata1, void *commanddata2); + +typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_NONBLOCKCALLBACK)(FMOD_SOUND *sound, FMOD_RESULT result); +typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_PCMREADCALLBACK)(FMOD_SOUND *sound, void *data, unsigned int datalen); +typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_PCMSETPOSCALLBACK)(FMOD_SOUND *sound, int subsound, unsigned int position, FMOD_TIMEUNIT postype); + +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_OPENCALLBACK) (const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_CLOSECALLBACK) (void *handle, void *userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_READCALLBACK) (void *handle, void *buffer, unsigned int sizebytes, unsigned int *bytesread, void *userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_SEEKCALLBACK) (void *handle, unsigned int pos, void *userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_ASYNCREADCALLBACK)(FMOD_ASYNCREADINFO *info, void *userdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_ASYNCCANCELCALLBACK)(void *handle, void *userdata); + +typedef void * (F_CALLBACK *FMOD_MEMORY_ALLOCCALLBACK) (unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr); +typedef void * (F_CALLBACK *FMOD_MEMORY_REALLOCCALLBACK)(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr); +typedef void (F_CALLBACK *FMOD_MEMORY_FREECALLBACK) (void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr); + +typedef float (F_CALLBACK *FMOD_3D_ROLLOFFCALLBACK) (FMOD_CHANNEL *channel, float distance); + + +/* +[ENUM] +[ + [DESCRIPTION] + List of windowing methods used in spectrum analysis to reduce leakage / transient signals intefering with the analysis. + This is a problem with analysis of continuous signals that only have a small portion of the signal sample (the fft window size). + Windowing the signal with a curve or triangle tapers the sides of the fft window to help alleviate this problem. + + [REMARKS] + Cyclic signals such as a sine wave that repeat their cycle in a multiple of the window size do not need windowing. + I.e. If the sine wave repeats every 1024, 512, 256 etc samples and the FMOD fft window is 1024, then the signal would not need windowing. + Not windowing is the same as FMOD_DSP_FFT_WINDOW_RECT, which is the default. + If the cycle of the signal (ie the sine wave) is not a multiple of the window size, it will cause frequency abnormalities, so a different windowing method is needed. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::getSpectrum + Channel::getSpectrum +] +*/ +typedef enum +{ + FMOD_DSP_FFT_WINDOW_RECT, /* w[n] = 1.0 */ + FMOD_DSP_FFT_WINDOW_TRIANGLE, /* w[n] = TRI(2n/N) */ + FMOD_DSP_FFT_WINDOW_HAMMING, /* w[n] = 0.54 - (0.46 * COS(n/N) ) */ + FMOD_DSP_FFT_WINDOW_HANNING, /* w[n] = 0.5 * (1.0 - COS(n/N) ) */ + FMOD_DSP_FFT_WINDOW_BLACKMAN, /* w[n] = 0.42 - (0.5 * COS(n/N) ) + (0.08 * COS(2.0 * n/N) ) */ + FMOD_DSP_FFT_WINDOW_BLACKMANHARRIS, /* w[n] = 0.35875 - (0.48829 * COS(1.0 * n/N)) + (0.14128 * COS(2.0 * n/N)) - (0.01168 * COS(3.0 * n/N)) */ + + FMOD_DSP_FFT_WINDOW_MAX, /* Maximum number of FFT window types supported. */ + FMOD_DSP_FFT_WINDOW_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DSP_FFT_WINDOW; + + +/* +[ENUM] +[ + [DESCRIPTION] + List of interpolation types that the FMOD Ex software mixer supports. + + [REMARKS] + The default resampler type is FMOD_DSP_RESAMPLER_LINEAR. + Use System::setSoftwareFormat to tell FMOD the resampling quality you require for FMOD_SOFTWARE based sounds. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setSoftwareFormat + System::getSoftwareFormat +] +*/ +typedef enum +{ + FMOD_DSP_RESAMPLER_NOINTERP, /* No interpolation. High frequency aliasing hiss will be audible depending on the sample rate of the sound. */ + FMOD_DSP_RESAMPLER_LINEAR, /* Linear interpolation (default method). Fast and good quality, causes very slight lowpass effect on low frequency sounds. */ + FMOD_DSP_RESAMPLER_CUBIC, /* Cubic interpolation. Slower than linear interpolation but better quality. */ + FMOD_DSP_RESAMPLER_SPLINE, /* 5 point spline interpolation. Slowest resampling method but best quality. */ + + FMOD_DSP_RESAMPLER_MAX, /* Maximum number of resample methods supported. */ + FMOD_DSP_RESAMPLER_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DSP_RESAMPLER; + + +/* +[ENUM] +[ + [DESCRIPTION] + List of tag types that could be stored within a sound. These include id3 tags, metadata from netstreams and vorbis/asf data. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getTag +] +*/ +typedef enum +{ + FMOD_TAGTYPE_UNKNOWN = 0, + FMOD_TAGTYPE_ID3V1, + FMOD_TAGTYPE_ID3V2, + FMOD_TAGTYPE_VORBISCOMMENT, + FMOD_TAGTYPE_SHOUTCAST, + FMOD_TAGTYPE_ICECAST, + FMOD_TAGTYPE_ASF, + FMOD_TAGTYPE_MIDI, + FMOD_TAGTYPE_PLAYLIST, + FMOD_TAGTYPE_FMOD, + FMOD_TAGTYPE_USER, + + FMOD_TAGTYPE_MAX, /* Maximum number of tag types supported. */ + FMOD_TAGTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_TAGTYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + List of data types that can be returned by Sound::getTag + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getTag +] +*/ +typedef enum +{ + FMOD_TAGDATATYPE_BINARY = 0, + FMOD_TAGDATATYPE_INT, + FMOD_TAGDATATYPE_FLOAT, + FMOD_TAGDATATYPE_STRING, + FMOD_TAGDATATYPE_STRING_UTF16, + FMOD_TAGDATATYPE_STRING_UTF16BE, + FMOD_TAGDATATYPE_STRING_UTF8, + FMOD_TAGDATATYPE_CDTOC, + + FMOD_TAGDATATYPE_MAX, /* Maximum number of tag datatypes supported. */ + FMOD_TAGDATATYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_TAGDATATYPE; + + +/* +[ENUM] +[ + [DESCRIPTION] + Types of delay that can be used with Channel::setDelay / Channel::getDelay. + + [REMARKS] + If you haven't called Channel::setDelay yet, if you call Channel::getDelay with FMOD_DELAYTYPE_DSPCLOCK_START it will return the + equivalent global DSP clock value to determine when a channel started, so that you can use it for other channels to sync against. + + Use System::getDSPClock to also get the current dspclock time, a base for future calls to Channel::setDelay. + + Use FMOD_64BIT_ADD or FMOD_64BIT_SUB to add a hi/lo combination together and cope with wraparound. + + If FMOD_DELAYTYPE_END_MS is specified, the value is not treated as a 64 bit number, just the delayhi value is used and it is treated as milliseconds. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Channel::setDelay + Channel::getDelay + System::getDSPClock +] +*/ +typedef enum +{ + FMOD_DELAYTYPE_END_MS, /* Delay at the end of the sound in milliseconds. Use delayhi only. Channel::isPlaying will remain true until this delay has passed even though the sound itself has stopped playing.*/ + FMOD_DELAYTYPE_DSPCLOCK_START, /* Time the sound started if Channel::getDelay is used, or if Channel::setDelay is used, the sound will delay playing until this exact tick. */ + FMOD_DELAYTYPE_DSPCLOCK_END, /* Time the sound should end. If this is non-zero, the channel will go silent at this exact tick. */ + FMOD_DELAYTYPE_DSPCLOCK_PAUSE, /* Time the sound should pause. If this is non-zero, the channel will pause at this exact tick. */ + + FMOD_DELAYTYPE_MAX, /* Maximum number of tag datatypes supported. */ + FMOD_DELAYTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DELAYTYPE; + + +#define FMOD_64BIT_ADD(_hi1, _lo1, _hi2, _lo2) _hi1 += ((_hi2) + ((((_lo1) + (_lo2)) < (_lo1)) ? 1 : 0)); (_lo1) += (_lo2); +#define FMOD_64BIT_SUB(_hi1, _lo1, _hi2, _lo2) _hi1 -= ((_hi2) + ((((_lo1) - (_lo2)) > (_lo1)) ? 1 : 0)); (_lo1) -= (_lo2); + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a piece of tag data. + + [REMARKS] + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + Members marked with [w] mean the variable can be written to. The user can set the value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getTag + FMOD_TAGTYPE + FMOD_TAGDATATYPE +] +*/ +typedef struct FMOD_TAG +{ + FMOD_TAGTYPE type; /* [r] The type of this tag. */ + FMOD_TAGDATATYPE datatype; /* [r] The type of data that this tag contains */ + char *name; /* [r] The name of this tag i.e. "TITLE", "ARTIST" etc. */ + void *data; /* [r] Pointer to the tag data - its format is determined by the datatype member */ + unsigned int datalen; /* [r] Length of the data contained in this tag */ + FMOD_BOOL updated; /* [r] True if this tag has been updated since last being accessed with Sound::getTag */ +} FMOD_TAG; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure describing a CD/DVD table of contents + + [REMARKS] + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + Members marked with [w] mean the variable can be written to. The user can set the value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getTag +] +*/ +typedef struct FMOD_CDTOC +{ + int numtracks; /* [r] The number of tracks on the CD */ + int min[100]; /* [r] The start offset of each track in minutes */ + int sec[100]; /* [r] The start offset of each track in seconds */ + int frame[100]; /* [r] The start offset of each track in frames */ +} FMOD_CDTOC; + + +/* +[DEFINE] +[ + [NAME] + FMOD_TIMEUNIT + + [DESCRIPTION] + List of time types that can be returned by Sound::getLength and used with Channel::setPosition or Channel::getPosition. + + [REMARKS] + FMOD_TIMEUNIT_SENTENCE_MS, FMOD_TIMEUNIT_SENTENCE_PCM, FMOD_TIMEUNIT_SENTENCE_PCMBYTES, FMOD_TIMEUNIT_SENTENCE and FMOD_TIMEUNIT_SENTENCE_SUBSOUND are only supported by Channel functions. + Do not combine flags except FMOD_TIMEUNIT_BUFFERED. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Sound::getLength + Channel::setPosition + Channel::getPosition +] +*/ +#define FMOD_TIMEUNIT_MS 0x00000001 /* Milliseconds. */ +#define FMOD_TIMEUNIT_PCM 0x00000002 /* PCM samples, related to milliseconds * samplerate / 1000. */ +#define FMOD_TIMEUNIT_PCMBYTES 0x00000004 /* Bytes, related to PCM samples * channels * datawidth (ie 16bit = 2 bytes). */ +#define FMOD_TIMEUNIT_RAWBYTES 0x00000008 /* Raw file bytes of (compressed) sound data (does not include headers). Only used by Sound::getLength and Channel::getPosition. */ +#define FMOD_TIMEUNIT_PCMFRACTION 0x00000010 /* Fractions of 1 PCM sample. Unsigned int range 0 to 0xFFFFFFFF. Used for sub-sample granularity for DSP purposes. */ +#define FMOD_TIMEUNIT_MODORDER 0x00000100 /* MOD/S3M/XM/IT. Order in a sequenced module format. Use Sound::getFormat to determine the PCM format being decoded to. */ +#define FMOD_TIMEUNIT_MODROW 0x00000200 /* MOD/S3M/XM/IT. Current row in a sequenced module format. Sound::getLength will return the number of rows in the currently playing or seeked to pattern. */ +#define FMOD_TIMEUNIT_MODPATTERN 0x00000400 /* MOD/S3M/XM/IT. Current pattern in a sequenced module format. Sound::getLength will return the number of patterns in the song and Channel::getPosition will return the currently playing pattern. */ +#define FMOD_TIMEUNIT_SENTENCE_MS 0x00010000 /* Currently playing subsound in a sentence time in milliseconds. */ +#define FMOD_TIMEUNIT_SENTENCE_PCM 0x00020000 /* Currently playing subsound in a sentence time in PCM Samples, related to milliseconds * samplerate / 1000. */ +#define FMOD_TIMEUNIT_SENTENCE_PCMBYTES 0x00040000 /* Currently playing subsound in a sentence time in bytes, related to PCM samples * channels * datawidth (ie 16bit = 2 bytes). */ +#define FMOD_TIMEUNIT_SENTENCE 0x00080000 /* Currently playing sentence index according to the channel. */ +#define FMOD_TIMEUNIT_SENTENCE_SUBSOUND 0x00100000 /* Currently playing subsound index in a sentence. */ +#define FMOD_TIMEUNIT_BUFFERED 0x10000000 /* Time value as seen by buffered stream. This is always ahead of audible time, and is only used for processing. */ +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + When creating a multichannel sound, FMOD will pan them to their default speaker locations, for example a 6 channel sound will default to one channel per 5.1 output speaker. + Another example is a stereo sound. It will default to left = front left, right = front right. + + This is for sounds that are not 'default'. For example you might have a sound that is 6 channels but actually made up of 3 stereo pairs, that should all be located in front left, front right only. + + [REMARKS] + For full flexibility of speaker assignments, use Channel::setSpeakerLevels. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_CREATESOUNDEXINFO + Channel::setSpeakerLevels +] +*/ +typedef enum +{ + FMOD_SPEAKERMAPTYPE_DEFAULT, /* This is the default, and just means FMOD decides which speakers it puts the source channels. */ + FMOD_SPEAKERMAPTYPE_ALLMONO, /* This means the sound is made up of all mono sounds. All voices will be panned to the front center by default in this case. */ + FMOD_SPEAKERMAPTYPE_ALLSTEREO, /* This means the sound is made up of all stereo sounds. All voices will be panned to front left and front right alternating every second channel. */ + FMOD_SPEAKERMAPTYPE_51_PROTOOLS /* Map a 5.1 sound to use protools L C R Ls Rs LFE mapping. Will return an error if not a 6 channel sound. */ +} FMOD_SPEAKERMAPTYPE; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Use this structure with System::createSound when more control is needed over loading. + The possible reasons to use this with System::createSound are: + - Loading a file from memory. + - Loading a file from within another larger (possibly wad/pak) file, by giving the loader an offset and length. + - To create a user created / non file based sound. + - To specify a starting subsound to seek to within a multi-sample sounds (ie FSB/DLS/SF2) when created as a stream. + - To specify which subsounds to load for multi-sample sounds (ie FSB/DLS/SF2) so that memory is saved and only a subset is actually loaded/read from disk. + - To specify 'piggyback' read and seek callbacks for capture of sound data as fmod reads and decodes it. Useful for ripping decoded PCM data from sounds as they are loaded / played. + - To specify a MIDI DLS/SF2 sample set file to load when opening a MIDI file. + See below on what members to fill for each of the above types of sound you want to create. + + [REMARKS] + This structure is optional! Specify 0 or NULL in System::createSound if you don't need it! + + Loading a file from memory. + - Create the sound using the FMOD_OPENMEMORY flag. + - Mandatory. Specify 'length' for the size of the memory block in bytes. + - Other flags are optional. + + + Loading a file from within another larger (possibly wad/pak) file, by giving the loader an offset and length. + - Mandatory. Specify 'fileoffset' and 'length'. + - Other flags are optional. + + + To create a user created / non file based sound. + - Create the sound using the FMOD_OPENUSER flag. + - Mandatory. Specify 'defaultfrequency, 'numchannels' and 'format'. + - Other flags are optional. + + + To specify a starting subsound to seek to and flush with, within a multi-sample stream (ie FSB/DLS/SF2). + + - Mandatory. Specify 'initialsubsound'. + + + To specify which subsounds to load for multi-sample sounds (ie FSB/DLS/SF2) so that memory is saved and only a subset is actually loaded/read from disk. + + - Mandatory. Specify 'inclusionlist' and 'inclusionlistnum'. + + + To specify 'piggyback' read and seek callbacks for capture of sound data as fmod reads and decodes it. Useful for ripping decoded PCM data from sounds as they are loaded / played. + + - Mandatory. Specify 'pcmreadcallback' and 'pcmseekcallback'. + + + To specify a MIDI DLS/SF2 sample set file to load when opening a MIDI file. + + - Mandatory. Specify 'dlsname'. + + + Setting the 'decodebuffersize' is for cpu intensive codecs that may be causing stuttering, not file intensive codecs (ie those from CD or netstreams) which are normally + altered with System::setStreamBufferSize. As an example of cpu intensive codecs, an mp3 file will take more cpu to decode than a PCM wav file. + If you have a stuttering effect, then it is using more cpu than the decode buffer playback rate can keep up with. Increasing the decode buffersize will most likely solve this problem. + + + FSB codec. If inclusionlist and numsubsounds are used together, this will trigger a special mode where subsounds are shuffled down to save memory. (useful for large FSB + files where you only want to load 1 sound). There will be no gaps, ie no null subsounds. As an example, if there are 10,000 subsounds and there is an inclusionlist with only 1 entry, + and numsubsounds = 1, then subsound 0 will be that entry, and there will only be the memory allocated for 1 subsound. Previously there would still be 10,000 subsound pointers and other + associated codec entries allocated along with it multiplied by 10,000. + + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + Members marked with [w] mean the variable can be written to. The user can set the value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createSound + System::setStreamBufferSize + FMOD_MODE + FMOD_SOUND_FORMAT + FMOD_SOUND_TYPE + FMOD_SPEAKERMAPTYPE +] +*/ +typedef struct FMOD_CREATESOUNDEXINFO +{ + int cbsize; /* [w] Size of this structure. This is used so the structure can be expanded in the future and still work on older versions of FMOD Ex. */ + unsigned int length; /* [w] Optional. Specify 0 to ignore. Size in bytes of file to load, or sound to create (in this case only if FMOD_OPENUSER is used). Required if loading from memory. If 0 is specified, then it will use the size of the file (unless loading from memory then an error will be returned). */ + unsigned int fileoffset; /* [w] Optional. Specify 0 to ignore. Offset from start of the file to start loading from. This is useful for loading files from inside big data files. */ + int numchannels; /* [w] Optional. Specify 0 to ignore. Number of channels in a sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. */ + int defaultfrequency; /* [w] Optional. Specify 0 to ignore. Default frequency of sound in a sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. Other formats use the frequency determined by the file format. */ + FMOD_SOUND_FORMAT format; /* [w] Optional. Specify 0 or FMOD_SOUND_FORMAT_NONE to ignore. Format of the sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. Other formats use the format determined by the file format. */ + unsigned int decodebuffersize; /* [w] Optional. Specify 0 to ignore. For streams. This determines the size of the double buffer (in PCM samples) that a stream uses. Use this for user created streams if you want to determine the size of the callback buffer passed to you. Specify 0 to use FMOD's default size which is currently equivalent to 400ms of the sound format created/loaded. */ + int initialsubsound; /* [w] Optional. Specify 0 to ignore. In a multi-sample file format such as .FSB/.DLS/.SF2, specify the initial subsound to seek to, only if FMOD_CREATESTREAM is used. */ + int numsubsounds; /* [w] Optional. Specify 0 to ignore or have no subsounds. In a sound created with FMOD_OPENUSER, specify the number of subsounds that are accessable with Sound::getSubSound. If not created with FMOD_OPENUSER, this will limit the number of subsounds loaded within a multi-subsound file. If using FSB, then if FMOD_CREATESOUNDEXINFO::inclusionlist is used, this will shuffle subsounds down so that there are not any gaps. It will mean that the indices of the sounds will be different. */ + int *inclusionlist; /* [w] Optional. Specify 0 to ignore. In a multi-sample format such as .FSB/.DLS/.SF2 it may be desirable to specify only a subset of sounds to be loaded out of the whole file. This is an array of subsound indices to load into memory when created. */ + int inclusionlistnum; /* [w] Optional. Specify 0 to ignore. This is the number of integers contained within the inclusionlist array. */ + FMOD_SOUND_PCMREADCALLBACK pcmreadcallback; /* [w] Optional. Specify 0 to ignore. Callback to 'piggyback' on FMOD's read functions and accept or even write PCM data while FMOD is opening the sound. Used for user sounds created with FMOD_OPENUSER or for capturing decoded data as FMOD reads it. */ + FMOD_SOUND_PCMSETPOSCALLBACK pcmsetposcallback; /* [w] Optional. Specify 0 to ignore. Callback for when the user calls a seeking function such as Channel::setTime or Channel::setPosition within a multi-sample sound, and for when it is opened.*/ + FMOD_SOUND_NONBLOCKCALLBACK nonblockcallback; /* [w] Optional. Specify 0 to ignore. Callback for successful completion, or error while loading a sound that used the FMOD_NONBLOCKING flag. Also called duing seeking, when setPosition is called or a stream is restarted. */ + const char *dlsname; /* [w] Optional. Specify 0 to ignore. Filename for a DLS or SF2 sample set when loading a MIDI file. If not specified, on Windows it will attempt to open /windows/system32/drivers/gm.dls or /windows/system32/drivers/etc/gm.dls, on Mac it will attempt to load /System/Library/Components/CoreAudio.component/Contents/Resources/gs_instruments.dls, otherwise the MIDI will fail to open. Current DLS support is for level 1 of the specification. */ + const char *encryptionkey; /* [w] Optional. Specify 0 to ignore. Key for encrypted FSB file. Without this key an encrypted FSB file will not load. */ + int maxpolyphony; /* [w] Optional. Specify 0 to ignore. For sequenced formats with dynamic channel allocation such as .MID and .IT, this specifies the maximum voice count allowed while playing. .IT defaults to 64. .MID defaults to 32. */ + void *userdata; /* [w] Optional. Specify 0 to ignore. This is user data to be attached to the sound during creation. Access via Sound::getUserData. Note: This is not passed to FMOD_FILE_OPENCALLBACK, that is a different userdata that is file specific. */ + FMOD_SOUND_TYPE suggestedsoundtype; /* [w] Optional. Specify 0 or FMOD_SOUND_TYPE_UNKNOWN to ignore. Instead of scanning all codec types, use this to speed up loading by making it jump straight to this codec. */ + FMOD_FILE_OPENCALLBACK useropen; /* [w] Optional. Specify 0 to ignore. Callback for opening this file. */ + FMOD_FILE_CLOSECALLBACK userclose; /* [w] Optional. Specify 0 to ignore. Callback for closing this file. */ + FMOD_FILE_READCALLBACK userread; /* [w] Optional. Specify 0 to ignore. Callback for reading from this file. */ + FMOD_FILE_SEEKCALLBACK userseek; /* [w] Optional. Specify 0 to ignore. Callback for seeking within this file. */ + FMOD_FILE_ASYNCREADCALLBACK userasyncread; /* [w] Optional. Specify 0 to ignore. Callback for seeking within this file. */ + FMOD_FILE_ASYNCCANCELCALLBACK userasynccancel; /* [w] Optional. Specify 0 to ignore. Callback for seeking within this file. */ + FMOD_SPEAKERMAPTYPE speakermap; /* [w] Optional. Specify 0 to ignore. Use this to differ the way fmod maps multichannel sounds to speakers. See FMOD_SPEAKERMAPTYPE for more. */ + FMOD_SOUNDGROUP *initialsoundgroup; /* [w] Optional. Specify 0 to ignore. Specify a sound group if required, to put sound in as it is created. */ + unsigned int initialseekposition;/* [w] Optional. Specify 0 to ignore. For streams. Specify an initial position to seek the stream to. */ + FMOD_TIMEUNIT initialseekpostype; /* [w] Optional. Specify 0 to ignore. For streams. Specify the time unit for the position set in initialseekposition. */ + int ignoresetfilesystem;/* [w] Optional. Specify 0 to ignore. Set to 1 to use fmod's built in file system. Ignores setFileSystem callbacks and also FMOD_CREATESOUNEXINFO file callbacks. Useful for specific cases where you don't want to use your own file system but want to use fmod's file system (ie net streaming). */ + int cddaforceaspi; /* [w] Optional. Specify 0 to ignore. For CDDA sounds only - if non-zero use ASPI instead of NTSCSI to access the specified CD/DVD device. */ + unsigned int audioqueuepolicy; /* [w] Optional. Specify 0 or FMOD_AUDIOQUEUE_CODECPOLICY_DEFAULT to ignore. Policy used to determine whether hardware or software is used for decoding, see FMOD_AUDIOQUEUE_CODECPOLICY for options (iOS >= 3.0 required, otherwise only hardware is available) */ + unsigned int minmidigranularity; /* [w] Optional. Specify 0 to ignore. Allows you to set a minimum desired MIDI mixer granularity. Values smaller than 512 give greater than default accuracy at the cost of more CPU and vice versa. Specify 0 for default (512 samples). */ + int nonblockthreadid; /* [w] Optional. Specify 0 to ignore. Specifies a thread index to execute non blocking load on. Allows for up to 5 threads to be used for loading at once. This is to avoid one load blocking another. Maximum value = 4. */ +} FMOD_CREATESOUNDEXINFO; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining a reverb environment. + + [REMARKS] + Note the default reverb properties are the same as the FMOD_PRESET_GENERIC preset. + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras float values are always linear. + + The numerical values listed below are the maximum, minimum and default values for each variable respectively. + + SUPPORTED next to each parameter means the platform the parameter can be set on. Some platforms support all parameters and some don't. + WII means Nintendo Wii hardware reverb (must use FMOD_HARDWARE). + PSP means Playstation Portable hardware reverb (must use FMOD_HARDWARE). + SFX means FMOD SFX software reverb. This works on any platform that uses FMOD_SOFTWARE for loading sounds. + --- means unsupported/deprecated. Will either be removed or supported by SFX in the future. + + Nintendo Wii Notes: + This structure supports only limited parameters, and maps them to the Wii hardware reverb as follows. + DecayTime = 'time' + ReverbDelay = 'predelay' + ModulationDepth = 'damping' + Reflections = 'coloration' + EnvDiffusion = 'crosstalk' + Room = 'mix' + + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + Members marked with [w] mean the variable can be written to. The user can set the value. + Members marked with [r/w] are either read or write depending on if you are using System::setReverbProperties (w) or System::getReverbProperties (r). + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setReverbProperties + System::getReverbProperties + FMOD_REVERB_PRESETS + FMOD_REVERB_FLAGS +] +*/ +typedef struct FMOD_REVERB_PROPERTIES +{ /* MIN MAX DEFAULT DESCRIPTION */ + int Instance; /* [w] 0 3 0 Environment Instance. (SUPPORTED:SFX(4 instances) and Wii (3 instances)) */ + int Environment; /* [r/w] -1 25 -1 Sets all listener properties. -1 = OFF. (SUPPORTED:SFX(-1 only)/PSP) */ + float EnvDiffusion; /* [r/w] 0.0 1.0 1.0 Environment diffusion (SUPPORTED:WII) */ + int Room; /* [r/w] -10000 0 -1000 Room effect level (at mid frequencies) (SUPPORTED:SFX/WII/PSP) */ + int RoomHF; /* [r/w] -10000 0 -100 Relative room effect level at high frequencies (SUPPORTED:SFX) */ + int RoomLF; /* [r/w] -10000 0 0 Relative room effect level at low frequencies (SUPPORTED:SFX) */ + float DecayTime; /* [r/w] 0.1 20.0 1.49 Reverberation decay time at mid frequencies (SUPPORTED:SFX/WII) */ + float DecayHFRatio; /* [r/w] 0.1 2.0 0.83 High-frequency to mid-frequency decay time ratio (SUPPORTED:SFX) */ + float DecayLFRatio; /* [r/w] 0.1 2.0 1.0 Low-frequency to mid-frequency decay time ratio (SUPPORTED:---) */ + int Reflections; /* [r/w] -10000 1000 -2602 Early reflections level relative to room effect (SUPPORTED:SFX/WII) */ + float ReflectionsDelay; /* [r/w] 0.0 0.3 0.007 Initial reflection delay time (SUPPORTED:SFX) */ + int Reverb; /* [r/w] -10000 2000 200 Late reverberation level relative to room effect (SUPPORTED:SFX) */ + float ReverbDelay; /* [r/w] 0.0 0.1 0.011 Late reverberation delay time relative to initial reflection (SUPPORTED:SFX/WII) */ + float ModulationTime; /* [r/w] 0.04 4.0 0.25 Modulation time (SUPPORTED:---) */ + float ModulationDepth; /* [r/w] 0.0 1.0 0.0 Modulation depth (SUPPORTED:WII) */ + float HFReference; /* [r/w] 20.0 20000.0 5000.0 Reference high frequency (hz) (SUPPORTED:SFX) */ + float LFReference; /* [r/w] 20.0 1000.0 250.0 Reference low frequency (hz) (SUPPORTED:SFX) */ + float Diffusion; /* [r/w] 0.0 100.0 100.0 Value that controls the echo density in the late reverberation decay. (SUPPORTED:SFX) */ + float Density; /* [r/w] 0.0 100.0 100.0 Value that controls the modal density in the late reverberation decay (SUPPORTED:SFX) */ + unsigned int Flags; /* [r/w] FMOD_REVERB_FLAGS - modifies the behavior of above properties (SUPPORTED:WII) */ +} FMOD_REVERB_PROPERTIES; + + +/* +[DEFINE] +[ + [NAME] + FMOD_REVERB_FLAGS + + [DESCRIPTION] + Values for the Flags member of the FMOD_REVERB_PROPERTIES structure. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_REVERB_PROPERTIES +] +*/ +#define FMOD_REVERB_FLAGS_HIGHQUALITYREVERB 0x00000400 /* Wii. Use high quality reverb */ +#define FMOD_REVERB_FLAGS_HIGHQUALITYDPL2REVERB 0x00000800 /* Wii. Use high quality DPL2 reverb */ +#define FMOD_REVERB_FLAGS_HARDWAREONLY 0x00001000 /* Don't create an SFX reverb for FMOD_SOFTWARE channels, hardware reverb only */ +#define FMOD_REVERB_FLAGS_DEFAULT 0x00000000 +/* [DEFINE_END] */ + + +/* +[DEFINE] +[ + [NAME] + FMOD_REVERB_PRESETS + + [DESCRIPTION] + A set of predefined environment PARAMETERS. + These are used to initialize an FMOD_REVERB_PROPERTIES structure statically. + i.e. + FMOD_REVERB_PROPERTIES prop = FMOD_PRESET_GENERIC; + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setReverbProperties +] +*/ +/* Inst Env Diffus Room RoomHF RmLF DecTm DecHF DecLF Refl RefDel Revb RevDel ModTm ModDp HFRef LFRef Diffus Densty FLAGS */ +#define FMOD_PRESET_OFF { 0, -1, 1.00f, -10000, -10000, 0, 1.00f, 1.00f, 1.0f, -2602, 0.007f, 200, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 0.0f, 0.0f, 0x33f } +#define FMOD_PRESET_GENERIC { 0, 0, 1.00f, -1000, -100, 0, 1.49f, 0.83f, 1.0f, -2602, 0.007f, 200, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_PADDEDCELL { 0, 1, 1.00f, -1000, -6000, 0, 0.17f, 0.10f, 1.0f, -1204, 0.001f, 207, 0.002f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_ROOM { 0, 2, 1.00f, -1000, -454, 0, 0.40f, 0.83f, 1.0f, -1646, 0.002f, 53, 0.003f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_BATHROOM { 0, 3, 1.00f, -1000, -1200, 0, 1.49f, 0.54f, 1.0f, -370, 0.007f, 1030, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 60.0f, 0x3f } +#define FMOD_PRESET_LIVINGROOM { 0, 4, 1.00f, -1000, -6000, 0, 0.50f, 0.10f, 1.0f, -1376, 0.003f, -1104, 0.004f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_STONEROOM { 0, 5, 1.00f, -1000, -300, 0, 2.31f, 0.64f, 1.0f, -711, 0.012f, 83, 0.017f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_AUDITORIUM { 0, 6, 1.00f, -1000, -476, 0, 4.32f, 0.59f, 1.0f, -789, 0.020f, -289, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CONCERTHALL { 0, 7, 1.00f, -1000, -500, 0, 3.92f, 0.70f, 1.0f, -1230, 0.020f, -2, 0.029f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CAVE { 0, 8, 1.00f, -1000, 0, 0, 2.91f, 1.30f, 1.0f, -602, 0.015f, -302, 0.022f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x1f } +#define FMOD_PRESET_ARENA { 0, 9, 1.00f, -1000, -698, 0, 7.24f, 0.33f, 1.0f, -1166, 0.020f, 16, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_HANGAR { 0, 10, 1.00f, -1000, -1000, 0, 10.05f, 0.23f, 1.0f, -602, 0.020f, 198, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CARPETTEDHALLWAY { 0, 11, 1.00f, -1000, -4000, 0, 0.30f, 0.10f, 1.0f, -1831, 0.002f, -1630, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_HALLWAY { 0, 12, 1.00f, -1000, -300, 0, 1.49f, 0.59f, 1.0f, -1219, 0.007f, 441, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_STONECORRIDOR { 0, 13, 1.00f, -1000, -237, 0, 2.70f, 0.79f, 1.0f, -1214, 0.013f, 395, 0.020f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_ALLEY { 0, 14, 0.30f, -1000, -270, 0, 1.49f, 0.86f, 1.0f, -1204, 0.007f, -4, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_FOREST { 0, 15, 0.30f, -1000, -3300, 0, 1.49f, 0.54f, 1.0f, -2560, 0.162f, -229, 0.088f, 0.25f, 0.000f, 5000.0f, 250.0f, 79.0f, 100.0f, 0x3f } +#define FMOD_PRESET_CITY { 0, 16, 0.50f, -1000, -800, 0, 1.49f, 0.67f, 1.0f, -2273, 0.007f, -1691, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 50.0f, 100.0f, 0x3f } +#define FMOD_PRESET_MOUNTAINS { 0, 17, 0.27f, -1000, -2500, 0, 1.49f, 0.21f, 1.0f, -2780, 0.300f, -1434, 0.100f, 0.25f, 0.000f, 5000.0f, 250.0f, 27.0f, 100.0f, 0x1f } +#define FMOD_PRESET_QUARRY { 0, 18, 1.00f, -1000, -1000, 0, 1.49f, 0.83f, 1.0f, -10000, 0.061f, 500, 0.025f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } +#define FMOD_PRESET_PLAIN { 0, 19, 0.21f, -1000, -2000, 0, 1.49f, 0.50f, 1.0f, -2466, 0.179f, -1926, 0.100f, 0.25f, 0.000f, 5000.0f, 250.0f, 21.0f, 100.0f, 0x3f } +#define FMOD_PRESET_PARKINGLOT { 0, 20, 1.00f, -1000, 0, 0, 1.65f, 1.50f, 1.0f, -1363, 0.008f, -1153, 0.012f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x1f } +#define FMOD_PRESET_SEWERPIPE { 0, 21, 0.80f, -1000, -1000, 0, 2.81f, 0.14f, 1.0f, 429, 0.014f, 1023, 0.021f, 0.25f, 0.000f, 5000.0f, 250.0f, 80.0f, 60.0f, 0x3f } +#define FMOD_PRESET_UNDERWATER { 0, 22, 1.00f, -1000, -4000, 0, 1.49f, 0.10f, 1.0f, -449, 0.007f, 1700, 0.011f, 1.18f, 0.348f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } + +/* PlayStation Portable Only presets */ +#define FMOD_PRESET_PSP_ROOM { 0, 1, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_STUDIO_A { 0, 2, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_STUDIO_B { 0, 3, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_STUDIO_C { 0, 4, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_HALL { 0, 5, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_SPACE { 0, 6, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_ECHO { 0, 7, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_DELAY { 0, 8, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FMOD_PRESET_PSP_PIPE { 0, 9, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } +/* [DEFINE_END] */ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining the properties for a reverb source, related to a FMOD channel. + + Note the default reverb properties are the same as the FMOD_PRESET_GENERIC preset. + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear. + PORTABILITY: Each member has the platform it supports in braces ie (win32/wii). + + The numerical values listed below are the maximum, minimum and default values for each variable respectively. + + [REMARKS] + SUPPORTED next to each parameter means the platform the parameter can be set on. Some platforms support all parameters and some don't. + WII means Nintendo Wii hardware reverb (must use FMOD_HARDWARE). + PSP means Playstation Portable hardware reverb (must use FMOD_HARDWARE). + SFX means FMOD SFX software reverb. This works on any platform that uses FMOD_SOFTWARE for loading sounds. + --- means unsupported/deprecated. Will either be removed or supported by SFX in the future. + + + 'ConnectionPoint' Parameter. This parameter is for the FMOD software reverb only (known as SFX in the list above). + By default the dsp network connection for a channel and its reverb is between the 'SFX Reverb' unit, and the channel's wavetable/resampler/dspcodec/oscillator unit (the unit below the channel DSP head). NULL can be used for this parameter to make it use this default behaviour. + This parameter allows the user to connect the SFX reverb to somewhere else internally, for example the channel DSP head, or a related channelgroup. The event system uses this so that it can have the output of an event going to the reverb, instead of just the output of the event's channels (thereby ignoring event effects/submixes etc). + Do not use if you are unaware of DSP network connection issues. Leave it at the default of NULL instead. + + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + Members marked with [w] mean the variable can be written to. The user can set the value. + Members marked with [r/w] are either read or write depending on if you are using Channel::setReverbProperties (w) or Channel::getReverbProperties (r). + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + Channel::setReverbProperties + Channel::getReverbProperties + FMOD_REVERB_CHANNELFLAGS +] +*/ +typedef struct FMOD_REVERB_CHANNELPROPERTIES +{ /* MIN MAX DEFAULT DESCRIPTION */ + int Direct; /* [r/w] -10000 1000 0 Direct path level (SUPPORTED:SFX) */ + int Room; /* [r/w] -10000 1000 0 Room effect level (SUPPORTED:SFX) */ + unsigned int Flags; /* [r/w] FMOD_REVERB_CHANNELFLAGS - modifies the behavior of properties (SUPPORTED:SFX) */ + FMOD_DSP *ConnectionPoint; /* [r/w] See remarks. DSP network location to connect reverb for this channel. (SUPPORTED:SFX).*/ +} FMOD_REVERB_CHANNELPROPERTIES; + + +/* +[DEFINE] +[ + [NAME] + FMOD_REVERB_CHANNELFLAGS + + [DESCRIPTION] + Values for the Flags member of the FMOD_REVERB_CHANNELPROPERTIES structure. + + [REMARKS] + For SFX Reverb, there is support for multiple reverb environments. + Use FMOD_REVERB_CHANNELFLAGS_ENVIRONMENT0 to FMOD_REVERB_CHANNELFLAGS_ENVIRONMENT3 in the flags member + of FMOD_REVERB_CHANNELPROPERTIES to specify which environment instance(s) to target. + - If you do not specify any instance the first reverb instance will be used. + - If you specify more than one instance with getReverbProperties, the first instance will be used. + - If you specify more than one instance with setReverbProperties, it will set more than 1 instance at once. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_REVERB_CHANNELPROPERTIES +] +*/ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE0 0x00000010 /* SFX/Wii. Specify channel to target reverb instance 0. Default target. */ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE1 0x00000020 /* SFX/Wii. Specify channel to target reverb instance 1. */ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE2 0x00000040 /* SFX/Wii. Specify channel to target reverb instance 2. */ +#define FMOD_REVERB_CHANNELFLAGS_INSTANCE3 0x00000080 /* SFX. Specify channel to target reverb instance 3. */ + +#define FMOD_REVERB_CHANNELFLAGS_DEFAULT FMOD_REVERB_CHANNELFLAGS_INSTANCE0 +/* [DEFINE_END] */ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Settings for advanced features like configuring memory and cpu usage for the FMOD_CREATECOMPRESSEDSAMPLE feature. + + [REMARKS] + maxMPEGcodecs / maxADPCMcodecs / maxXMAcodecs will determine the maximum cpu usage of playing realtime samples. Use this to lower potential excess cpu usage and also control memory usage. + + maxPCMcodecs is for use with PS3 only. It will determine the maximum number of PCM voices that can be played at once. This includes streams of any format and all sounds created + *without* the FMOD_CREATECOMPRESSEDSAMPLE flag. + + Memory will be allocated for codecs 'up front' (during System::init) if these values are specified as non zero. If any are zero, it allocates memory for the codec whenever a file of the type in question is loaded. So if maxMPEGcodecs is 0 for example, it will allocate memory for the mpeg codecs the first time an mp3 is loaded or an mp3 based .FSB file is loaded. + + Due to inefficient encoding techniques on certain .wav based ADPCM files, FMOD can can need an extra 29720 bytes per codec. This means for lowest memory consumption. Use FSB as it uses an optimal/small ADPCM block size. + + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + Members marked with [w] mean the variable can be written to. The user can set the value. + Members marked with [r/w] are either read or write depending on if you are using System::setAdvancedSettings (w) or System::getAdvancedSettings (r). + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::setAdvancedSettings + System::getAdvancedSettings + System::init + FMOD_MODE +] +*/ +typedef struct FMOD_ADVANCEDSETTINGS +{ + int cbsize; /* [w] Size of this structure. Use sizeof(FMOD_ADVANCEDSETTINGS) NOTE: This must be set before calling System::getAdvancedSettings! */ + int maxMPEGcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. Mpeg codecs consume 21,684 bytes per instance and this number will determine how many mpeg channels can be played simultaneously. Default = 32. */ + int maxADPCMcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. ADPCM codecs consume 2,136 bytes per instance and this number will determine how many ADPCM channels can be played simultaneously. Default = 32. */ + int maxXMAcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. XMA codecs consume 14,836 bytes per instance and this number will determine how many XMA channels can be played simultaneously. Default = 32. */ + int maxCELTcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. CELT codecs consume 11,500 bytes per instance and this number will determine how many CELT channels can be played simultaneously. Default = 32. */ + int maxVORBIScodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. Vorbis codecs consume 12,000 bytes per instance and this number will determine how many Vorbis channels can be played simultaneously. Default = 32. */ + int maxAT9Codecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. AT9 codecs consume 8,720 bytes per instance and this number will determine how many AT9 channels can be played simultaneously. Default = 32. */ + int maxPCMcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with PS3 only. PCM codecs consume 12,672 bytes per instance and this number will determine how many streams and PCM voices can be played simultaneously. Default = 16. */ + int ASIONumChannels; /* [r/w] Optional. Specify 0 to ignore. Number of channels available on the ASIO device. */ + char **ASIOChannelList; /* [r/w] Optional. Specify 0 to ignore. Pointer to an array of strings (number of entries defined by ASIONumChannels) with ASIO channel names. */ + FMOD_SPEAKER *ASIOSpeakerList; /* [r/w] Optional. Specify 0 to ignore. Pointer to a list of speakers that the ASIO channels map to. This can be called after System::init to remap ASIO output. */ + int max3DReverbDSPs; /* [r/w] Optional. Specify 0 to ignore. The max number of 3d reverb DSP's in the system. (NOTE: CURRENTLY DISABLED / UNUSED) */ + float HRTFMinAngle; /* [r/w] Optional. For use with FMOD_INIT_HRTF_LOWPASS. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function begins to have an effect. 0 = in front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 180.0. */ + float HRTFMaxAngle; /* [r/w] Optional. For use with FMOD_INIT_HRTF_LOWPASS. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function has maximum effect. 0 = front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 360.0. */ + float HRTFFreq; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_HRTF_LOWPASS. The cutoff frequency of the HRTF's lowpass filter function when at maximum effect. (i.e. at HRTFMaxAngle). Default = 4000.0. */ + float vol0virtualvol; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_VOL0_BECOMES_VIRTUAL. If this flag is used, and the volume is 0.0, then the sound will become virtual. Use this value to raise the threshold to a different point where a sound goes virtual. */ + int eventqueuesize; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD Event system only. Specifies the number of slots available for simultaneous non blocking loads, across all threads. Default = 32. */ + unsigned int defaultDecodeBufferSize; /* [r/w] Optional. Specify 0 to ignore. For streams. This determines the default size of the double buffer (in milliseconds) that a stream uses. Default = 400ms */ + char *debugLogFilename; /* [r/w] Optional. Specify 0 to ignore. Gives fmod's logging system a path/filename. Normally the log is placed in the same directory as the executable and called fmod.log. When using System::getAdvancedSettings, provide at least 256 bytes of memory to copy into. */ + unsigned short profileport; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_ENABLE_PROFILE. Specify the port to listen on for connections by the profiler application. */ + unsigned int geometryMaxFadeTime; /* [r/w] Optional. Specify 0 to ignore. The maximum time in miliseconds it takes for a channel to fade to the new level when its occlusion changes. */ + unsigned int maxSpectrumWaveDataBuffers; /* [r/w] Optional. Specify 0 to ignore. Tells System::init to allocate a pool of wavedata/spectrum buffers to prevent memory fragmentation, any additional buffers will be allocated normally. */ + unsigned int musicSystemCacheDelay; /* [r/w] Optional. Specify 0 to ignore. The delay the music system should allow for loading a sample from disk (in milliseconds). Default = 400 ms. */ + float distanceFilterCenterFreq; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_DISTANCE_FILTERING. The default center frequency in Hz for the distance filtering effect. Default = 1500.0. */ + unsigned int stackSizeStream; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD Stream thread in bytes. Useful for custom codecs that use excess stack. Default 49,152 (48kb) */ + unsigned int stackSizeNonBlocking; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD_NONBLOCKING loading thread. Useful for custom codecs that use excess stack. Default 65,536 (64kb) */ + unsigned int stackSizeMixer; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD mixer thread. Useful for custom dsps that use excess stack. Default 49,152 (48kb) */ +} FMOD_ADVANCEDSETTINGS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Special channel index values for FMOD functions. + + [REMARKS] + To get 'all' of the channels, use System::getMasterChannelGroup. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::playSound + System::playDSP + System::getChannel + System::getMasterChannelGroup +] +*/ +typedef enum +{ + FMOD_CHANNEL_FREE = -1, /* For a channel index, FMOD chooses a free voice using the priority system. */ + FMOD_CHANNEL_REUSE = -2 /* For a channel index, re-use the channel handle that was passed in. */ +} FMOD_CHANNELINDEX; + +#include "fmod_codec.h" +#include "fmod_dsp.h" +#include "fmod_memoryinfo.h" + +/* ========================================================================================== */ +/* FUNCTION PROTOTYPES */ +/* ========================================================================================== */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + FMOD global system functions (optional). +*/ + +FMOD_RESULT F_API FMOD_Memory_Initialize (void *poolmem, int poollen, FMOD_MEMORY_ALLOCCALLBACK useralloc, FMOD_MEMORY_REALLOCCALLBACK userrealloc, FMOD_MEMORY_FREECALLBACK userfree, FMOD_MEMORY_TYPE memtypeflags); +FMOD_RESULT F_API FMOD_Memory_GetStats (int *currentalloced, int *maxalloced, FMOD_BOOL blocking); +FMOD_RESULT F_API FMOD_Debug_SetLevel (FMOD_DEBUGLEVEL level); +FMOD_RESULT F_API FMOD_Debug_GetLevel (FMOD_DEBUGLEVEL *level); +FMOD_RESULT F_API FMOD_File_SetDiskBusy (int busy); +FMOD_RESULT F_API FMOD_File_GetDiskBusy (int *busy); + +/* + FMOD System factory functions. Use this to create an FMOD System Instance. below you will see FMOD_System_Init/Close to get started. +*/ + +FMOD_RESULT F_API FMOD_System_Create (FMOD_SYSTEM **system); +FMOD_RESULT F_API FMOD_System_Release (FMOD_SYSTEM *system); + + +/* + 'System' API +*/ + +/* + Pre-init functions. +*/ + +FMOD_RESULT F_API FMOD_System_SetOutput (FMOD_SYSTEM *system, FMOD_OUTPUTTYPE output); +FMOD_RESULT F_API FMOD_System_GetOutput (FMOD_SYSTEM *system, FMOD_OUTPUTTYPE *output); +FMOD_RESULT F_API FMOD_System_GetNumDrivers (FMOD_SYSTEM *system, int *numdrivers); +FMOD_RESULT F_API FMOD_System_GetDriverInfo (FMOD_SYSTEM *system, int id, char *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetDriverInfoW (FMOD_SYSTEM *system, int id, short *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetDriverCaps (FMOD_SYSTEM *system, int id, FMOD_CAPS *caps, int *controlpaneloutputrate, FMOD_SPEAKERMODE *controlpanelspeakermode); +FMOD_RESULT F_API FMOD_System_SetDriver (FMOD_SYSTEM *system, int driver); +FMOD_RESULT F_API FMOD_System_GetDriver (FMOD_SYSTEM *system, int *driver); +FMOD_RESULT F_API FMOD_System_SetHardwareChannels (FMOD_SYSTEM *system, int numhardwarechannels); +FMOD_RESULT F_API FMOD_System_SetSoftwareChannels (FMOD_SYSTEM *system, int numsoftwarechannels); +FMOD_RESULT F_API FMOD_System_GetSoftwareChannels (FMOD_SYSTEM *system, int *numsoftwarechannels); +FMOD_RESULT F_API FMOD_System_SetSoftwareFormat (FMOD_SYSTEM *system, int samplerate, FMOD_SOUND_FORMAT format, int numoutputchannels, int maxinputchannels, FMOD_DSP_RESAMPLER resamplemethod); +FMOD_RESULT F_API FMOD_System_GetSoftwareFormat (FMOD_SYSTEM *system, int *samplerate, FMOD_SOUND_FORMAT *format, int *numoutputchannels, int *maxinputchannels, FMOD_DSP_RESAMPLER *resamplemethod, int *bits); +FMOD_RESULT F_API FMOD_System_SetDSPBufferSize (FMOD_SYSTEM *system, unsigned int bufferlength, int numbuffers); +FMOD_RESULT F_API FMOD_System_GetDSPBufferSize (FMOD_SYSTEM *system, unsigned int *bufferlength, int *numbuffers); +FMOD_RESULT F_API FMOD_System_SetFileSystem (FMOD_SYSTEM *system, FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek, FMOD_FILE_ASYNCREADCALLBACK userasyncread, FMOD_FILE_ASYNCCANCELCALLBACK userasynccancel, int blockalign); +FMOD_RESULT F_API FMOD_System_AttachFileSystem (FMOD_SYSTEM *system, FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek); +FMOD_RESULT F_API FMOD_System_SetAdvancedSettings (FMOD_SYSTEM *system, FMOD_ADVANCEDSETTINGS *settings); +FMOD_RESULT F_API FMOD_System_GetAdvancedSettings (FMOD_SYSTEM *system, FMOD_ADVANCEDSETTINGS *settings); +FMOD_RESULT F_API FMOD_System_SetSpeakerMode (FMOD_SYSTEM *system, FMOD_SPEAKERMODE speakermode); +FMOD_RESULT F_API FMOD_System_GetSpeakerMode (FMOD_SYSTEM *system, FMOD_SPEAKERMODE *speakermode); +FMOD_RESULT F_API FMOD_System_SetCallback (FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK callback); + +/* + Plug-in support +*/ + +FMOD_RESULT F_API FMOD_System_SetPluginPath (FMOD_SYSTEM *system, const char *path); +FMOD_RESULT F_API FMOD_System_LoadPlugin (FMOD_SYSTEM *system, const char *filename, unsigned int *handle, unsigned int priority); +FMOD_RESULT F_API FMOD_System_UnloadPlugin (FMOD_SYSTEM *system, unsigned int handle); +FMOD_RESULT F_API FMOD_System_GetNumPlugins (FMOD_SYSTEM *system, FMOD_PLUGINTYPE plugintype, int *numplugins); +FMOD_RESULT F_API FMOD_System_GetPluginHandle (FMOD_SYSTEM *system, FMOD_PLUGINTYPE plugintype, int index, unsigned int *handle); +FMOD_RESULT F_API FMOD_System_GetPluginInfo (FMOD_SYSTEM *system, unsigned int handle, FMOD_PLUGINTYPE *plugintype, char *name, int namelen, unsigned int *version); +FMOD_RESULT F_API FMOD_System_SetOutputByPlugin (FMOD_SYSTEM *system, unsigned int handle); +FMOD_RESULT F_API FMOD_System_GetOutputByPlugin (FMOD_SYSTEM *system, unsigned int *handle); +FMOD_RESULT F_API FMOD_System_CreateDSPByPlugin (FMOD_SYSTEM *system, unsigned int handle, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_RegisterCodec (FMOD_SYSTEM *system, FMOD_CODEC_DESCRIPTION *description, unsigned int *handle, unsigned int priority); +FMOD_RESULT F_API FMOD_System_RegisterDSP (FMOD_SYSTEM *system, FMOD_DSP_DESCRIPTION *description, unsigned int *handle); + +/* + Init/Close +*/ + +FMOD_RESULT F_API FMOD_System_Init (FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata); +FMOD_RESULT F_API FMOD_System_Close (FMOD_SYSTEM *system); + +/* + General post-init system functions +*/ + +FMOD_RESULT F_API FMOD_System_Update (FMOD_SYSTEM *system); + +FMOD_RESULT F_API FMOD_System_Set3DSettings (FMOD_SYSTEM *system, float dopplerscale, float distancefactor, float rolloffscale); +FMOD_RESULT F_API FMOD_System_Get3DSettings (FMOD_SYSTEM *system, float *dopplerscale, float *distancefactor, float *rolloffscale); +FMOD_RESULT F_API FMOD_System_Set3DNumListeners (FMOD_SYSTEM *system, int numlisteners); +FMOD_RESULT F_API FMOD_System_Get3DNumListeners (FMOD_SYSTEM *system, int *numlisteners); +FMOD_RESULT F_API FMOD_System_Set3DListenerAttributes(FMOD_SYSTEM *system, int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_System_Get3DListenerAttributes(FMOD_SYSTEM *system, int listener, FMOD_VECTOR *pos, FMOD_VECTOR *vel, FMOD_VECTOR *forward, FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_System_Set3DRolloffCallback (FMOD_SYSTEM *system, FMOD_3D_ROLLOFFCALLBACK callback); +FMOD_RESULT F_API FMOD_System_Set3DSpeakerPosition (FMOD_SYSTEM *system, FMOD_SPEAKER speaker, float x, float y, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_System_Get3DSpeakerPosition (FMOD_SYSTEM *system, FMOD_SPEAKER speaker, float *x, float *y, FMOD_BOOL *active); + +FMOD_RESULT F_API FMOD_System_SetStreamBufferSize (FMOD_SYSTEM *system, unsigned int filebuffersize, FMOD_TIMEUNIT filebuffersizetype); +FMOD_RESULT F_API FMOD_System_GetStreamBufferSize (FMOD_SYSTEM *system, unsigned int *filebuffersize, FMOD_TIMEUNIT *filebuffersizetype); + +/* + System information functions. +*/ + +FMOD_RESULT F_API FMOD_System_GetVersion (FMOD_SYSTEM *system, unsigned int *version); +FMOD_RESULT F_API FMOD_System_GetOutputHandle (FMOD_SYSTEM *system, void **handle); +FMOD_RESULT F_API FMOD_System_GetChannelsPlaying (FMOD_SYSTEM *system, int *channels); +FMOD_RESULT F_API FMOD_System_GetHardwareChannels (FMOD_SYSTEM *system, int *numhardwarechannels); +FMOD_RESULT F_API FMOD_System_GetCPUUsage (FMOD_SYSTEM *system, float *dsp, float *stream, float *geometry, float *update, float *total); +FMOD_RESULT F_API FMOD_System_GetSoundRAM (FMOD_SYSTEM *system, int *currentalloced, int *maxalloced, int *total); +FMOD_RESULT F_API FMOD_System_GetNumCDROMDrives (FMOD_SYSTEM *system, int *numdrives); +FMOD_RESULT F_API FMOD_System_GetCDROMDriveName (FMOD_SYSTEM *system, int drive, char *drivename, int drivenamelen, char *scsiname, int scsinamelen, char *devicename, int devicenamelen); +FMOD_RESULT F_API FMOD_System_GetSpectrum (FMOD_SYSTEM *system, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); +FMOD_RESULT F_API FMOD_System_GetWaveData (FMOD_SYSTEM *system, float *wavearray, int numvalues, int channeloffset); + +/* + Sound/DSP/Channel/FX creation and retrieval. +*/ + +FMOD_RESULT F_API FMOD_System_CreateSound (FMOD_SYSTEM *system, const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_System_CreateStream (FMOD_SYSTEM *system, const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_System_CreateDSP (FMOD_SYSTEM *system, FMOD_DSP_DESCRIPTION *description, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_CreateDSPByType (FMOD_SYSTEM *system, FMOD_DSP_TYPE type, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_CreateChannelGroup (FMOD_SYSTEM *system, const char *name, FMOD_CHANNELGROUP **channelgroup); +FMOD_RESULT F_API FMOD_System_CreateSoundGroup (FMOD_SYSTEM *system, const char *name, FMOD_SOUNDGROUP **soundgroup); +FMOD_RESULT F_API FMOD_System_CreateReverb (FMOD_SYSTEM *system, FMOD_REVERB **reverb); + +FMOD_RESULT F_API FMOD_System_PlaySound (FMOD_SYSTEM *system, FMOD_CHANNELINDEX channelid, FMOD_SOUND *sound, FMOD_BOOL paused, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_System_PlayDSP (FMOD_SYSTEM *system, FMOD_CHANNELINDEX channelid, FMOD_DSP *dsp, FMOD_BOOL paused, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_System_GetChannel (FMOD_SYSTEM *system, int channelid, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_System_GetMasterChannelGroup (FMOD_SYSTEM *system, FMOD_CHANNELGROUP **channelgroup); +FMOD_RESULT F_API FMOD_System_GetMasterSoundGroup (FMOD_SYSTEM *system, FMOD_SOUNDGROUP **soundgroup); + +/* + Reverb API +*/ + +FMOD_RESULT F_API FMOD_System_SetReverbProperties (FMOD_SYSTEM *system, const FMOD_REVERB_PROPERTIES *prop); +FMOD_RESULT F_API FMOD_System_GetReverbProperties (FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); +FMOD_RESULT F_API FMOD_System_SetReverbAmbientProperties(FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); +FMOD_RESULT F_API FMOD_System_GetReverbAmbientProperties(FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); + +/* + System level DSP access. +*/ + +FMOD_RESULT F_API FMOD_System_GetDSPHead (FMOD_SYSTEM *system, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_System_AddDSP (FMOD_SYSTEM *system, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); +FMOD_RESULT F_API FMOD_System_LockDSP (FMOD_SYSTEM *system); +FMOD_RESULT F_API FMOD_System_UnlockDSP (FMOD_SYSTEM *system); +FMOD_RESULT F_API FMOD_System_GetDSPClock (FMOD_SYSTEM *system, unsigned int *hi, unsigned int *lo); + +/* + Recording API. +*/ + +FMOD_RESULT F_API FMOD_System_GetRecordNumDrivers (FMOD_SYSTEM *system, int *numdrivers); +FMOD_RESULT F_API FMOD_System_GetRecordDriverInfo (FMOD_SYSTEM *system, int id, char *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetRecordDriverInfoW (FMOD_SYSTEM *system, int id, short *name, int namelen, FMOD_GUID *guid); +FMOD_RESULT F_API FMOD_System_GetRecordDriverCaps (FMOD_SYSTEM *system, int id, FMOD_CAPS *caps, int *minfrequency, int *maxfrequency); +FMOD_RESULT F_API FMOD_System_GetRecordPosition (FMOD_SYSTEM *system, int id, unsigned int *position); + +FMOD_RESULT F_API FMOD_System_RecordStart (FMOD_SYSTEM *system, int id, FMOD_SOUND *sound, FMOD_BOOL loop); +FMOD_RESULT F_API FMOD_System_RecordStop (FMOD_SYSTEM *system, int id); +FMOD_RESULT F_API FMOD_System_IsRecording (FMOD_SYSTEM *system, int id, FMOD_BOOL *recording); + +/* + Geometry API. +*/ + +FMOD_RESULT F_API FMOD_System_CreateGeometry (FMOD_SYSTEM *system, int maxpolygons, int maxvertices, FMOD_GEOMETRY **geometry); +FMOD_RESULT F_API FMOD_System_SetGeometrySettings (FMOD_SYSTEM *system, float maxworldsize); +FMOD_RESULT F_API FMOD_System_GetGeometrySettings (FMOD_SYSTEM *system, float *maxworldsize); +FMOD_RESULT F_API FMOD_System_LoadGeometry (FMOD_SYSTEM *system, const void *data, int datasize, FMOD_GEOMETRY **geometry); +FMOD_RESULT F_API FMOD_System_GetGeometryOcclusion (FMOD_SYSTEM *system, const FMOD_VECTOR *listener, const FMOD_VECTOR *source, float *direct, float *reverb); + +/* + Network functions. +*/ + +FMOD_RESULT F_API FMOD_System_SetNetworkProxy (FMOD_SYSTEM *system, const char *proxy); +FMOD_RESULT F_API FMOD_System_GetNetworkProxy (FMOD_SYSTEM *system, char *proxy, int proxylen); +FMOD_RESULT F_API FMOD_System_SetNetworkTimeout (FMOD_SYSTEM *system, int timeout); +FMOD_RESULT F_API FMOD_System_GetNetworkTimeout (FMOD_SYSTEM *system, int *timeout); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_System_SetUserData (FMOD_SYSTEM *system, void *userdata); +FMOD_RESULT F_API FMOD_System_GetUserData (FMOD_SYSTEM *system, void **userdata); + +FMOD_RESULT F_API FMOD_System_GetMemoryInfo (FMOD_SYSTEM *system, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Sound' API +*/ + +FMOD_RESULT F_API FMOD_Sound_Release (FMOD_SOUND *sound); +FMOD_RESULT F_API FMOD_Sound_GetSystemObject (FMOD_SOUND *sound, FMOD_SYSTEM **system); + +/* + Standard sound manipulation functions. +*/ + +FMOD_RESULT F_API FMOD_Sound_Lock (FMOD_SOUND *sound, unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); +FMOD_RESULT F_API FMOD_Sound_Unlock (FMOD_SOUND *sound, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); +FMOD_RESULT F_API FMOD_Sound_SetDefaults (FMOD_SOUND *sound, float frequency, float volume, float pan, int priority); +FMOD_RESULT F_API FMOD_Sound_GetDefaults (FMOD_SOUND *sound, float *frequency, float *volume, float *pan, int *priority); +FMOD_RESULT F_API FMOD_Sound_SetVariations (FMOD_SOUND *sound, float frequencyvar, float volumevar, float panvar); +FMOD_RESULT F_API FMOD_Sound_GetVariations (FMOD_SOUND *sound, float *frequencyvar, float *volumevar, float *panvar); +FMOD_RESULT F_API FMOD_Sound_Set3DMinMaxDistance (FMOD_SOUND *sound, float min, float max); +FMOD_RESULT F_API FMOD_Sound_Get3DMinMaxDistance (FMOD_SOUND *sound, float *min, float *max); +FMOD_RESULT F_API FMOD_Sound_Set3DConeSettings (FMOD_SOUND *sound, float insideconeangle, float outsideconeangle, float outsidevolume); +FMOD_RESULT F_API FMOD_Sound_Get3DConeSettings (FMOD_SOUND *sound, float *insideconeangle, float *outsideconeangle, float *outsidevolume); +FMOD_RESULT F_API FMOD_Sound_Set3DCustomRolloff (FMOD_SOUND *sound, FMOD_VECTOR *points, int numpoints); +FMOD_RESULT F_API FMOD_Sound_Get3DCustomRolloff (FMOD_SOUND *sound, FMOD_VECTOR **points, int *numpoints); +FMOD_RESULT F_API FMOD_Sound_SetSubSound (FMOD_SOUND *sound, int index, FMOD_SOUND *subsound); +FMOD_RESULT F_API FMOD_Sound_GetSubSound (FMOD_SOUND *sound, int index, FMOD_SOUND **subsound); +FMOD_RESULT F_API FMOD_Sound_GetSubSoundParent (FMOD_SOUND *sound, FMOD_SOUND **parentsound); +FMOD_RESULT F_API FMOD_Sound_SetSubSoundSentence (FMOD_SOUND *sound, int *subsoundlist, int numsubsounds); +FMOD_RESULT F_API FMOD_Sound_GetName (FMOD_SOUND *sound, char *name, int namelen); +FMOD_RESULT F_API FMOD_Sound_GetLength (FMOD_SOUND *sound, unsigned int *length, FMOD_TIMEUNIT lengthtype); +FMOD_RESULT F_API FMOD_Sound_GetFormat (FMOD_SOUND *sound, FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits); +FMOD_RESULT F_API FMOD_Sound_GetNumSubSounds (FMOD_SOUND *sound, int *numsubsounds); +FMOD_RESULT F_API FMOD_Sound_GetNumTags (FMOD_SOUND *sound, int *numtags, int *numtagsupdated); +FMOD_RESULT F_API FMOD_Sound_GetTag (FMOD_SOUND *sound, const char *name, int index, FMOD_TAG *tag); +FMOD_RESULT F_API FMOD_Sound_GetOpenState (FMOD_SOUND *sound, FMOD_OPENSTATE *openstate, unsigned int *percentbuffered, FMOD_BOOL *starving, FMOD_BOOL *diskbusy); +FMOD_RESULT F_API FMOD_Sound_ReadData (FMOD_SOUND *sound, void *buffer, unsigned int lenbytes, unsigned int *read); +FMOD_RESULT F_API FMOD_Sound_SeekData (FMOD_SOUND *sound, unsigned int pcm); + +FMOD_RESULT F_API FMOD_Sound_SetSoundGroup (FMOD_SOUND *sound, FMOD_SOUNDGROUP *soundgroup); +FMOD_RESULT F_API FMOD_Sound_GetSoundGroup (FMOD_SOUND *sound, FMOD_SOUNDGROUP **soundgroup); + +/* + Synchronization point API. These points can come from markers embedded in wav files, and can also generate channel callbacks. +*/ + +FMOD_RESULT F_API FMOD_Sound_GetNumSyncPoints (FMOD_SOUND *sound, int *numsyncpoints); +FMOD_RESULT F_API FMOD_Sound_GetSyncPoint (FMOD_SOUND *sound, int index, FMOD_SYNCPOINT **point); +FMOD_RESULT F_API FMOD_Sound_GetSyncPointInfo (FMOD_SOUND *sound, FMOD_SYNCPOINT *point, char *name, int namelen, unsigned int *offset, FMOD_TIMEUNIT offsettype); +FMOD_RESULT F_API FMOD_Sound_AddSyncPoint (FMOD_SOUND *sound, unsigned int offset, FMOD_TIMEUNIT offsettype, const char *name, FMOD_SYNCPOINT **point); +FMOD_RESULT F_API FMOD_Sound_DeleteSyncPoint (FMOD_SOUND *sound, FMOD_SYNCPOINT *point); + +/* + Functions also in Channel class but here they are the 'default' to save having to change it in Channel all the time. +*/ + +FMOD_RESULT F_API FMOD_Sound_SetMode (FMOD_SOUND *sound, FMOD_MODE mode); +FMOD_RESULT F_API FMOD_Sound_GetMode (FMOD_SOUND *sound, FMOD_MODE *mode); +FMOD_RESULT F_API FMOD_Sound_SetLoopCount (FMOD_SOUND *sound, int loopcount); +FMOD_RESULT F_API FMOD_Sound_GetLoopCount (FMOD_SOUND *sound, int *loopcount); +FMOD_RESULT F_API FMOD_Sound_SetLoopPoints (FMOD_SOUND *sound, unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); +FMOD_RESULT F_API FMOD_Sound_GetLoopPoints (FMOD_SOUND *sound, unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + +/* + For MOD/S3M/XM/IT/MID sequenced formats only. +*/ + +FMOD_RESULT F_API FMOD_Sound_GetMusicNumChannels (FMOD_SOUND *sound, int *numchannels); +FMOD_RESULT F_API FMOD_Sound_SetMusicChannelVolume (FMOD_SOUND *sound, int channel, float volume); +FMOD_RESULT F_API FMOD_Sound_GetMusicChannelVolume (FMOD_SOUND *sound, int channel, float *volume); +FMOD_RESULT F_API FMOD_Sound_SetMusicSpeed (FMOD_SOUND *sound, float speed); +FMOD_RESULT F_API FMOD_Sound_GetMusicSpeed (FMOD_SOUND *sound, float *speed); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Sound_SetUserData (FMOD_SOUND *sound, void *userdata); +FMOD_RESULT F_API FMOD_Sound_GetUserData (FMOD_SOUND *sound, void **userdata); + +FMOD_RESULT F_API FMOD_Sound_GetMemoryInfo (FMOD_SOUND *sound, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Channel' API +*/ + +FMOD_RESULT F_API FMOD_Channel_GetSystemObject (FMOD_CHANNEL *channel, FMOD_SYSTEM **system); + +FMOD_RESULT F_API FMOD_Channel_Stop (FMOD_CHANNEL *channel); +FMOD_RESULT F_API FMOD_Channel_SetPaused (FMOD_CHANNEL *channel, FMOD_BOOL paused); +FMOD_RESULT F_API FMOD_Channel_GetPaused (FMOD_CHANNEL *channel, FMOD_BOOL *paused); +FMOD_RESULT F_API FMOD_Channel_SetVolume (FMOD_CHANNEL *channel, float volume); +FMOD_RESULT F_API FMOD_Channel_GetVolume (FMOD_CHANNEL *channel, float *volume); +FMOD_RESULT F_API FMOD_Channel_SetFrequency (FMOD_CHANNEL *channel, float frequency); +FMOD_RESULT F_API FMOD_Channel_GetFrequency (FMOD_CHANNEL *channel, float *frequency); +FMOD_RESULT F_API FMOD_Channel_SetPan (FMOD_CHANNEL *channel, float pan); +FMOD_RESULT F_API FMOD_Channel_GetPan (FMOD_CHANNEL *channel, float *pan); +FMOD_RESULT F_API FMOD_Channel_SetDelay (FMOD_CHANNEL *channel, FMOD_DELAYTYPE delaytype, unsigned int delayhi, unsigned int delaylo); +FMOD_RESULT F_API FMOD_Channel_GetDelay (FMOD_CHANNEL *channel, FMOD_DELAYTYPE delaytype, unsigned int *delayhi, unsigned int *delaylo); +FMOD_RESULT F_API FMOD_Channel_SetSpeakerMix (FMOD_CHANNEL *channel, float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); +FMOD_RESULT F_API FMOD_Channel_GetSpeakerMix (FMOD_CHANNEL *channel, float *frontleft, float *frontright, float *center, float *lfe, float *backleft, float *backright, float *sideleft, float *sideright); +FMOD_RESULT F_API FMOD_Channel_SetSpeakerLevels (FMOD_CHANNEL *channel, FMOD_SPEAKER speaker, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_GetSpeakerLevels (FMOD_CHANNEL *channel, FMOD_SPEAKER speaker, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_SetInputChannelMix (FMOD_CHANNEL *channel, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_GetInputChannelMix (FMOD_CHANNEL *channel, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_Channel_SetMute (FMOD_CHANNEL *channel, FMOD_BOOL mute); +FMOD_RESULT F_API FMOD_Channel_GetMute (FMOD_CHANNEL *channel, FMOD_BOOL *mute); +FMOD_RESULT F_API FMOD_Channel_SetPriority (FMOD_CHANNEL *channel, int priority); +FMOD_RESULT F_API FMOD_Channel_GetPriority (FMOD_CHANNEL *channel, int *priority); +FMOD_RESULT F_API FMOD_Channel_SetPosition (FMOD_CHANNEL *channel, unsigned int position, FMOD_TIMEUNIT postype); +FMOD_RESULT F_API FMOD_Channel_GetPosition (FMOD_CHANNEL *channel, unsigned int *position, FMOD_TIMEUNIT postype); +FMOD_RESULT F_API FMOD_Channel_SetReverbProperties (FMOD_CHANNEL *channel, const FMOD_REVERB_CHANNELPROPERTIES *prop); +FMOD_RESULT F_API FMOD_Channel_GetReverbProperties (FMOD_CHANNEL *channel, FMOD_REVERB_CHANNELPROPERTIES *prop); +FMOD_RESULT F_API FMOD_Channel_SetLowPassGain (FMOD_CHANNEL *channel, float gain); +FMOD_RESULT F_API FMOD_Channel_GetLowPassGain (FMOD_CHANNEL *channel, float *gain); + +FMOD_RESULT F_API FMOD_Channel_SetChannelGroup (FMOD_CHANNEL *channel, FMOD_CHANNELGROUP *channelgroup); +FMOD_RESULT F_API FMOD_Channel_GetChannelGroup (FMOD_CHANNEL *channel, FMOD_CHANNELGROUP **channelgroup); +FMOD_RESULT F_API FMOD_Channel_SetCallback (FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACK callback); + +/* + 3D functionality. +*/ + +FMOD_RESULT F_API FMOD_Channel_Set3DAttributes (FMOD_CHANNEL *channel, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); +FMOD_RESULT F_API FMOD_Channel_Get3DAttributes (FMOD_CHANNEL *channel, FMOD_VECTOR *pos, FMOD_VECTOR *vel); +FMOD_RESULT F_API FMOD_Channel_Set3DMinMaxDistance (FMOD_CHANNEL *channel, float mindistance, float maxdistance); +FMOD_RESULT F_API FMOD_Channel_Get3DMinMaxDistance (FMOD_CHANNEL *channel, float *mindistance, float *maxdistance); +FMOD_RESULT F_API FMOD_Channel_Set3DConeSettings (FMOD_CHANNEL *channel, float insideconeangle, float outsideconeangle, float outsidevolume); +FMOD_RESULT F_API FMOD_Channel_Get3DConeSettings (FMOD_CHANNEL *channel, float *insideconeangle, float *outsideconeangle, float *outsidevolume); +FMOD_RESULT F_API FMOD_Channel_Set3DConeOrientation (FMOD_CHANNEL *channel, FMOD_VECTOR *orientation); +FMOD_RESULT F_API FMOD_Channel_Get3DConeOrientation (FMOD_CHANNEL *channel, FMOD_VECTOR *orientation); +FMOD_RESULT F_API FMOD_Channel_Set3DCustomRolloff (FMOD_CHANNEL *channel, FMOD_VECTOR *points, int numpoints); +FMOD_RESULT F_API FMOD_Channel_Get3DCustomRolloff (FMOD_CHANNEL *channel, FMOD_VECTOR **points, int *numpoints); +FMOD_RESULT F_API FMOD_Channel_Set3DOcclusion (FMOD_CHANNEL *channel, float directocclusion, float reverbocclusion); +FMOD_RESULT F_API FMOD_Channel_Get3DOcclusion (FMOD_CHANNEL *channel, float *directocclusion, float *reverbocclusion); +FMOD_RESULT F_API FMOD_Channel_Set3DSpread (FMOD_CHANNEL *channel, float angle); +FMOD_RESULT F_API FMOD_Channel_Get3DSpread (FMOD_CHANNEL *channel, float *angle); +FMOD_RESULT F_API FMOD_Channel_Set3DPanLevel (FMOD_CHANNEL *channel, float level); +FMOD_RESULT F_API FMOD_Channel_Get3DPanLevel (FMOD_CHANNEL *channel, float *level); +FMOD_RESULT F_API FMOD_Channel_Set3DDopplerLevel (FMOD_CHANNEL *channel, float level); +FMOD_RESULT F_API FMOD_Channel_Get3DDopplerLevel (FMOD_CHANNEL *channel, float *level); +FMOD_RESULT F_API FMOD_Channel_Set3DDistanceFilter (FMOD_CHANNEL *channel, FMOD_BOOL custom, float customLevel, float centerFreq); +FMOD_RESULT F_API FMOD_Channel_Get3DDistanceFilter (FMOD_CHANNEL *channel, FMOD_BOOL *custom, float *customLevel, float *centerFreq); + +/* + DSP functionality only for channels playing sounds created with FMOD_SOFTWARE. +*/ + +FMOD_RESULT F_API FMOD_Channel_GetDSPHead (FMOD_CHANNEL *channel, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_Channel_AddDSP (FMOD_CHANNEL *channel, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); + +/* + Information only functions. +*/ + +FMOD_RESULT F_API FMOD_Channel_IsPlaying (FMOD_CHANNEL *channel, FMOD_BOOL *isplaying); +FMOD_RESULT F_API FMOD_Channel_IsVirtual (FMOD_CHANNEL *channel, FMOD_BOOL *isvirtual); +FMOD_RESULT F_API FMOD_Channel_GetAudibility (FMOD_CHANNEL *channel, float *audibility); +FMOD_RESULT F_API FMOD_Channel_GetCurrentSound (FMOD_CHANNEL *channel, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_Channel_GetSpectrum (FMOD_CHANNEL *channel, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); +FMOD_RESULT F_API FMOD_Channel_GetWaveData (FMOD_CHANNEL *channel, float *wavearray, int numvalues, int channeloffset); +FMOD_RESULT F_API FMOD_Channel_GetIndex (FMOD_CHANNEL *channel, int *index); + +/* + Functions also found in Sound class but here they can be set per channel. +*/ + +FMOD_RESULT F_API FMOD_Channel_SetMode (FMOD_CHANNEL *channel, FMOD_MODE mode); +FMOD_RESULT F_API FMOD_Channel_GetMode (FMOD_CHANNEL *channel, FMOD_MODE *mode); +FMOD_RESULT F_API FMOD_Channel_SetLoopCount (FMOD_CHANNEL *channel, int loopcount); +FMOD_RESULT F_API FMOD_Channel_GetLoopCount (FMOD_CHANNEL *channel, int *loopcount); +FMOD_RESULT F_API FMOD_Channel_SetLoopPoints (FMOD_CHANNEL *channel, unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); +FMOD_RESULT F_API FMOD_Channel_GetLoopPoints (FMOD_CHANNEL *channel, unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Channel_SetUserData (FMOD_CHANNEL *channel, void *userdata); +FMOD_RESULT F_API FMOD_Channel_GetUserData (FMOD_CHANNEL *channel, void **userdata); + +FMOD_RESULT F_API FMOD_Channel_GetMemoryInfo (FMOD_CHANNEL *channel, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'ChannelGroup' API +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_Release (FMOD_CHANNELGROUP *channelgroup); +FMOD_RESULT F_API FMOD_ChannelGroup_GetSystemObject (FMOD_CHANNELGROUP *channelgroup, FMOD_SYSTEM **system); + +/* + Channelgroup scale values. (changes attributes relative to the channels, doesn't overwrite them) +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_SetVolume (FMOD_CHANNELGROUP *channelgroup, float volume); +FMOD_RESULT F_API FMOD_ChannelGroup_GetVolume (FMOD_CHANNELGROUP *channelgroup, float *volume); +FMOD_RESULT F_API FMOD_ChannelGroup_SetPitch (FMOD_CHANNELGROUP *channelgroup, float pitch); +FMOD_RESULT F_API FMOD_ChannelGroup_GetPitch (FMOD_CHANNELGROUP *channelgroup, float *pitch); +FMOD_RESULT F_API FMOD_ChannelGroup_Set3DOcclusion (FMOD_CHANNELGROUP *channelgroup, float directocclusion, float reverbocclusion); +FMOD_RESULT F_API FMOD_ChannelGroup_Get3DOcclusion (FMOD_CHANNELGROUP *channelgroup, float *directocclusion, float *reverbocclusion); +FMOD_RESULT F_API FMOD_ChannelGroup_SetPaused (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL paused); +FMOD_RESULT F_API FMOD_ChannelGroup_GetPaused (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL *paused); +FMOD_RESULT F_API FMOD_ChannelGroup_SetMute (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL mute); +FMOD_RESULT F_API FMOD_ChannelGroup_GetMute (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL *mute); + +/* + Channelgroup override values. (recursively overwrites whatever settings the channels had) +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_Stop (FMOD_CHANNELGROUP *channelgroup); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideVolume (FMOD_CHANNELGROUP *channelgroup, float volume); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideFrequency(FMOD_CHANNELGROUP *channelgroup, float frequency); +FMOD_RESULT F_API FMOD_ChannelGroup_OverridePan (FMOD_CHANNELGROUP *channelgroup, float pan); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideReverbProperties(FMOD_CHANNELGROUP *channelgroup, const FMOD_REVERB_CHANNELPROPERTIES *prop); +FMOD_RESULT F_API FMOD_ChannelGroup_Override3DAttributes(FMOD_CHANNELGROUP *channelgroup, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); +FMOD_RESULT F_API FMOD_ChannelGroup_OverrideSpeakerMix(FMOD_CHANNELGROUP *channelgroup, float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); + +/* + Nested channel groups. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_AddGroup (FMOD_CHANNELGROUP *channelgroup, FMOD_CHANNELGROUP *group); +FMOD_RESULT F_API FMOD_ChannelGroup_GetNumGroups (FMOD_CHANNELGROUP *channelgroup, int *numgroups); +FMOD_RESULT F_API FMOD_ChannelGroup_GetGroup (FMOD_CHANNELGROUP *channelgroup, int index, FMOD_CHANNELGROUP **group); +FMOD_RESULT F_API FMOD_ChannelGroup_GetParentGroup (FMOD_CHANNELGROUP *channelgroup, FMOD_CHANNELGROUP **group); + +/* + DSP functionality only for channel groups playing sounds created with FMOD_SOFTWARE. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_GetDSPHead (FMOD_CHANNELGROUP *channelgroup, FMOD_DSP **dsp); +FMOD_RESULT F_API FMOD_ChannelGroup_AddDSP (FMOD_CHANNELGROUP *channelgroup, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); + +/* + Information only functions. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_GetName (FMOD_CHANNELGROUP *channelgroup, char *name, int namelen); +FMOD_RESULT F_API FMOD_ChannelGroup_GetNumChannels (FMOD_CHANNELGROUP *channelgroup, int *numchannels); +FMOD_RESULT F_API FMOD_ChannelGroup_GetChannel (FMOD_CHANNELGROUP *channelgroup, int index, FMOD_CHANNEL **channel); +FMOD_RESULT F_API FMOD_ChannelGroup_GetSpectrum (FMOD_CHANNELGROUP *channelgroup, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); +FMOD_RESULT F_API FMOD_ChannelGroup_GetWaveData (FMOD_CHANNELGROUP *channelgroup, float *wavearray, int numvalues, int channeloffset); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_ChannelGroup_SetUserData (FMOD_CHANNELGROUP *channelgroup, void *userdata); +FMOD_RESULT F_API FMOD_ChannelGroup_GetUserData (FMOD_CHANNELGROUP *channelgroup, void **userdata); + +FMOD_RESULT F_API FMOD_ChannelGroup_GetMemoryInfo (FMOD_CHANNELGROUP *channelgroup, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'SoundGroup' API +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_Release (FMOD_SOUNDGROUP *soundgroup); +FMOD_RESULT F_API FMOD_SoundGroup_GetSystemObject (FMOD_SOUNDGROUP *soundgroup, FMOD_SYSTEM **system); + +/* + SoundGroup control functions. +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_SetMaxAudible (FMOD_SOUNDGROUP *soundgroup, int maxaudible); +FMOD_RESULT F_API FMOD_SoundGroup_GetMaxAudible (FMOD_SOUNDGROUP *soundgroup, int *maxaudible); +FMOD_RESULT F_API FMOD_SoundGroup_SetMaxAudibleBehavior(FMOD_SOUNDGROUP *soundgroup, FMOD_SOUNDGROUP_BEHAVIOR behavior); +FMOD_RESULT F_API FMOD_SoundGroup_GetMaxAudibleBehavior(FMOD_SOUNDGROUP *soundgroup, FMOD_SOUNDGROUP_BEHAVIOR *behavior); +FMOD_RESULT F_API FMOD_SoundGroup_SetMuteFadeSpeed (FMOD_SOUNDGROUP *soundgroup, float speed); +FMOD_RESULT F_API FMOD_SoundGroup_GetMuteFadeSpeed (FMOD_SOUNDGROUP *soundgroup, float *speed); +FMOD_RESULT F_API FMOD_SoundGroup_SetVolume (FMOD_SOUNDGROUP *soundgroup, float volume); +FMOD_RESULT F_API FMOD_SoundGroup_GetVolume (FMOD_SOUNDGROUP *soundgroup, float *volume); +FMOD_RESULT F_API FMOD_SoundGroup_Stop (FMOD_SOUNDGROUP *soundgroup); + +/* + Information only functions. +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_GetName (FMOD_SOUNDGROUP *soundgroup, char *name, int namelen); +FMOD_RESULT F_API FMOD_SoundGroup_GetNumSounds (FMOD_SOUNDGROUP *soundgroup, int *numsounds); +FMOD_RESULT F_API FMOD_SoundGroup_GetSound (FMOD_SOUNDGROUP *soundgroup, int index, FMOD_SOUND **sound); +FMOD_RESULT F_API FMOD_SoundGroup_GetNumPlaying (FMOD_SOUNDGROUP *soundgroup, int *numplaying); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_SoundGroup_SetUserData (FMOD_SOUNDGROUP *soundgroup, void *userdata); +FMOD_RESULT F_API FMOD_SoundGroup_GetUserData (FMOD_SOUNDGROUP *soundgroup, void **userdata); + +FMOD_RESULT F_API FMOD_SoundGroup_GetMemoryInfo (FMOD_SOUNDGROUP *soundgroup, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'DSP' API +*/ + +FMOD_RESULT F_API FMOD_DSP_Release (FMOD_DSP *dsp); +FMOD_RESULT F_API FMOD_DSP_GetSystemObject (FMOD_DSP *dsp, FMOD_SYSTEM **system); + +/* + Connection / disconnection / input and output enumeration. +*/ + +FMOD_RESULT F_API FMOD_DSP_AddInput (FMOD_DSP *dsp, FMOD_DSP *target, FMOD_DSPCONNECTION **connection); +FMOD_RESULT F_API FMOD_DSP_DisconnectFrom (FMOD_DSP *dsp, FMOD_DSP *target); +FMOD_RESULT F_API FMOD_DSP_DisconnectAll (FMOD_DSP *dsp, FMOD_BOOL inputs, FMOD_BOOL outputs); +FMOD_RESULT F_API FMOD_DSP_Remove (FMOD_DSP *dsp); +FMOD_RESULT F_API FMOD_DSP_GetNumInputs (FMOD_DSP *dsp, int *numinputs); +FMOD_RESULT F_API FMOD_DSP_GetNumOutputs (FMOD_DSP *dsp, int *numoutputs); +FMOD_RESULT F_API FMOD_DSP_GetInput (FMOD_DSP *dsp, int index, FMOD_DSP **input, FMOD_DSPCONNECTION **inputconnection); +FMOD_RESULT F_API FMOD_DSP_GetOutput (FMOD_DSP *dsp, int index, FMOD_DSP **output, FMOD_DSPCONNECTION **outputconnection); + +/* + DSP unit control. +*/ + +FMOD_RESULT F_API FMOD_DSP_SetActive (FMOD_DSP *dsp, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_DSP_GetActive (FMOD_DSP *dsp, FMOD_BOOL *active); +FMOD_RESULT F_API FMOD_DSP_SetBypass (FMOD_DSP *dsp, FMOD_BOOL bypass); +FMOD_RESULT F_API FMOD_DSP_GetBypass (FMOD_DSP *dsp, FMOD_BOOL *bypass); +FMOD_RESULT F_API FMOD_DSP_SetSpeakerActive (FMOD_DSP *dsp, FMOD_SPEAKER speaker, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_DSP_GetSpeakerActive (FMOD_DSP *dsp, FMOD_SPEAKER speaker, FMOD_BOOL *active); +FMOD_RESULT F_API FMOD_DSP_Reset (FMOD_DSP *dsp); + +/* + DSP parameter control. +*/ + +FMOD_RESULT F_API FMOD_DSP_SetParameter (FMOD_DSP *dsp, int index, float value); +FMOD_RESULT F_API FMOD_DSP_GetParameter (FMOD_DSP *dsp, int index, float *value, char *valuestr, int valuestrlen); +FMOD_RESULT F_API FMOD_DSP_GetNumParameters (FMOD_DSP *dsp, int *numparams); +FMOD_RESULT F_API FMOD_DSP_GetParameterInfo (FMOD_DSP *dsp, int index, char *name, char *label, char *description, int descriptionlen, float *min, float *max); +FMOD_RESULT F_API FMOD_DSP_ShowConfigDialog (FMOD_DSP *dsp, void *hwnd, FMOD_BOOL show); + +/* + DSP attributes. +*/ + +FMOD_RESULT F_API FMOD_DSP_GetInfo (FMOD_DSP *dsp, char *name, unsigned int *version, int *channels, int *configwidth, int *configheight); +FMOD_RESULT F_API FMOD_DSP_GetType (FMOD_DSP *dsp, FMOD_DSP_TYPE *type); +FMOD_RESULT F_API FMOD_DSP_SetDefaults (FMOD_DSP *dsp, float frequency, float volume, float pan, int priority); +FMOD_RESULT F_API FMOD_DSP_GetDefaults (FMOD_DSP *dsp, float *frequency, float *volume, float *pan, int *priority); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_DSP_SetUserData (FMOD_DSP *dsp, void *userdata); +FMOD_RESULT F_API FMOD_DSP_GetUserData (FMOD_DSP *dsp, void **userdata); + +FMOD_RESULT F_API FMOD_DSP_GetMemoryInfo (FMOD_DSP *dsp, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'DSPConnection' API +*/ + +FMOD_RESULT F_API FMOD_DSPConnection_GetInput (FMOD_DSPCONNECTION *dspconnection, FMOD_DSP **input); +FMOD_RESULT F_API FMOD_DSPConnection_GetOutput (FMOD_DSPCONNECTION *dspconnection, FMOD_DSP **output); +FMOD_RESULT F_API FMOD_DSPConnection_SetMix (FMOD_DSPCONNECTION *dspconnection, float volume); +FMOD_RESULT F_API FMOD_DSPConnection_GetMix (FMOD_DSPCONNECTION *dspconnection, float *volume); +FMOD_RESULT F_API FMOD_DSPConnection_SetLevels (FMOD_DSPCONNECTION *dspconnection, FMOD_SPEAKER speaker, float *levels, int numlevels); +FMOD_RESULT F_API FMOD_DSPConnection_GetLevels (FMOD_DSPCONNECTION *dspconnection, FMOD_SPEAKER speaker, float *levels, int numlevels); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_DSPConnection_SetUserData (FMOD_DSPCONNECTION *dspconnection, void *userdata); +FMOD_RESULT F_API FMOD_DSPConnection_GetUserData (FMOD_DSPCONNECTION *dspconnection, void **userdata); + +FMOD_RESULT F_API FMOD_DSPConnection_GetMemoryInfo (FMOD_DSPCONNECTION *dspconnection, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Geometry' API +*/ + +FMOD_RESULT F_API FMOD_Geometry_Release (FMOD_GEOMETRY *geometry); + +/* + Polygon manipulation. +*/ + +FMOD_RESULT F_API FMOD_Geometry_AddPolygon (FMOD_GEOMETRY *geometry, float directocclusion, float reverbocclusion, FMOD_BOOL doublesided, int numvertices, const FMOD_VECTOR *vertices, int *polygonindex); +FMOD_RESULT F_API FMOD_Geometry_GetNumPolygons (FMOD_GEOMETRY *geometry, int *numpolygons); +FMOD_RESULT F_API FMOD_Geometry_GetMaxPolygons (FMOD_GEOMETRY *geometry, int *maxpolygons, int *maxvertices); +FMOD_RESULT F_API FMOD_Geometry_GetPolygonNumVertices(FMOD_GEOMETRY *geometry, int index, int *numvertices); +FMOD_RESULT F_API FMOD_Geometry_SetPolygonVertex (FMOD_GEOMETRY *geometry, int index, int vertexindex, const FMOD_VECTOR *vertex); +FMOD_RESULT F_API FMOD_Geometry_GetPolygonVertex (FMOD_GEOMETRY *geometry, int index, int vertexindex, FMOD_VECTOR *vertex); +FMOD_RESULT F_API FMOD_Geometry_SetPolygonAttributes (FMOD_GEOMETRY *geometry, int index, float directocclusion, float reverbocclusion, FMOD_BOOL doublesided); +FMOD_RESULT F_API FMOD_Geometry_GetPolygonAttributes (FMOD_GEOMETRY *geometry, int index, float *directocclusion, float *reverbocclusion, FMOD_BOOL *doublesided); + +/* + Object manipulation. +*/ + +FMOD_RESULT F_API FMOD_Geometry_SetActive (FMOD_GEOMETRY *geometry, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_Geometry_GetActive (FMOD_GEOMETRY *geometry, FMOD_BOOL *active); +FMOD_RESULT F_API FMOD_Geometry_SetRotation (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *forward, const FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_Geometry_GetRotation (FMOD_GEOMETRY *geometry, FMOD_VECTOR *forward, FMOD_VECTOR *up); +FMOD_RESULT F_API FMOD_Geometry_SetPosition (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *position); +FMOD_RESULT F_API FMOD_Geometry_GetPosition (FMOD_GEOMETRY *geometry, FMOD_VECTOR *position); +FMOD_RESULT F_API FMOD_Geometry_SetScale (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *scale); +FMOD_RESULT F_API FMOD_Geometry_GetScale (FMOD_GEOMETRY *geometry, FMOD_VECTOR *scale); +FMOD_RESULT F_API FMOD_Geometry_Save (FMOD_GEOMETRY *geometry, void *data, int *datasize); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Geometry_SetUserData (FMOD_GEOMETRY *geometry, void *userdata); +FMOD_RESULT F_API FMOD_Geometry_GetUserData (FMOD_GEOMETRY *geometry, void **userdata); + +FMOD_RESULT F_API FMOD_Geometry_GetMemoryInfo (FMOD_GEOMETRY *geometry, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +/* + 'Reverb' API +*/ + +FMOD_RESULT F_API FMOD_Reverb_Release (FMOD_REVERB *reverb); + +/* + Reverb manipulation. +*/ + +FMOD_RESULT F_API FMOD_Reverb_Set3DAttributes (FMOD_REVERB *reverb, const FMOD_VECTOR *position, float mindistance, float maxdistance); +FMOD_RESULT F_API FMOD_Reverb_Get3DAttributes (FMOD_REVERB *reverb, FMOD_VECTOR *position, float *mindistance, float *maxdistance); +FMOD_RESULT F_API FMOD_Reverb_SetProperties (FMOD_REVERB *reverb, const FMOD_REVERB_PROPERTIES *properties); +FMOD_RESULT F_API FMOD_Reverb_GetProperties (FMOD_REVERB *reverb, FMOD_REVERB_PROPERTIES *properties); +FMOD_RESULT F_API FMOD_Reverb_SetActive (FMOD_REVERB *reverb, FMOD_BOOL active); +FMOD_RESULT F_API FMOD_Reverb_GetActive (FMOD_REVERB *reverb, FMOD_BOOL *active); + +/* + Userdata set/get. +*/ + +FMOD_RESULT F_API FMOD_Reverb_SetUserData (FMOD_REVERB *reverb, void *userdata); +FMOD_RESULT F_API FMOD_Reverb_GetUserData (FMOD_REVERB *reverb, void **userdata); + +FMOD_RESULT F_API FMOD_Reverb_GetMemoryInfo (FMOD_REVERB *reverb, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/engine/fmod-4/inc/fmod.hpp b/engine/fmod-4/inc/fmod.hpp new file mode 100644 index 0000000..df19647 --- /dev/null +++ b/engine/fmod-4/inc/fmod.hpp @@ -0,0 +1,609 @@ +/* ========================================================================================== */ +/* FMOD Ex - C++ header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* Use this header in conjunction with fmod.h (which contains all the constants / callbacks) */ +/* to develop using C++ classes. */ +/* ========================================================================================== */ + +#ifndef _FMOD_HPP +#define _FMOD_HPP + +#include "fmod.h" + +/* + Constant and defines +*/ + +/* + FMOD Namespace +*/ +namespace FMOD +{ + class System; + class Sound; + class Channel; + class ChannelGroup; + class SoundGroup; + class Reverb; + class DSP; + class DSPConnection; + class Geometry; + + /* + FMOD global system functions (optional). + */ + inline FMOD_RESULT Memory_Initialize(void *poolmem, int poollen, FMOD_MEMORY_ALLOCCALLBACK useralloc, FMOD_MEMORY_REALLOCCALLBACK userrealloc, FMOD_MEMORY_FREECALLBACK userfree, FMOD_MEMORY_TYPE memtypeflags = FMOD_MEMORY_ALL) { return FMOD_Memory_Initialize(poolmem, poollen, useralloc, userrealloc, userfree, memtypeflags); } + inline FMOD_RESULT Memory_GetStats (int *currentalloced, int *maxalloced, bool blocking = true) { return FMOD_Memory_GetStats(currentalloced, maxalloced, blocking); } + inline FMOD_RESULT Debug_SetLevel(FMOD_DEBUGLEVEL level) { return FMOD_Debug_SetLevel(level); } + inline FMOD_RESULT Debug_GetLevel(FMOD_DEBUGLEVEL *level) { return FMOD_Debug_GetLevel(level); } + inline FMOD_RESULT File_SetDiskBusy(int busy) { return FMOD_File_SetDiskBusy(busy); } + inline FMOD_RESULT File_GetDiskBusy(int *busy) { return FMOD_File_GetDiskBusy(busy); } + + /* + FMOD System factory functions. + */ + inline FMOD_RESULT System_Create(System **system) { return FMOD_System_Create((FMOD_SYSTEM **)system); } + + /* + 'System' API + */ + + class System + { + private: + + System(); /* Constructor made private so user cannot statically instance a System class. + System_Create must be used. */ + public: + + FMOD_RESULT F_API release (); + + // Pre-init functions. + FMOD_RESULT F_API setOutput (FMOD_OUTPUTTYPE output); + FMOD_RESULT F_API getOutput (FMOD_OUTPUTTYPE *output); + FMOD_RESULT F_API getNumDrivers (int *numdrivers); + FMOD_RESULT F_API getDriverInfo (int id, char *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getDriverInfoW (int id, short *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getDriverCaps (int id, FMOD_CAPS *caps, int *controlpaneloutputrate, FMOD_SPEAKERMODE *controlpanelspeakermode); + FMOD_RESULT F_API setDriver (int driver); + FMOD_RESULT F_API getDriver (int *driver); + FMOD_RESULT F_API setHardwareChannels (int numhardwarechannels); + FMOD_RESULT F_API setSoftwareChannels (int numsoftwarechannels); + FMOD_RESULT F_API getSoftwareChannels (int *numsoftwarechannels); + FMOD_RESULT F_API setSoftwareFormat (int samplerate, FMOD_SOUND_FORMAT format, int numoutputchannels, int maxinputchannels, FMOD_DSP_RESAMPLER resamplemethod); + FMOD_RESULT F_API getSoftwareFormat (int *samplerate, FMOD_SOUND_FORMAT *format, int *numoutputchannels, int *maxinputchannels, FMOD_DSP_RESAMPLER *resamplemethod, int *bits); + FMOD_RESULT F_API setDSPBufferSize (unsigned int bufferlength, int numbuffers); + FMOD_RESULT F_API getDSPBufferSize (unsigned int *bufferlength, int *numbuffers); + FMOD_RESULT F_API setFileSystem (FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek, FMOD_FILE_ASYNCREADCALLBACK userasyncread, FMOD_FILE_ASYNCCANCELCALLBACK userasynccancel, int blockalign); + FMOD_RESULT F_API attachFileSystem (FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek); + FMOD_RESULT F_API setAdvancedSettings (FMOD_ADVANCEDSETTINGS *settings); + FMOD_RESULT F_API getAdvancedSettings (FMOD_ADVANCEDSETTINGS *settings); + FMOD_RESULT F_API setSpeakerMode (FMOD_SPEAKERMODE speakermode); + FMOD_RESULT F_API getSpeakerMode (FMOD_SPEAKERMODE *speakermode); + FMOD_RESULT F_API setCallback (FMOD_SYSTEM_CALLBACK callback); + + // Plug-in support + FMOD_RESULT F_API setPluginPath (const char *path); + FMOD_RESULT F_API loadPlugin (const char *filename, unsigned int *handle, unsigned int priority = 0); + FMOD_RESULT F_API unloadPlugin (unsigned int handle); + FMOD_RESULT F_API getNumPlugins (FMOD_PLUGINTYPE plugintype, int *numplugins); + FMOD_RESULT F_API getPluginHandle (FMOD_PLUGINTYPE plugintype, int index, unsigned int *handle); + FMOD_RESULT F_API getPluginInfo (unsigned int handle, FMOD_PLUGINTYPE *plugintype, char *name, int namelen, unsigned int *version); + FMOD_RESULT F_API setOutputByPlugin (unsigned int handle); + FMOD_RESULT F_API getOutputByPlugin (unsigned int *handle); + FMOD_RESULT F_API createDSPByPlugin (unsigned int handle, DSP **dsp); + FMOD_RESULT F_API registerCodec (FMOD_CODEC_DESCRIPTION *description, unsigned int *handle, unsigned int priority = 0); + FMOD_RESULT F_API registerDSP (FMOD_DSP_DESCRIPTION *description, unsigned int *handle); + + // Init/Close + FMOD_RESULT F_API init (int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata); + FMOD_RESULT F_API close (); + + // General post-init system functions + FMOD_RESULT F_API update (); /* IMPORTANT! CALL THIS ONCE PER FRAME! */ + + FMOD_RESULT F_API set3DSettings (float dopplerscale, float distancefactor, float rolloffscale); + FMOD_RESULT F_API get3DSettings (float *dopplerscale, float *distancefactor, float *rolloffscale); + FMOD_RESULT F_API set3DNumListeners (int numlisteners); + FMOD_RESULT F_API get3DNumListeners (int *numlisteners); + FMOD_RESULT F_API set3DListenerAttributes(int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up); + FMOD_RESULT F_API get3DListenerAttributes(int listener, FMOD_VECTOR *pos, FMOD_VECTOR *vel, FMOD_VECTOR *forward, FMOD_VECTOR *up); + FMOD_RESULT F_API set3DRolloffCallback (FMOD_3D_ROLLOFFCALLBACK callback); + FMOD_RESULT F_API set3DSpeakerPosition (FMOD_SPEAKER speaker, float x, float y, bool active); + FMOD_RESULT F_API get3DSpeakerPosition (FMOD_SPEAKER speaker, float *x, float *y, bool *active); + + FMOD_RESULT F_API setStreamBufferSize (unsigned int filebuffersize, FMOD_TIMEUNIT filebuffersizetype); + FMOD_RESULT F_API getStreamBufferSize (unsigned int *filebuffersize, FMOD_TIMEUNIT *filebuffersizetype); + + // System information functions. + FMOD_RESULT F_API getVersion (unsigned int *version); + FMOD_RESULT F_API getOutputHandle (void **handle); + FMOD_RESULT F_API getChannelsPlaying (int *channels); + FMOD_RESULT F_API getHardwareChannels (int *numhardwarechannels); + FMOD_RESULT F_API getCPUUsage (float *dsp, float *stream, float *geometry, float *update, float *total); + FMOD_RESULT F_API getSoundRAM (int *currentalloced, int *maxalloced, int *total); + FMOD_RESULT F_API getNumCDROMDrives (int *numdrives); + FMOD_RESULT F_API getCDROMDriveName (int drive, char *drivename, int drivenamelen, char *scsiname, int scsinamelen, char *devicename, int devicenamelen); + FMOD_RESULT F_API getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); + FMOD_RESULT F_API getWaveData (float *wavearray, int numvalues, int channeloffset); + + // Sound/DSP/Channel/FX creation and retrieval. + FMOD_RESULT F_API createSound (const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound); + FMOD_RESULT F_API createStream (const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, Sound **sound); + FMOD_RESULT F_API createDSP (FMOD_DSP_DESCRIPTION *description, DSP **dsp); + FMOD_RESULT F_API createDSPByType (FMOD_DSP_TYPE type, DSP **dsp); + FMOD_RESULT F_API createChannelGroup (const char *name, ChannelGroup **channelgroup); + FMOD_RESULT F_API createSoundGroup (const char *name, SoundGroup **soundgroup); + FMOD_RESULT F_API createReverb (Reverb **reverb); + + FMOD_RESULT F_API playSound (FMOD_CHANNELINDEX channelid, Sound *sound, bool paused, Channel **channel); + FMOD_RESULT F_API playDSP (FMOD_CHANNELINDEX channelid, DSP *dsp, bool paused, Channel **channel); + FMOD_RESULT F_API getChannel (int channelid, Channel **channel); + FMOD_RESULT F_API getMasterChannelGroup (ChannelGroup **channelgroup); + FMOD_RESULT F_API getMasterSoundGroup (SoundGroup **soundgroup); + + // Reverb API + FMOD_RESULT F_API setReverbProperties (const FMOD_REVERB_PROPERTIES *prop); + FMOD_RESULT F_API getReverbProperties (FMOD_REVERB_PROPERTIES *prop); + FMOD_RESULT F_API setReverbAmbientProperties(FMOD_REVERB_PROPERTIES *prop); + FMOD_RESULT F_API getReverbAmbientProperties(FMOD_REVERB_PROPERTIES *prop); + + // System level DSP access. + FMOD_RESULT F_API getDSPHead (DSP **dsp); + FMOD_RESULT F_API addDSP (DSP *dsp, DSPConnection **connection); + FMOD_RESULT F_API lockDSP (); + FMOD_RESULT F_API unlockDSP (); + FMOD_RESULT F_API getDSPClock (unsigned int *hi, unsigned int *lo); + + // Recording API. + FMOD_RESULT F_API getRecordNumDrivers (int *numdrivers); + FMOD_RESULT F_API getRecordDriverInfo (int id, char *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getRecordDriverInfoW (int id, short *name, int namelen, FMOD_GUID *guid); + FMOD_RESULT F_API getRecordDriverCaps (int id, FMOD_CAPS *caps, int *minfrequency, int *maxfrequency); + FMOD_RESULT F_API getRecordPosition (int id, unsigned int *position); + + FMOD_RESULT F_API recordStart (int id, Sound *sound, bool loop); + FMOD_RESULT F_API recordStop (int id); + FMOD_RESULT F_API isRecording (int id, bool *recording); + + // Geometry API. + FMOD_RESULT F_API createGeometry (int maxpolygons, int maxvertices, Geometry **geometry); + FMOD_RESULT F_API setGeometrySettings (float maxworldsize); + FMOD_RESULT F_API getGeometrySettings (float *maxworldsize); + FMOD_RESULT F_API loadGeometry (const void *data, int datasize, Geometry **geometry); + FMOD_RESULT F_API getGeometryOcclusion (const FMOD_VECTOR *listener, const FMOD_VECTOR *source, float *direct, float *reverb); + + // Network functions. + FMOD_RESULT F_API setNetworkProxy (const char *proxy); + FMOD_RESULT F_API getNetworkProxy (char *proxy, int proxylen); + FMOD_RESULT F_API setNetworkTimeout (int timeout); + FMOD_RESULT F_API getNetworkTimeout (int *timeout); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'Sound' API + */ + class Sound + { + private: + + Sound(); /* Constructor made private so user cannot statically instance a Sound class. + Appropriate Sound creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // Standard sound manipulation functions. + FMOD_RESULT F_API lock (unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); + FMOD_RESULT F_API unlock (void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); + FMOD_RESULT F_API setDefaults (float frequency, float volume, float pan, int priority); + FMOD_RESULT F_API getDefaults (float *frequency, float *volume, float *pan, int *priority); + FMOD_RESULT F_API setVariations (float frequencyvar, float volumevar, float panvar); + FMOD_RESULT F_API getVariations (float *frequencyvar, float *volumevar, float *panvar); + FMOD_RESULT F_API set3DMinMaxDistance (float min, float max); + FMOD_RESULT F_API get3DMinMaxDistance (float *min, float *max); + FMOD_RESULT F_API set3DConeSettings (float insideconeangle, float outsideconeangle, float outsidevolume); + FMOD_RESULT F_API get3DConeSettings (float *insideconeangle, float *outsideconeangle, float *outsidevolume); + FMOD_RESULT F_API set3DCustomRolloff (FMOD_VECTOR *points, int numpoints); + FMOD_RESULT F_API get3DCustomRolloff (FMOD_VECTOR **points, int *numpoints); + FMOD_RESULT F_API setSubSound (int index, Sound *subsound); + FMOD_RESULT F_API getSubSound (int index, Sound **subsound); + FMOD_RESULT F_API getSubSoundParent (Sound **parentsound); + FMOD_RESULT F_API setSubSoundSentence (int *subsoundlist, int numsubsounds); + FMOD_RESULT F_API getName (char *name, int namelen); + FMOD_RESULT F_API getLength (unsigned int *length, FMOD_TIMEUNIT lengthtype); + FMOD_RESULT F_API getFormat (FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits); + FMOD_RESULT F_API getNumSubSounds (int *numsubsounds); + FMOD_RESULT F_API getNumTags (int *numtags, int *numtagsupdated); + FMOD_RESULT F_API getTag (const char *name, int index, FMOD_TAG *tag); + FMOD_RESULT F_API getOpenState (FMOD_OPENSTATE *openstate, unsigned int *percentbuffered, bool *starving, bool *diskbusy); + FMOD_RESULT F_API readData (void *buffer, unsigned int lenbytes, unsigned int *read); + FMOD_RESULT F_API seekData (unsigned int pcm); + + FMOD_RESULT F_API setSoundGroup (SoundGroup *soundgroup); + FMOD_RESULT F_API getSoundGroup (SoundGroup **soundgroup); + + // Synchronization point API. These points can come from markers embedded in wav files, and can also generate channel callbacks. + FMOD_RESULT F_API getNumSyncPoints (int *numsyncpoints); + FMOD_RESULT F_API getSyncPoint (int index, FMOD_SYNCPOINT **point); + FMOD_RESULT F_API getSyncPointInfo (FMOD_SYNCPOINT *point, char *name, int namelen, unsigned int *offset, FMOD_TIMEUNIT offsettype); + FMOD_RESULT F_API addSyncPoint (unsigned int offset, FMOD_TIMEUNIT offsettype, const char *name, FMOD_SYNCPOINT **point); + FMOD_RESULT F_API deleteSyncPoint (FMOD_SYNCPOINT *point); + + // Functions also in Channel class but here they are the 'default' to save having to change it in Channel all the time. + FMOD_RESULT F_API setMode (FMOD_MODE mode); + FMOD_RESULT F_API getMode (FMOD_MODE *mode); + FMOD_RESULT F_API setLoopCount (int loopcount); + FMOD_RESULT F_API getLoopCount (int *loopcount); + FMOD_RESULT F_API setLoopPoints (unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); + FMOD_RESULT F_API getLoopPoints (unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + + // For MOD/S3M/XM/IT/MID sequenced formats only. + FMOD_RESULT F_API getMusicNumChannels (int *numchannels); + FMOD_RESULT F_API setMusicChannelVolume (int channel, float volume); + FMOD_RESULT F_API getMusicChannelVolume (int channel, float *volume); + FMOD_RESULT F_API setMusicSpeed (float speed); + FMOD_RESULT F_API getMusicSpeed (float *speed); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'Channel' API. + */ + class Channel + { + private: + + Channel(); /* Constructor made private so user cannot statically instance a Channel class. + Appropriate Channel creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API getSystemObject (System **system); + + FMOD_RESULT F_API stop (); + FMOD_RESULT F_API setPaused (bool paused); + FMOD_RESULT F_API getPaused (bool *paused); + FMOD_RESULT F_API setVolume (float volume); + FMOD_RESULT F_API getVolume (float *volume); + FMOD_RESULT F_API setFrequency (float frequency); + FMOD_RESULT F_API getFrequency (float *frequency); + FMOD_RESULT F_API setPan (float pan); + FMOD_RESULT F_API getPan (float *pan); + FMOD_RESULT F_API setDelay (FMOD_DELAYTYPE delaytype, unsigned int delayhi, unsigned int delaylo); + FMOD_RESULT F_API getDelay (FMOD_DELAYTYPE delaytype, unsigned int *delayhi, unsigned int *delaylo); + FMOD_RESULT F_API setSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); + FMOD_RESULT F_API getSpeakerMix (float *frontleft, float *frontright, float *center, float *lfe, float *backleft, float *backright, float *sideleft, float *sideright); + FMOD_RESULT F_API setSpeakerLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + FMOD_RESULT F_API getSpeakerLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + FMOD_RESULT F_API setInputChannelMix (float *levels, int numlevels); + FMOD_RESULT F_API getInputChannelMix (float *levels, int numlevels); + FMOD_RESULT F_API setMute (bool mute); + FMOD_RESULT F_API getMute (bool *mute); + FMOD_RESULT F_API setPriority (int priority); + FMOD_RESULT F_API getPriority (int *priority); + FMOD_RESULT F_API setPosition (unsigned int position, FMOD_TIMEUNIT postype); + FMOD_RESULT F_API getPosition (unsigned int *position, FMOD_TIMEUNIT postype); + FMOD_RESULT F_API setReverbProperties (const FMOD_REVERB_CHANNELPROPERTIES *prop); + FMOD_RESULT F_API getReverbProperties (FMOD_REVERB_CHANNELPROPERTIES *prop); + FMOD_RESULT F_API setLowPassGain (float gain); + FMOD_RESULT F_API getLowPassGain (float *gain); + + FMOD_RESULT F_API setChannelGroup (ChannelGroup *channelgroup); + FMOD_RESULT F_API getChannelGroup (ChannelGroup **channelgroup); + FMOD_RESULT F_API setCallback (FMOD_CHANNEL_CALLBACK callback); + + // 3D functionality. + FMOD_RESULT F_API set3DAttributes (const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); + FMOD_RESULT F_API get3DAttributes (FMOD_VECTOR *pos, FMOD_VECTOR *vel); + FMOD_RESULT F_API set3DMinMaxDistance (float mindistance, float maxdistance); + FMOD_RESULT F_API get3DMinMaxDistance (float *mindistance, float *maxdistance); + FMOD_RESULT F_API set3DConeSettings (float insideconeangle, float outsideconeangle, float outsidevolume); + FMOD_RESULT F_API get3DConeSettings (float *insideconeangle, float *outsideconeangle, float *outsidevolume); + FMOD_RESULT F_API set3DConeOrientation (FMOD_VECTOR *orientation); + FMOD_RESULT F_API get3DConeOrientation (FMOD_VECTOR *orientation); + FMOD_RESULT F_API set3DCustomRolloff (FMOD_VECTOR *points, int numpoints); + FMOD_RESULT F_API get3DCustomRolloff (FMOD_VECTOR **points, int *numpoints); + FMOD_RESULT F_API set3DOcclusion (float directocclusion, float reverbocclusion); + FMOD_RESULT F_API get3DOcclusion (float *directocclusion, float *reverbocclusion); + FMOD_RESULT F_API set3DSpread (float angle); + FMOD_RESULT F_API get3DSpread (float *angle); + FMOD_RESULT F_API set3DPanLevel (float level); + FMOD_RESULT F_API get3DPanLevel (float *level); + FMOD_RESULT F_API set3DDopplerLevel (float level); + FMOD_RESULT F_API get3DDopplerLevel (float *level); + FMOD_RESULT F_API set3DDistanceFilter (bool custom, float customLevel, float centerFreq); + FMOD_RESULT F_API get3DDistanceFilter (bool *custom, float *customLevel, float *centerFreq); + + // DSP functionality only for channels playing sounds created with FMOD_SOFTWARE. + FMOD_RESULT F_API getDSPHead (DSP **dsp); + FMOD_RESULT F_API addDSP (DSP *dsp, DSPConnection **connection); + + // Information only functions. + FMOD_RESULT F_API isPlaying (bool *isplaying); + FMOD_RESULT F_API isVirtual (bool *isvirtual); + FMOD_RESULT F_API getAudibility (float *audibility); + FMOD_RESULT F_API getCurrentSound (Sound **sound); + FMOD_RESULT F_API getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); + FMOD_RESULT F_API getWaveData (float *wavearray, int numvalues, int channeloffset); + FMOD_RESULT F_API getIndex (int *index); + + // Functions also found in Sound class but here they can be set per channel. + FMOD_RESULT F_API setMode (FMOD_MODE mode); + FMOD_RESULT F_API getMode (FMOD_MODE *mode); + FMOD_RESULT F_API setLoopCount (int loopcount); + FMOD_RESULT F_API getLoopCount (int *loopcount); + FMOD_RESULT F_API setLoopPoints (unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); + FMOD_RESULT F_API getLoopPoints (unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'ChannelGroup' API + */ + class ChannelGroup + { + private: + + ChannelGroup(); /* Constructor made private so user cannot statically instance a ChannelGroup class. + Appropriate ChannelGroup creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // Channelgroup scale values. (changes attributes relative to the channels, doesn't overwrite them) + FMOD_RESULT F_API setVolume (float volume); + FMOD_RESULT F_API getVolume (float *volume); + FMOD_RESULT F_API setPitch (float pitch); + FMOD_RESULT F_API getPitch (float *pitch); + FMOD_RESULT F_API set3DOcclusion (float directocclusion, float reverbocclusion); + FMOD_RESULT F_API get3DOcclusion (float *directocclusion, float *reverbocclusion); + FMOD_RESULT F_API setPaused (bool paused); + FMOD_RESULT F_API getPaused (bool *paused); + FMOD_RESULT F_API setMute (bool mute); + FMOD_RESULT F_API getMute (bool *mute); + + // Channelgroup override values. (recursively overwrites whatever settings the channels had) + FMOD_RESULT F_API stop (); + FMOD_RESULT F_API overrideVolume (float volume); + FMOD_RESULT F_API overrideFrequency (float frequency); + FMOD_RESULT F_API overridePan (float pan); + FMOD_RESULT F_API overrideReverbProperties(const FMOD_REVERB_CHANNELPROPERTIES *prop); + FMOD_RESULT F_API override3DAttributes (const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); + FMOD_RESULT F_API overrideSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); + + // Nested channel groups. + FMOD_RESULT F_API addGroup (ChannelGroup *group); + FMOD_RESULT F_API getNumGroups (int *numgroups); + FMOD_RESULT F_API getGroup (int index, ChannelGroup **group); + FMOD_RESULT F_API getParentGroup (ChannelGroup **group); + + // DSP functionality only for channel groups playing sounds created with FMOD_SOFTWARE. + FMOD_RESULT F_API getDSPHead (DSP **dsp); + FMOD_RESULT F_API addDSP (DSP *dsp, DSPConnection **connection); + + // Information only functions. + FMOD_RESULT F_API getName (char *name, int namelen); + FMOD_RESULT F_API getNumChannels (int *numchannels); + FMOD_RESULT F_API getChannel (int index, Channel **channel); + FMOD_RESULT F_API getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); + FMOD_RESULT F_API getWaveData (float *wavearray, int numvalues, int channeloffset); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'SoundGroup' API + */ + class SoundGroup + { + private: + + SoundGroup(); /* Constructor made private so user cannot statically instance a SoundGroup class. + Appropriate SoundGroup creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // SoundGroup control functions. + FMOD_RESULT F_API setMaxAudible (int maxaudible); + FMOD_RESULT F_API getMaxAudible (int *maxaudible); + FMOD_RESULT F_API setMaxAudibleBehavior (FMOD_SOUNDGROUP_BEHAVIOR behavior); + FMOD_RESULT F_API getMaxAudibleBehavior (FMOD_SOUNDGROUP_BEHAVIOR *behavior); + FMOD_RESULT F_API setMuteFadeSpeed (float speed); + FMOD_RESULT F_API getMuteFadeSpeed (float *speed); + FMOD_RESULT F_API setVolume (float volume); + FMOD_RESULT F_API getVolume (float *volume); + FMOD_RESULT F_API stop (); + + // Information only functions. + FMOD_RESULT F_API getName (char *name, int namelen); + FMOD_RESULT F_API getNumSounds (int *numsounds); + FMOD_RESULT F_API getSound (int index, Sound **sound); + FMOD_RESULT F_API getNumPlaying (int *numplaying); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + /* + 'DSP' API + */ + class DSP + { + private: + + DSP(); /* Constructor made private so user cannot statically instance a DSP class. + Appropriate DSP creation or retrieval function must be used. */ + public: + + FMOD_RESULT F_API release (); + FMOD_RESULT F_API getSystemObject (System **system); + + // Connection / disconnection / input and output enumeration. + FMOD_RESULT F_API addInput (DSP *target, DSPConnection **connection); + FMOD_RESULT F_API disconnectFrom (DSP *target); + FMOD_RESULT F_API disconnectAll (bool inputs, bool outputs); + FMOD_RESULT F_API remove (); + FMOD_RESULT F_API getNumInputs (int *numinputs); + FMOD_RESULT F_API getNumOutputs (int *numoutputs); + FMOD_RESULT F_API getInput (int index, DSP **input, DSPConnection **inputconnection); + FMOD_RESULT F_API getOutput (int index, DSP **output, DSPConnection **outputconnection); + + // DSP unit control. + FMOD_RESULT F_API setActive (bool active); + FMOD_RESULT F_API getActive (bool *active); + FMOD_RESULT F_API setBypass (bool bypass); + FMOD_RESULT F_API getBypass (bool *bypass); + FMOD_RESULT F_API setSpeakerActive (FMOD_SPEAKER speaker, bool active); + FMOD_RESULT F_API getSpeakerActive (FMOD_SPEAKER speaker, bool *active); + FMOD_RESULT F_API reset (); + + + // DSP parameter control. + FMOD_RESULT F_API setParameter (int index, float value); + FMOD_RESULT F_API getParameter (int index, float *value, char *valuestr, int valuestrlen); + FMOD_RESULT F_API getNumParameters (int *numparams); + FMOD_RESULT F_API getParameterInfo (int index, char *name, char *label, char *description, int descriptionlen, float *min, float *max); + FMOD_RESULT F_API showConfigDialog (void *hwnd, bool show); + + // DSP attributes. + FMOD_RESULT F_API getInfo (char *name, unsigned int *version, int *channels, int *configwidth, int *configheight); + FMOD_RESULT F_API getType (FMOD_DSP_TYPE *type); + FMOD_RESULT F_API setDefaults (float frequency, float volume, float pan, int priority); + FMOD_RESULT F_API getDefaults (float *frequency, float *volume, float *pan, int *priority); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + + /* + 'DSPConnection' API + */ + class DSPConnection + { + private: + + DSPConnection(); /* Constructor made private so user cannot statically instance a DSPConnection class. + Appropriate DSPConnection creation or retrieval function must be used. */ + + public: + + FMOD_RESULT F_API getInput (DSP **input); + FMOD_RESULT F_API getOutput (DSP **output); + FMOD_RESULT F_API setMix (float volume); + FMOD_RESULT F_API getMix (float *volume); + FMOD_RESULT F_API setLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + FMOD_RESULT F_API getLevels (FMOD_SPEAKER speaker, float *levels, int numlevels); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + + /* + 'Geometry' API + */ + class Geometry + { + private: + + Geometry(); /* Constructor made private so user cannot statically instance a Geometry class. + Appropriate Geometry creation or retrieval function must be used. */ + + public: + + FMOD_RESULT F_API release (); + + // Polygon manipulation. + FMOD_RESULT F_API addPolygon (float directocclusion, float reverbocclusion, bool doublesided, int numvertices, const FMOD_VECTOR *vertices, int *polygonindex); + FMOD_RESULT F_API getNumPolygons (int *numpolygons); + FMOD_RESULT F_API getMaxPolygons (int *maxpolygons, int *maxvertices); + FMOD_RESULT F_API getPolygonNumVertices (int index, int *numvertices); + FMOD_RESULT F_API setPolygonVertex (int index, int vertexindex, const FMOD_VECTOR *vertex); + FMOD_RESULT F_API getPolygonVertex (int index, int vertexindex, FMOD_VECTOR *vertex); + FMOD_RESULT F_API setPolygonAttributes (int index, float directocclusion, float reverbocclusion, bool doublesided); + FMOD_RESULT F_API getPolygonAttributes (int index, float *directocclusion, float *reverbocclusion, bool *doublesided); + + // Object manipulation. + FMOD_RESULT F_API setActive (bool active); + FMOD_RESULT F_API getActive (bool *active); + FMOD_RESULT F_API setRotation (const FMOD_VECTOR *forward, const FMOD_VECTOR *up); + FMOD_RESULT F_API getRotation (FMOD_VECTOR *forward, FMOD_VECTOR *up); + FMOD_RESULT F_API setPosition (const FMOD_VECTOR *position); + FMOD_RESULT F_API getPosition (FMOD_VECTOR *position); + FMOD_RESULT F_API setScale (const FMOD_VECTOR *scale); + FMOD_RESULT F_API getScale (FMOD_VECTOR *scale); + FMOD_RESULT F_API save (void *data, int *datasize); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; + + + /* + 'Reverb' API + */ + class Reverb + { + private: + + Reverb(); /* Constructor made private so user cannot statically instance a Reverb class. + Appropriate Reverb creation or retrieval function must be used. */ + + public: + + FMOD_RESULT F_API release (); + + // Reverb manipulation. + FMOD_RESULT F_API set3DAttributes (const FMOD_VECTOR *position, float mindistance, float maxdistance); + FMOD_RESULT F_API get3DAttributes (FMOD_VECTOR *position, float *mindistance,float *maxdistance); + FMOD_RESULT F_API setProperties (const FMOD_REVERB_PROPERTIES *properties); + FMOD_RESULT F_API getProperties (FMOD_REVERB_PROPERTIES *properties); + FMOD_RESULT F_API setActive (bool active); + FMOD_RESULT F_API getActive (bool *active); + + // Userdata set/get. + FMOD_RESULT F_API setUserData (void *userdata); + FMOD_RESULT F_API getUserData (void **userdata); + + FMOD_RESULT F_API getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); + }; +} + +#endif diff --git a/engine/fmod-4/inc/fmod_codec.h b/engine/fmod-4/inc/fmod_codec.h new file mode 100644 index 0000000..7f1759a --- /dev/null +++ b/engine/fmod-4/inc/fmod_codec.h @@ -0,0 +1,159 @@ +/* ==================================================================================================== */ +/* FMOD Ex - codec development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* Use this header if you are wanting to develop your own file format plugin to use with */ +/* FMOD's codec system. With this header you can make your own fileformat plugin that FMOD */ +/* can register and use. See the documentation and examples on how to make a working plugin. */ +/* */ +/* ==================================================================================================== */ + +#ifndef _FMOD_CODEC_H +#define _FMOD_CODEC_H + +typedef struct FMOD_CODEC_STATE FMOD_CODEC_STATE; +typedef struct FMOD_CODEC_WAVEFORMAT FMOD_CODEC_WAVEFORMAT; + +/* + Codec callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_OPENCALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_CLOSECALLBACK) (FMOD_CODEC_STATE *codec_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_READCALLBACK) (FMOD_CODEC_STATE *codec_state, void *buffer, unsigned int sizebytes, unsigned int *bytesread); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETLENGTHCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *length, FMOD_TIMEUNIT lengthtype); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, unsigned int position, FMOD_TIMEUNIT postype); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *position, FMOD_TIMEUNIT postype); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SOUNDCREATECALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, FMOD_SOUND *sound); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_METADATACALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_TAGTYPE tagtype, char *name, void *data, unsigned int datalen, FMOD_TAGDATATYPE datatype, int unique); +typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETWAVEFORMAT) (FMOD_CODEC_STATE *codec_state, int index, FMOD_CODEC_WAVEFORMAT *waveformat); + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + When creating a codec, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_CODEC_STATE +] +*/ +typedef struct FMOD_CODEC_DESCRIPTION +{ + const char *name; /* [in] Name of the codec. */ + unsigned int version; /* [in] Plugin writer's version number. */ + int defaultasstream; /* [in] Tells FMOD to open the file as a stream when calling System::createSound, and not a static sample. Should normally be 0 (FALSE), because generally the user wants to decode the file into memory when using System::createSound. Mainly used for formats that decode for a very long time, or could use large amounts of memory when decoded. Usually sequenced formats such as mod/s3m/xm/it/midi fall into this category. It is mainly to stop users that don't know what they're doing from getting FMOD_ERR_MEMORY returned from createSound when they should have in fact called System::createStream or used FMOD_CREATESTREAM in System::createSound. */ + FMOD_TIMEUNIT timeunits; /* [in] When setposition codec is called, only these time formats will be passed to the codec. Use bitwise OR to accumulate different types. */ + FMOD_CODEC_OPENCALLBACK open; /* [in] Open callback for the codec for when FMOD tries to open a sound using this codec. */ + FMOD_CODEC_CLOSECALLBACK close; /* [in] Close callback for the codec for when FMOD tries to close a sound using this codec. */ + FMOD_CODEC_READCALLBACK read; /* [in] Read callback for the codec for when FMOD tries to read some data from the file to the destination format (specified in the open callback). */ + FMOD_CODEC_GETLENGTHCALLBACK getlength; /* [in] Callback to return the length of the song in whatever format required when Sound::getLength is called. */ + FMOD_CODEC_SETPOSITIONCALLBACK setposition; /* [in] Seek callback for the codec for when FMOD tries to seek within the file with Channel::setPosition. */ + FMOD_CODEC_GETPOSITIONCALLBACK getposition; /* [in] Tell callback for the codec for when FMOD tries to get the current position within the with Channel::getPosition. */ + FMOD_CODEC_SOUNDCREATECALLBACK soundcreate; /* [in] Sound creation callback for the codec when FMOD finishes creating the sound. (So the codec can set more parameters for the related created sound, ie loop points/mode or 3D attributes etc). */ + FMOD_CODEC_GETWAVEFORMAT getwaveformat; /* [in] Callback to tell FMOD about the waveformat of a particular subsound. This is to save memory, rather than saving 1000 FMOD_CODEC_WAVEFORMAT structures in the codec, the codec might have a more optimal way of storing this information. */ +} FMOD_CODEC_DESCRIPTION; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Set these values marked 'in' to tell fmod what sort of sound to create. + The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2. + Members marked as 'out' are set by fmod. Do not modify these. Simply specify 0 for these values when declaring the structure, FMOD will fill in the values for you after creation with the correct function pointers. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + An FMOD file might be from disk, memory or network, however the file may be opened by the user. + + 'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF. + 'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), MIDI/MOD/S3M/XM/IT (contain instruments). + The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute. + When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_SOUND_FORMAT + FMOD_FILE_READCALLBACK + FMOD_FILE_SEEKCALLBACK + FMOD_CODEC_METADATACALLBACK + Sound::getSubSound + Sound::getNumSubSounds +] +*/ +struct FMOD_CODEC_WAVEFORMAT +{ + char name[256]; /* [in] Name of sound.*/ + FMOD_SOUND_FORMAT format; /* [in] Format for (decompressed) codec output, ie FMOD_SOUND_FORMAT_PCM8, FMOD_SOUND_FORMAT_PCM16.*/ + int channels; /* [in] Number of channels used by codec, ie mono = 1, stereo = 2. */ + int frequency; /* [in] Default frequency in hz of the codec, ie 44100. */ + unsigned int lengthbytes; /* [in] Length in bytes of the source data. */ + unsigned int lengthpcm; /* [in] Length in decompressed, PCM samples of the file, ie length in seconds * frequency. Used for Sound::getLength and for memory allocation of static decompressed sample data. */ + int blockalign; /* [in] Blockalign in decompressed, PCM samples of the optimal decode chunk size for this format. The codec read callback will be called in multiples of this value. */ + int loopstart; /* [in] Loopstart in decompressed, PCM samples of file. */ + int loopend; /* [in] Loopend in decompressed, PCM samples of file. */ + FMOD_MODE mode; /* [in] Mode to determine whether the sound should by default load as looping, non looping, 2d or 3d. */ + unsigned int channelmask; /* [in] Microsoft speaker channel mask, as defined for WAVEFORMATEXTENSIBLE and is found in ksmedia.h. Leave at 0 to play in natural speaker order. */ +}; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Codec plugin structure that is passed into each callback. + + Set these numsubsounds and waveformat members when called in FMOD_CODEC_OPENCALLBACK to tell fmod what sort of sound to create. + + The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + An FMOD file might be from disk, memory or internet, however the file may be opened by the user. + + 'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF. + 'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), DLS (contain instruments). + The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute. + When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_SOUND_FORMAT + FMOD_FILE_READCALLBACK + FMOD_FILE_SEEKCALLBACK + FMOD_CODEC_METADATACALLBACK + Sound::getSubSound + Sound::getNumSubSounds +] +*/ +struct FMOD_CODEC_STATE +{ + int numsubsounds; /* [in] Number of 'subsounds' in this sound. Anything other than 0 makes it a 'container' format (ie CDDA/DLS/FSB etc which contain 1 or more su bsounds). For most normal, single sound codec such as WAV/AIFF/MP3, this should be 0 as they are not a container for subsounds, they are the sound by itself. */ + FMOD_CODEC_WAVEFORMAT *waveformat; /* [in] Pointer to an array of format structures containing information about each sample. Can be 0 or NULL if FMOD_CODEC_GETWAVEFORMAT callback is preferred. The number of entries here must equal the number of subsounds defined in the subsound parameter. If numsubsounds = 0 then there should be 1 instance of this structure. */ + void *plugindata; /* [in] Plugin writer created data the codec author wants to attach to this object. */ + + void *filehandle; /* [out] This will return an internal FMOD file handle to use with the callbacks provided. */ + unsigned int filesize; /* [out] This will contain the size of the file in bytes. */ + FMOD_FILE_READCALLBACK fileread; /* [out] This will return a callable FMOD file function to use from codec. */ + FMOD_FILE_SEEKCALLBACK fileseek; /* [out] This will return a callable FMOD file function to use from codec. */ + FMOD_CODEC_METADATACALLBACK metadata; /* [out] This will return a callable FMOD metadata function to use from codec. */ +}; + +#endif + + diff --git a/engine/fmod-4/inc/fmod_dsp.h b/engine/fmod-4/inc/fmod_dsp.h new file mode 100644 index 0000000..b8df653 --- /dev/null +++ b/engine/fmod-4/inc/fmod_dsp.h @@ -0,0 +1,746 @@ +/* ========================================================================================== */ +/* FMOD Ex - DSP header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* Use this header if you are interested in delving deeper into the FMOD software mixing / */ +/* DSP engine. In this header you can find parameter structures for FMOD system reigstered */ +/* DSP effects and generators. */ +/* Also use this header if you are wanting to develop your own DSP plugin to use with FMOD's */ +/* dsp system. With this header you can make your own DSP plugin that FMOD can */ +/* register and use. See the documentation and examples on how to make a working plugin. */ +/* */ +/* ========================================================================================== */ + +#ifndef _FMOD_DSP_H +#define _FMOD_DSP_H + +typedef struct FMOD_DSP_STATE FMOD_DSP_STATE; + +/* + DSP callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_CREATECALLBACK) (FMOD_DSP_STATE *dsp_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_RELEASECALLBACK) (FMOD_DSP_STATE *dsp_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_RESETCALLBACK) (FMOD_DSP_STATE *dsp_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_READCALLBACK) (FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_SETPOSITIONCALLBACK)(FMOD_DSP_STATE *dsp_state, unsigned int pos); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_SETPARAMCALLBACK) (FMOD_DSP_STATE *dsp_state, int index, float value); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_GETPARAMCALLBACK) (FMOD_DSP_STATE *dsp_state, int index, float *value, char *valuestr); +typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_DIALOGCALLBACK) (FMOD_DSP_STATE *dsp_state, void *hwnd, int show); + +/* +[ENUM] +[ + [DESCRIPTION] + These definitions can be used for creating FMOD defined special effects or DSP units. + + [REMARKS] + To get them to be active, first create the unit, then add it somewhere into the DSP network, either at the front of the network near the soundcard unit to affect the global output (by using System::getDSPHead), or on a single channel (using Channel::getDSPHead). + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createDSPByType +] +*/ +typedef enum +{ + FMOD_DSP_TYPE_UNKNOWN, /* This unit was created via a non FMOD plugin so has an unknown purpose. */ + FMOD_DSP_TYPE_MIXER, /* This unit does nothing but take inputs and mix them together then feed the result to the soundcard unit. */ + FMOD_DSP_TYPE_OSCILLATOR, /* This unit generates sine/square/saw/triangle or noise tones. */ + FMOD_DSP_TYPE_LOWPASS, /* This unit filters sound using a high quality, resonant lowpass filter algorithm but consumes more CPU time. */ + FMOD_DSP_TYPE_ITLOWPASS, /* This unit filters sound using a resonant lowpass filter algorithm that is used in Impulse Tracker, but with limited cutoff range (0 to 8060hz). */ + FMOD_DSP_TYPE_HIGHPASS, /* This unit filters sound using a resonant highpass filter algorithm. */ + FMOD_DSP_TYPE_ECHO, /* This unit produces an echo on the sound and fades out at the desired rate. */ + FMOD_DSP_TYPE_FLANGE, /* This unit produces a flange effect on the sound. */ + FMOD_DSP_TYPE_DISTORTION, /* This unit distorts the sound. */ + FMOD_DSP_TYPE_NORMALIZE, /* This unit normalizes or amplifies the sound to a certain level. */ + FMOD_DSP_TYPE_PARAMEQ, /* This unit attenuates or amplifies a selected frequency range. */ + FMOD_DSP_TYPE_PITCHSHIFT, /* This unit bends the pitch of a sound without changing the speed of playback. */ + FMOD_DSP_TYPE_CHORUS, /* This unit produces a chorus effect on the sound. */ + FMOD_DSP_TYPE_VSTPLUGIN, /* This unit allows the use of Steinberg VST plugins */ + FMOD_DSP_TYPE_WINAMPPLUGIN, /* This unit allows the use of Nullsoft Winamp plugins */ + FMOD_DSP_TYPE_ITECHO, /* This unit produces an echo on the sound and fades out at the desired rate as is used in Impulse Tracker. */ + FMOD_DSP_TYPE_COMPRESSOR, /* This unit implements dynamic compression (linked multichannel, wideband) */ + FMOD_DSP_TYPE_SFXREVERB, /* This unit implements SFX reverb */ + FMOD_DSP_TYPE_LOWPASS_SIMPLE, /* This unit filters sound using a simple lowpass with no resonance, but has flexible cutoff and is fast. */ + FMOD_DSP_TYPE_DELAY, /* This unit produces different delays on individual channels of the sound. */ + FMOD_DSP_TYPE_TREMOLO, /* This unit produces a tremolo / chopper effect on the sound. */ + FMOD_DSP_TYPE_LADSPAPLUGIN, /* This unit allows the use of LADSPA standard plugins. */ + FMOD_DSP_TYPE_HIGHPASS_SIMPLE, /* This unit filters sound using a simple highpass with no resonance, but has flexible cutoff and is fast. */ + FMOD_DSP_TYPE_HARDWARE = 1000, /* Offset that platform specific FMOD_HARDWARE DSPs will start at. */ + FMOD_DSP_TYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ +} FMOD_DSP_TYPE; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure to define a parameter for a DSP unit. + + [REMARKS] + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + Members marked with [w] mean the variable can be written to. The user can set the value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createDSP + DSP::setParameter +] +*/ +typedef struct FMOD_DSP_PARAMETERDESC +{ + float min; /* [w] Minimum value of the parameter (ie 100.0). */ + float max; /* [w] Maximum value of the parameter (ie 22050.0). */ + float defaultval; /* [w] Default value of parameter. */ + char name[16]; /* [w] Name of the parameter to be displayed (ie "Cutoff frequency"). */ + char label[16]; /* [w] Short string to be put next to value to denote the unit type (ie "hz"). */ + const char *description; /* [w] Description of the parameter to be displayed as a help item / tooltip for this parameter. */ +} FMOD_DSP_PARAMETERDESC; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + When creating a DSP unit, declare one of these and provide the relevant callbacks and name for FMOD to use when it creates and uses a DSP unit of this type. + + [REMARKS] + + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + Members marked with [w] mean the variable can be written to. The user can set the value. + + IMPORTANT: The 'paramdesc' member should point to static memory, as FMOD references the data internally using the pointer provided. Do not store these parameter description structures on the stack, or in heap memory that is freed while FMOD is using it. + + There are 2 different ways to change a parameter in this architecture. + One is to use DSP::setParameter / DSP::getParameter. This is platform independant and is dynamic, so new unknown plugins can have their parameters enumerated and used. + The other is to use DSP::showConfigDialog. This is platform specific and requires a GUI, and will display a dialog box to configure the plugin. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::createDSP + FMOD_DSP_STATE +] +*/ +typedef struct FMOD_DSP_DESCRIPTION +{ + char name[32]; /* [w] Name of the unit to be displayed in the network. */ + unsigned int version; /* [w] Plugin writer's version number. */ + int channels; /* [w] Number of channels. Use 0 to process whatever number of channels is currently in the network. >0 would be mostly used if the unit is a unit that only generates sound. */ + FMOD_DSP_CREATECALLBACK create; /* [w] Create callback. This is called when DSP unit is created. Can be null. */ + FMOD_DSP_RELEASECALLBACK release; /* [w] Release callback. This is called just before the unit is freed so the user can do any cleanup needed for the unit. Can be null. */ + FMOD_DSP_RESETCALLBACK reset; /* [w] Reset callback. This is called by the user to reset any history buffers that may need resetting for a filter, when it is to be used or re-used for the first time to its initial clean state. Use to avoid clicks or artifacts. */ + FMOD_DSP_READCALLBACK read; /* [w] Read callback. Processing is done here. Can be null. */ + FMOD_DSP_SETPOSITIONCALLBACK setposition; /* [w] Set position callback. This is called if the unit wants to update its position info but not process data, or reset a cursor position internally if it is reading data from a certain source. Can be null. */ + + int numparameters; /* [w] Number of parameters used in this filter. The user finds this with DSP::getNumParameters */ + FMOD_DSP_PARAMETERDESC *paramdesc; /* [w] Variable number of parameter structures. */ + FMOD_DSP_SETPARAMCALLBACK setparameter; /* [w] This is called when the user calls DSP::setParameter. Can be null. */ + FMOD_DSP_GETPARAMCALLBACK getparameter; /* [w] This is called when the user calls DSP::getParameter. Can be null. */ + FMOD_DSP_DIALOGCALLBACK config; /* [w] This is called when the user calls DSP::showConfigDialog. Can be used to display a dialog to configure the filter. Can be null. */ + int configwidth; /* [w] Width of config dialog graphic if there is one. 0 otherwise.*/ + int configheight; /* [w] Height of config dialog graphic if there is one. 0 otherwise.*/ + void *userdata; /* [w] Optional. Specify 0 to ignore. This is user data to be attached to the DSP unit during creation. Access via DSP::getUserData. */ +} FMOD_DSP_DESCRIPTION; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + DSP plugin structure that is passed into each callback. + + [REMARKS] + Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + Members marked with [w] mean the variable can be written to. The user can set the value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_DSP_DESCRIPTION +] +*/ +struct FMOD_DSP_STATE +{ + FMOD_DSP *instance; /* [r] Handle to the DSP hand the user created. Not to be modified. C++ users cast to FMOD::DSP to use. */ + void *plugindata; /* [w] Plugin writer created data the output author wants to attach to this object. */ + unsigned short speakermask; /* [w] Specifies which speakers the DSP effect is active on */ +}; + + +/* + =================================================================================================== + + FMOD built in effect parameters. + Use DSP::setParameter with these enums for the 'index' parameter. + + =================================================================================================== +*/ + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_OSCILLATOR filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_OSCILLATOR_TYPE, /* Waveform type. 0 = sine. 1 = square. 2 = sawup. 3 = sawdown. 4 = triangle. 5 = noise. */ + FMOD_DSP_OSCILLATOR_RATE /* Frequency of the sinewave in hz. 1.0 to 22000.0. Default = 220.0. */ +} FMOD_DSP_OSCILLATOR; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_LOWPASS filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_LOWPASS_CUTOFF, /* Lowpass cutoff frequency in hz. 10.0 to 22000.0. Default = 5000.0. */ + FMOD_DSP_LOWPASS_RESONANCE /* Lowpass resonance Q value. 1.0 to 10.0. Default = 1.0. */ +} FMOD_DSP_LOWPASS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ITLOWPASS filter. + This is different to the default FMOD_DSP_TYPE_ITLOWPASS filter in that it uses a different quality algorithm and is + the filter used to produce the correct sounding playback in .IT files. + FMOD Ex's .IT playback uses this filter. + + [REMARKS] + Note! This filter actually has a limited cutoff frequency below the specified maximum, due to its limited design, + so for a more open range filter use FMOD_DSP_LOWPASS or if you don't mind not having resonance, + FMOD_DSP_LOWPASS_SIMPLE. + The effective maximum cutoff is about 8060hz. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_ITLOWPASS_CUTOFF, /* Lowpass cutoff frequency in hz. 1.0 to 22000.0. Default = 5000.0/ */ + FMOD_DSP_ITLOWPASS_RESONANCE /* Lowpass resonance Q value. 0.0 to 127.0. Default = 1.0. */ +} FMOD_DSP_ITLOWPASS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_HIGHPASS filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_HIGHPASS_CUTOFF, /* Highpass cutoff frequency in hz. 1.0 to output 22000.0. Default = 5000.0. */ + FMOD_DSP_HIGHPASS_RESONANCE /* Highpass resonance Q value. 1.0 to 10.0. Default = 1.0. */ +} FMOD_DSP_HIGHPASS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ECHO filter. + + [REMARKS] + Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer. + Larger echo delays result in larger amounts of memory allocated. + + 'maxchannels' also dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the echo unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel echo, etc. + If the echo effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes. + When the echo is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count. + If a channel echo is set to a lower number than the sound's channel count that is coming in, it will not echo the sound. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_ECHO_DELAY, /* Echo delay in ms. 10 to 5000. Default = 500. */ + FMOD_DSP_ECHO_DECAYRATIO, /* Echo decay per delay. 0 to 1. 1.0 = No decay, 0.0 = total decay (ie simple 1 line delay). Default = 0.5. */ + FMOD_DSP_ECHO_MAXCHANNELS, /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */ + FMOD_DSP_ECHO_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 1.0. */ + FMOD_DSP_ECHO_WETMIX /* Volume of echo signal to pass to output. 0.0 to 1.0. Default = 1.0. */ +} FMOD_DSP_ECHO; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_DELAY filter. + + [REMARKS] + Note. Every time MaxDelay is changed, the plugin re-allocates the delay buffer. This means the delay will dissapear at that time while it refills its new buffer. + A larger MaxDelay results in larger amounts of memory allocated. + Channel delays above MaxDelay will be clipped to MaxDelay and the delay buffer will not be resized. + + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_DELAY_CH0, /* Channel #0 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH1, /* Channel #1 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH2, /* Channel #2 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH3, /* Channel #3 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH4, /* Channel #4 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH5, /* Channel #5 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH6, /* Channel #6 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH7, /* Channel #7 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH8, /* Channel #8 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH9, /* Channel #9 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH10, /* Channel #10 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH11, /* Channel #11 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH12, /* Channel #12 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH13, /* Channel #13 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH14, /* Channel #14 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_CH15, /* Channel #15 Delay in ms. 0 to 10000. Default = 0. */ + FMOD_DSP_DELAY_MAXDELAY /* Maximum delay in ms. 0 to 10000. Default = 10. */ +} FMOD_DSP_DELAY; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_FLANGE filter. + + [REMARKS] + Flange is an effect where the signal is played twice at the same time, and one copy slides back and forth creating a whooshing or flanging effect. + As there are 2 copies of the same signal, by default each signal is given 50% mix, so that the total is not louder than the original unaffected signal. + + Flange depth is a percentage of a 10ms shift from the original signal. Anything above 10ms is not considered flange because to the ear it begins to 'echo' so 10ms is the highest value possible. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_FLANGE_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.45. */ + FMOD_DSP_FLANGE_WETMIX, /* Volume of flange signal to pass to output. 0.0 to 1.0. Default = 0.55. */ + FMOD_DSP_FLANGE_DEPTH, /* Flange depth (percentage of 40ms delay). 0.01 to 1.0. Default = 1.0. */ + FMOD_DSP_FLANGE_RATE /* Flange speed in hz. 0.0 to 20.0. Default = 0.1. */ +} FMOD_DSP_FLANGE; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_TREMOLO filter. + + [REMARKS] + The tremolo effect varies the amplitude of a sound. Depending on the settings, this unit can produce a tremolo, chopper or auto-pan effect. + + The shape of the LFO (low freq. oscillator) can morphed between sine, triangle and sawtooth waves using the FMOD_DSP_TREMOLO_SHAPE and FMOD_DSP_TREMOLO_SKEW parameters. + FMOD_DSP_TREMOLO_DUTY and FMOD_DSP_TREMOLO_SQUARE are useful for a chopper-type effect where the first controls the on-time duration and second controls the flatness of the envelope. + FMOD_DSP_TREMOLO_SPREAD varies the LFO phase between channels to get an auto-pan effect. This works best with a sine shape LFO. + The LFO can be synchronized using the FMOD_DSP_TREMOLO_PHASE parameter which sets its instantaneous phase. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_TREMOLO_FREQUENCY, /* LFO frequency in Hz. 0.1 to 20. Default = 4. */ + FMOD_DSP_TREMOLO_DEPTH, /* Tremolo depth. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_SHAPE, /* LFO shape morph between triangle and sine. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_SKEW, /* Time-skewing of LFO cycle. -1 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_DUTY, /* LFO on-time. 0 to 1. Default = 0.5. */ + FMOD_DSP_TREMOLO_SQUARE, /* Flatness of the LFO shape. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_PHASE, /* Instantaneous LFO phase. 0 to 1. Default = 0. */ + FMOD_DSP_TREMOLO_SPREAD /* Rotation / auto-pan effect. -1 to 1. Default = 0. */ +} FMOD_DSP_TREMOLO; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_DISTORTION filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_DISTORTION_LEVEL /* Distortion value. 0.0 to 1.0. Default = 0.5. */ +} FMOD_DSP_DISTORTION; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_NORMALIZE filter. + + [REMARKS] + Normalize amplifies the sound based on the maximum peaks within the signal. + For example if the maximum peaks in the signal were 50% of the bandwidth, it would scale the whole sound by 2. + The lower threshold value makes the normalizer ignores peaks below a certain point, to avoid over-amplification if a loud signal suddenly came in, and also to avoid amplifying to maximum things like background hiss. + + Because FMOD is a realtime audio processor, it doesn't have the luxury of knowing the peak for the whole sound (ie it can't see into the future), so it has to process data as it comes in. + To avoid very sudden changes in volume level based on small samples of new data, fmod fades towards the desired amplification which makes for smooth gain control. The fadetime parameter can control this. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_NORMALIZE_FADETIME, /* Time to ramp the silence to full in ms. 0.0 to 20000.0. Default = 5000.0. */ + FMOD_DSP_NORMALIZE_THRESHHOLD, /* Lower volume range threshold to ignore. 0.0 to 1.0. Default = 0.1. Raise higher to stop amplification of very quiet signals. */ + FMOD_DSP_NORMALIZE_MAXAMP /* Maximum amplification allowed. 1.0 to 100000.0. Default = 20.0. 1.0 = no amplifaction, higher values allow more boost. */ +} FMOD_DSP_NORMALIZE; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_PARAMEQ filter. + + [REMARKS] + Parametric EQ is a bandpass filter that attenuates or amplifies a selected frequency and its neighbouring frequencies. + + To create a multi-band EQ create multiple FMOD_DSP_TYPE_PARAMEQ units and set each unit to different frequencies, for example 1000hz, 2000hz, 4000hz, 8000hz, 16000hz with a range of 1 octave each. + + When a frequency has its gain set to 1.0, the sound will be unaffected and represents the original signal exactly. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_PARAMEQ_CENTER, /* Frequency center. 20.0 to 22000.0. Default = 8000.0. */ + FMOD_DSP_PARAMEQ_BANDWIDTH, /* Octave range around the center frequency to filter. 0.2 to 5.0. Default = 1.0. */ + FMOD_DSP_PARAMEQ_GAIN /* Frequency Gain. 0.05 to 3.0. Default = 1.0. */ +} FMOD_DSP_PARAMEQ; + + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_PITCHSHIFT filter. + + [REMARKS] + This pitch shifting unit can be used to change the pitch of a sound without speeding it up or slowing it down. + It can also be used for time stretching or scaling, for example if the pitch was doubled, and the frequency of the sound was halved, the pitch of the sound would sound correct but it would be twice as slow. + + Warning! This filter is very computationally expensive! Similar to a vocoder, it requires several overlapping FFT and IFFT's to produce smooth output, and can require around 440mhz for 1 stereo 48khz signal using the default settings. + Reducing the signal to mono will half the cpu usage. + Reducing this will lower audio quality, but what settings to use are largely dependant on the sound being played. A noisy polyphonic signal will need higher fft size compared to a speaking voice for example. + + This pitch shifter is based on the pitch shifter code at http://www.dspdimension.com, written by Stephan M. Bernsee. + The original code is COPYRIGHT 1999-2003 Stephan M. Bernsee . + + 'maxchannels' dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the pitch shift unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel pitch shift, etc. + If the pitch shift effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes. + When the pitch shift is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count. + If a channel pitch shift is set to a lower number than the sound's channel count that is coming in, it will not pitch shift the sound. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_PITCHSHIFT_PITCH, /* Pitch value. 0.5 to 2.0. Default = 1.0. 0.5 = one octave down, 2.0 = one octave up. 1.0 does not change the pitch. */ + FMOD_DSP_PITCHSHIFT_FFTSIZE, /* FFT window size. 256, 512, 1024, 2048, 4096. Default = 1024. Increase this to reduce 'smearing'. This effect is a warbling sound similar to when an mp3 is encoded at very low bitrates. */ + FMOD_DSP_PITCHSHIFT_OVERLAP, /* Removed. Do not use. FMOD now uses 4 overlaps and cannot be changed. */ + FMOD_DSP_PITCHSHIFT_MAXCHANNELS /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */ +} FMOD_DSP_PITCHSHIFT; + + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_CHORUS filter. + + [REMARKS] + Chrous is an effect where the sound is more 'spacious' due to 1 to 3 versions of the sound being played along side the original signal but with the pitch of each copy modulating on a sine wave. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_CHORUS_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_WETMIX1, /* Volume of 1st chorus tap. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_WETMIX2, /* Volume of 2nd chorus tap. This tap is 90 degrees out of phase of the first tap. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_WETMIX3, /* Volume of 3rd chorus tap. This tap is 90 degrees out of phase of the second tap. 0.0 to 1.0. Default = 0.5. */ + FMOD_DSP_CHORUS_DELAY, /* Chorus delay in ms. 0.1 to 100.0. Default = 40.0 ms. */ + FMOD_DSP_CHORUS_RATE, /* Chorus modulation rate in hz. 0.0 to 20.0. Default = 0.8 hz. */ + FMOD_DSP_CHORUS_DEPTH /* Chorus modulation depth. 0.0 to 1.0. Default = 0.03. */ +} FMOD_DSP_CHORUS; + + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ITECHO filter. + This is effectively a software based echo filter that emulates the DirectX DMO echo effect. Impulse tracker files can support this, and FMOD will produce the effect on ANY platform, not just those that support DirectX effects! + + [REMARKS] + Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer. + Larger echo delays result in larger amounts of memory allocated. + + As this is a stereo filter made mainly for IT playback, it is targeted for stereo signals. + With mono signals only the FMOD_DSP_ITECHO_LEFTDELAY is used. + For multichannel signals (>2) there will be no echo on those channels. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::SetParameter + DSP::GetParameter + FMOD_DSP_TYPE + System::addDSP +] +*/ +typedef enum +{ + FMOD_DSP_ITECHO_WETDRYMIX, /* Ratio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0.0 through 100.0 (all wet). The default value is 50. */ + FMOD_DSP_ITECHO_FEEDBACK, /* Percentage of output fed back into input, in the range from 0.0 through 100.0. The default value is 50. */ + FMOD_DSP_ITECHO_LEFTDELAY, /* Delay for left channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */ + FMOD_DSP_ITECHO_RIGHTDELAY, /* Delay for right channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */ + FMOD_DSP_ITECHO_PANDELAY /* Value that specifies whether to swap left and right delays with each successive echo. The default value is zero, meaning no swap. Possible values are defined as 0.0 (equivalent to FALSE) and 1.0 (equivalent to TRUE). CURRENTLY NOT SUPPORTED. */ +} FMOD_DSP_ITECHO; + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_COMPRESSOR unit. + This is a simple linked multichannel software limiter that is uniform across the whole spectrum. + + [REMARKS] + The limiter is not guaranteed to catch every peak above the threshold level, + because it cannot apply gain reduction instantaneously - the time delay is + determined by the attack time. However setting the attack time too short will + distort the sound, so it is a compromise. High level peaks can be avoided by + using a short attack time - but not too short, and setting the threshold a few + decibels below the critical level. + + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::SetParameter + DSP::GetParameter + FMOD_DSP_TYPE + System::addDSP +] +*/ +typedef enum +{ + FMOD_DSP_COMPRESSOR_THRESHOLD, /* Threshold level (dB) in the range from -60 through 0. The default value is 0. */ + FMOD_DSP_COMPRESSOR_ATTACK, /* Gain reduction attack time (milliseconds), in the range from 10 through 200. The default value is 50. */ + FMOD_DSP_COMPRESSOR_RELEASE, /* Gain reduction release time (milliseconds), in the range from 20 through 1000. The default value is 50. */ + FMOD_DSP_COMPRESSOR_GAINMAKEUP /* Make-up gain (dB) applied after limiting, in the range from 0 through 30. The default value is 0. */ +} FMOD_DSP_COMPRESSOR; + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_SFXREVERB unit. + + [REMARKS] + This is a high quality I3DL2 based reverb. + On top of the I3DL2 property set, "Dry Level" is also included to allow the dry mix to be changed. + + These properties can be set with presets in FMOD_REVERB_PRESETS. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::SetParameter + DSP::GetParameter + FMOD_DSP_TYPE + System::addDSP + FMOD_REVERB_PRESETS +] +*/ +typedef enum +{ + FMOD_DSP_SFXREVERB_DRYLEVEL, /* Dry Level : Mix level of dry signal in output in mB. Ranges from -10000.0 to 0.0. Default is 0. */ + FMOD_DSP_SFXREVERB_ROOM, /* Room : Room effect level at low frequencies in mB. Ranges from -10000.0 to 0.0. Default is -10000.0. */ + FMOD_DSP_SFXREVERB_ROOMHF, /* Room HF : Room effect high-frequency level re. low frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ + FMOD_DSP_SFXREVERB_DECAYTIME, /* Decay Time : Reverberation decay time at low-frequencies in seconds. Ranges from 0.1 to 20.0. Default is 1.0. */ + FMOD_DSP_SFXREVERB_DECAYHFRATIO, /* Decay HF Ratio : High-frequency to low-frequency decay time ratio. Ranges from 0.1 to 2.0. Default is 0.5. */ + FMOD_DSP_SFXREVERB_REFLECTIONSLEVEL, /* Reflections : Early reflections level relative to room effect in mB. Ranges from -10000.0 to 1000.0. Default is -10000.0. */ + FMOD_DSP_SFXREVERB_REFLECTIONSDELAY, /* Reflect Delay : Delay time of first reflection in seconds. Ranges from 0.0 to 0.3. Default is 0.02. */ + FMOD_DSP_SFXREVERB_REVERBLEVEL, /* Reverb : Late reverberation level relative to room effect in mB. Ranges from -10000.0 to 2000.0. Default is 0.0. */ + FMOD_DSP_SFXREVERB_REVERBDELAY, /* Reverb Delay : Late reverberation delay time relative to first reflection in seconds. Ranges from 0.0 to 0.1. Default is 0.04. */ + FMOD_DSP_SFXREVERB_DIFFUSION, /* Diffusion : Reverberation diffusion (echo density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */ + FMOD_DSP_SFXREVERB_DENSITY, /* Density : Reverberation density (modal density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */ + FMOD_DSP_SFXREVERB_HFREFERENCE, /* HF Reference : Reference high frequency in Hz. Ranges from 20.0 to 20000.0. Default is 5000.0. */ + FMOD_DSP_SFXREVERB_ROOMLF, /* Room LF : Room effect low-frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ + FMOD_DSP_SFXREVERB_LFREFERENCE /* LF Reference : Reference low-frequency in Hz. Ranges from 20.0 to 1000.0. Default is 250.0. */ +} FMOD_DSP_SFXREVERB; + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_LOWPASS_SIMPLE filter. + This is a very simple low pass filter, based on two single-pole RC time-constant modules. + The emphasis is on speed rather than accuracy, so this should not be used for task requiring critical filtering. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_LOWPASS_SIMPLE_CUTOFF /* Lowpass cutoff frequency in hz. 10.0 to 22000.0. Default = 5000.0 */ +} FMOD_DSP_LOWPASS_SIMPLE; + +/* +[ENUM] +[ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_HIGHPASS_SIMPLE filter. + This is a very simple single-order high pass filter. + The emphasis is on speed rather than accuracy, so this should not be used for task requiring critical filtering. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE +] +*/ +typedef enum +{ + FMOD_DSP_HIGHPASS_SIMPLE_CUTOFF /* Highpass cutoff frequency in hz. 10.0 to 22000.0. Default = 1000.0 */ +} FMOD_DSP_HIGHPASS_SIMPLE; + +#endif + diff --git a/engine/fmod-4/inc/fmod_errors.h b/engine/fmod-4/inc/fmod_errors.h new file mode 100644 index 0000000..20cf9e8 --- /dev/null +++ b/engine/fmod-4/inc/fmod_errors.h @@ -0,0 +1,123 @@ + +/* ============================================================================================== */ +/* FMOD Ex - Error string header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* Use this header if you want to store or display a string version / english explanation of */ +/* the FMOD error codes. */ +/* */ +/* ============================================================================================== */ + +#ifndef _FMOD_ERRORS_H +#define _FMOD_ERRORS_H + +#include "fmod.h" + +#ifdef __GNUC__ +static const char *FMOD_ErrorString(FMOD_RESULT errcode) __attribute__((unused)); +#endif + +static const char *FMOD_ErrorString(FMOD_RESULT errcode) +{ + switch (errcode) + { + case FMOD_ERR_ALREADYLOCKED: return "Tried to call lock a second time before unlock was called. "; + case FMOD_ERR_BADCOMMAND: return "Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). "; + case FMOD_ERR_CDDA_DRIVERS: return "Neither NTSCSI nor ASPI could be initialised. "; + case FMOD_ERR_CDDA_INIT: return "An error occurred while initialising the CDDA subsystem. "; + case FMOD_ERR_CDDA_INVALID_DEVICE: return "Couldn't find the specified device. "; + case FMOD_ERR_CDDA_NOAUDIO: return "No audio tracks on the specified disc. "; + case FMOD_ERR_CDDA_NODEVICES: return "No CD/DVD devices were found. "; + case FMOD_ERR_CDDA_NODISC: return "No disc present in the specified drive. "; + case FMOD_ERR_CDDA_READ: return "A CDDA read error occurred. "; + case FMOD_ERR_CHANNEL_ALLOC: return "Error trying to allocate a channel. "; + case FMOD_ERR_CHANNEL_STOLEN: return "The specified channel has been reused to play another sound. "; + case FMOD_ERR_COM: return "A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. "; + case FMOD_ERR_DMA: return "DMA Failure. See debug output for more information. "; + case FMOD_ERR_DSP_CONNECTION: return "DSP connection error. Connection possibly caused a cyclic dependancy. Or tried to connect a tree too many units deep (more than 128). "; + case FMOD_ERR_DSP_FORMAT: return "DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. "; + case FMOD_ERR_DSP_NOTFOUND: return "DSP connection error. Couldn't find the DSP unit specified. "; + case FMOD_ERR_DSP_RUNNING: return "DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. "; + case FMOD_ERR_DSP_TOOMANYCONNECTIONS: return "DSP connection error. The unit being connected to or disconnected should only have 1 input or output. "; + case FMOD_ERR_EVENT_ALREADY_LOADED: return "The specified project or bank has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. "; + case FMOD_ERR_EVENT_FAILED: return "An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. "; + case FMOD_ERR_EVENT_GUIDCONFLICT: return "An event with the same GUID already exists. "; + case FMOD_ERR_EVENT_INFOONLY: return "Can't execute this command on an EVENT_INFOONLY event. "; + case FMOD_ERR_EVENT_INTERNAL: return "An error occured that wasn't supposed to. See debug log for reason. "; + case FMOD_ERR_EVENT_MAXSTREAMS: return "Event failed because 'Max streams' was hit when FMOD_EVENT_INIT_FAIL_ON_MAXSTREAMS was specified. "; + case FMOD_ERR_EVENT_MISMATCH: return "FSB mismatches the FEV it was compiled with, the stream/sample mode it was meant to be created with was different, or the FEV was built for a different platform. "; + case FMOD_ERR_EVENT_NAMECONFLICT: return "A category with the same name already exists. "; + case FMOD_ERR_EVENT_NEEDSSIMPLE: return "Tried to call a function on a complex event that's only supported by simple events. "; + case FMOD_ERR_EVENT_NOTFOUND: return "The requested event, event group, event category or event property could not be found. "; + case FMOD_ERR_FILE_BAD: return "Error loading file. "; + case FMOD_ERR_FILE_COULDNOTSEEK: return "Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. "; + case FMOD_ERR_FILE_DISKEJECTED: return "Media was ejected while reading. "; + case FMOD_ERR_FILE_EOF: return "End of file unexpectedly reached while trying to read essential data (truncated data?). "; + case FMOD_ERR_FILE_NOTFOUND: return "File not found. "; + case FMOD_ERR_FILE_UNWANTED: return "Unwanted file access occured. "; + case FMOD_ERR_FORMAT: return "Unsupported file or audio format. "; + case FMOD_ERR_HTTP: return "A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. "; + case FMOD_ERR_HTTP_ACCESS: return "The specified resource requires authentication or is forbidden. "; + case FMOD_ERR_HTTP_PROXY_AUTH: return "Proxy authentication is required to access the specified resource. "; + case FMOD_ERR_HTTP_SERVER_ERROR: return "A HTTP server error occurred. "; + case FMOD_ERR_HTTP_TIMEOUT: return "The HTTP request timed out. "; + case FMOD_ERR_INITIALIZATION: return "FMOD was not initialized correctly to support this function. "; + case FMOD_ERR_INITIALIZED: return "Cannot call this command after System::init. "; + case FMOD_ERR_INTERNAL: return "An error occured that wasn't supposed to. Contact support. "; + case FMOD_ERR_INVALID_ADDRESS: return "On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) "; + case FMOD_ERR_INVALID_FLOAT: return "Value passed in was a NaN, Inf or denormalized float. "; + case FMOD_ERR_INVALID_HANDLE: return "An invalid object handle was used. "; + case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function. "; + case FMOD_ERR_INVALID_POSITION: return "An invalid seek position was passed to this function. "; + case FMOD_ERR_INVALID_SPEAKER: return "An invalid speaker was passed to this function based on the current speaker mode. "; + case FMOD_ERR_INVALID_SYNCPOINT: return "The syncpoint did not come from this sound handle. "; + case FMOD_ERR_INVALID_VECTOR: return "The vectors passed in are not unit length, or perpendicular. "; + case FMOD_ERR_MAXAUDIBLE: return "Reached maximum audible playback count for this sound's soundgroup. "; + case FMOD_ERR_MEMORY: return "Not enough memory or resources. "; + case FMOD_ERR_MEMORY_CANTPOINT: return "Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. "; + case FMOD_ERR_MEMORY_SRAM: return "Not enough memory or resources on console sound ram. "; + case FMOD_ERR_MUSIC_NOCALLBACK: return "The music callback is required, but it has not been set. "; + case FMOD_ERR_MUSIC_NOTFOUND: return "The requested music entity could not be found. "; + case FMOD_ERR_MUSIC_UNINITIALIZED: return "Music system is not initialized probably because no music data is loaded. "; + case FMOD_ERR_NEEDS2D: return "Tried to call a command on a 3d sound when the command was meant for 2d sound. "; + case FMOD_ERR_NEEDS3D: return "Tried to call a command on a 2d sound when the command was meant for 3d sound. "; + case FMOD_ERR_NEEDSHARDWARE: return "Tried to use a feature that requires hardware support. (ie trying to play a GCADPCM compressed sound in software on Wii). "; + case FMOD_ERR_NEEDSSOFTWARE: return "Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. "; + case FMOD_ERR_NET_CONNECT: return "Couldn't connect to the specified host. "; + case FMOD_ERR_NET_SOCKET_ERROR: return "A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. "; + case FMOD_ERR_NET_URL: return "The specified URL couldn't be resolved. "; + case FMOD_ERR_NET_WOULD_BLOCK: return "Operation on a non-blocking socket could not complete immediately. "; + case FMOD_ERR_NOTREADY: return "Operation could not be performed because specified sound/DSP connection is not ready. "; + case FMOD_ERR_OUTPUT_ALLOCATED: return "Error initializing output device, but more specifically, the output device is already in use and cannot be reused. "; + case FMOD_ERR_OUTPUT_CREATEBUFFER: return "Error creating hardware sound buffer. "; + case FMOD_ERR_OUTPUT_DRIVERCALL: return "A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. "; + case FMOD_ERR_OUTPUT_ENUMERATION: return "Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal. "; + case FMOD_ERR_OUTPUT_FORMAT: return "Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). "; + case FMOD_ERR_OUTPUT_INIT: return "Error initializing output device. "; + case FMOD_ERR_OUTPUT_NOHARDWARE: return "FMOD_HARDWARE was specified but the sound card does not have the resources necessary to play it. "; + case FMOD_ERR_OUTPUT_NOSOFTWARE: return "Attempted to create a software sound but no software channels were specified in System::init. "; + case FMOD_ERR_PAN: return "Panning only works with mono or stereo sound sources. "; + case FMOD_ERR_PLUGIN: return "An unspecified error has been returned from a 3rd party plugin. "; + case FMOD_ERR_PLUGIN_INSTANCES: return "The number of allowed instances of a plugin has been exceeded. "; + case FMOD_ERR_PLUGIN_MISSING: return "A requested output, dsp unit type or codec was not available. "; + case FMOD_ERR_PLUGIN_RESOURCE: return "A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback or other DLLs that it needs to load) "; + case FMOD_ERR_PRELOADED: return "The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. "; + case FMOD_ERR_PROGRAMMERSOUND: return "The specified sound is still in use by the event system, wait for the event which is using it finish with it. "; + case FMOD_ERR_RECORD: return "An error occured trying to initialize the recording device. "; + case FMOD_ERR_REVERB_INSTANCE: return "Specified instance in FMOD_REVERB_PROPERTIES couldn't be set. Most likely because it is an invalid instance number or the reverb doesnt exist. "; + case FMOD_ERR_SUBSOUNDS: return "The error occured because the sound referenced contains subsounds when it shouldn't have, or it doesn't contain subsounds when it should have. The operation may also not be able to be performed on a parent sound, or a parent sound was played without setting up a sentence first. "; + case FMOD_ERR_SUBSOUND_ALLOCATED: return "This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. "; + case FMOD_ERR_SUBSOUND_CANTMOVE: return "Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file. "; + case FMOD_ERR_SUBSOUND_MODE: return "The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with. "; + case FMOD_ERR_TAGNOTFOUND: return "The specified tag could not be found or there are no tags. "; + case FMOD_ERR_TOOMANYCHANNELS: return "The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. "; + case FMOD_ERR_UNIMPLEMENTED: return "Something in FMOD hasn't been implemented when it should be! contact support! "; + case FMOD_ERR_UNINITIALIZED: return "This command failed because System::init or System::setDriver was not called. "; + case FMOD_ERR_UNSUPPORTED: return "A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. "; + case FMOD_ERR_UPDATE: return "An error caused by System::update occured. "; + case FMOD_ERR_VERSION: return "The version number of this file format is not supported. "; + case FMOD_OK: return "No errors."; + default : return "Unknown error."; + }; +} + +#endif diff --git a/engine/fmod-4/inc/fmod_memoryinfo.h b/engine/fmod-4/inc/fmod_memoryinfo.h new file mode 100644 index 0000000..7b7eea9 --- /dev/null +++ b/engine/fmod-4/inc/fmod_memoryinfo.h @@ -0,0 +1,201 @@ +/* ============================================================================================= */ +/* FMOD Ex - Memory info header file. Copyright (c), Firelight Technologies Pty, Ltd. 2008-2016. */ +/* */ +/* Use this header if you are interested in getting detailed information on FMOD's memory */ +/* usage. See the documentation for more details. */ +/* */ +/* ============================================================================================= */ + +#ifndef _FMOD_MEMORYINFO_H +#define _FMOD_MEMORYINFO_H + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure to be filled with detailed memory usage information of an FMOD object + + [REMARKS] + Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + On return from getMemoryInfo, each member of this structure will hold the amount of memory used for its type in bytes. + + Members marked with [in] mean the user sets the value before passing it to the function. + Members marked with [out] mean FMOD sets the value to be used after the function exits. + + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + System::getMemoryInfo + EventSystem::getMemoryInfo + FMOD_MEMBITS + FMOD_EVENT_MEMBITS +] +*/ +typedef struct FMOD_MEMORY_USAGE_DETAILS +{ + unsigned int other; /* [out] Memory not accounted for by other types */ + unsigned int string; /* [out] String data */ + unsigned int system; /* [out] System object and various internals */ + unsigned int plugins; /* [out] Plugin objects and internals */ + unsigned int output; /* [out] Output module object and internals */ + unsigned int channel; /* [out] Channel related memory */ + unsigned int channelgroup; /* [out] ChannelGroup objects and internals */ + unsigned int codec; /* [out] Codecs allocated for streaming */ + unsigned int file; /* [out] File buffers and structures */ + unsigned int sound; /* [out] Sound objects and internals */ + unsigned int secondaryram; /* [out] Sound data stored in secondary RAM */ + unsigned int soundgroup; /* [out] SoundGroup objects and internals */ + unsigned int streambuffer; /* [out] Stream buffer memory */ + unsigned int dspconnection; /* [out] DSPConnection objects and internals */ + unsigned int dsp; /* [out] DSP implementation objects */ + unsigned int dspcodec; /* [out] Realtime file format decoding DSP objects */ + unsigned int profile; /* [out] Profiler memory footprint. */ + unsigned int recordbuffer; /* [out] Buffer used to store recorded data from microphone */ + unsigned int reverb; /* [out] Reverb implementation objects */ + unsigned int reverbchannelprops; /* [out] Reverb channel properties structs */ + unsigned int geometry; /* [out] Geometry objects and internals */ + unsigned int syncpoint; /* [out] Sync point memory. */ + unsigned int eventsystem; /* [out] EventSystem and various internals */ + unsigned int musicsystem; /* [out] MusicSystem and various internals */ + unsigned int fev; /* [out] Definition of objects contained in all loaded projects e.g. events, groups, categories */ + unsigned int memoryfsb; /* [out] Data loaded with preloadFSB */ + unsigned int eventproject; /* [out] EventProject objects and internals */ + unsigned int eventgroupi; /* [out] EventGroup objects and internals */ + unsigned int soundbankclass; /* [out] Objects used to manage wave banks */ + unsigned int soundbanklist; /* [out] Data used to manage lists of wave bank usage */ + unsigned int streaminstance; /* [out] Stream objects and internals */ + unsigned int sounddefclass; /* [out] Sound definition objects */ + unsigned int sounddefdefclass; /* [out] Sound definition static data objects */ + unsigned int sounddefpool; /* [out] Sound definition pool data */ + unsigned int reverbdef; /* [out] Reverb definition objects */ + unsigned int eventreverb; /* [out] Reverb objects */ + unsigned int userproperty; /* [out] User property objects */ + unsigned int eventinstance; /* [out] Event instance base objects */ + unsigned int eventinstance_complex; /* [out] Complex event instance objects */ + unsigned int eventinstance_simple; /* [out] Simple event instance objects */ + unsigned int eventinstance_layer; /* [out] Event layer instance objects */ + unsigned int eventinstance_sound; /* [out] Event sound instance objects */ + unsigned int eventenvelope; /* [out] Event envelope objects */ + unsigned int eventenvelopedef; /* [out] Event envelope definition objects */ + unsigned int eventparameter; /* [out] Event parameter objects */ + unsigned int eventcategory; /* [out] Event category objects */ + unsigned int eventenvelopepoint; /* [out] Event envelope point objects */ + unsigned int eventinstancepool; /* [out] Event instance pool memory */ +} FMOD_MEMORY_USAGE_DETAILS; + + +/* +[DEFINE] +[ + [NAME] + FMOD_MEMBITS + + [DESCRIPTION] + Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Ex class. + Use with the "memorybits" parameter of getMemoryInfo to get information on FMOD Ex memory usage. + + [REMARKS] + Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + The FMOD_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See System::getMemoryInfo for an example. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_EVENT_MEMBITS + System::getMemoryInfo +] +*/ +#define FMOD_MEMBITS_OTHER 0x00000001 /* Memory not accounted for by other types */ +#define FMOD_MEMBITS_STRING 0x00000002 /* String data */ + +#define FMOD_MEMBITS_SYSTEM 0x00000004 /* System object and various internals */ +#define FMOD_MEMBITS_PLUGINS 0x00000008 /* Plugin objects and internals */ +#define FMOD_MEMBITS_OUTPUT 0x00000010 /* Output module object and internals */ +#define FMOD_MEMBITS_CHANNEL 0x00000020 /* Channel related memory */ +#define FMOD_MEMBITS_CHANNELGROUP 0x00000040 /* ChannelGroup objects and internals */ +#define FMOD_MEMBITS_CODEC 0x00000080 /* Codecs allocated for streaming */ +#define FMOD_MEMBITS_FILE 0x00000100 /* Codecs allocated for streaming */ +#define FMOD_MEMBITS_SOUND 0x00000200 /* Sound objects and internals */ +#define FMOD_MEMBITS_SOUND_SECONDARYRAM 0x00000400 /* Sound data stored in secondary RAM */ +#define FMOD_MEMBITS_SOUNDGROUP 0x00000800 /* SoundGroup objects and internals */ +#define FMOD_MEMBITS_STREAMBUFFER 0x00001000 /* Stream buffer memory */ +#define FMOD_MEMBITS_DSPCONNECTION 0x00002000 /* DSPConnection objects and internals */ +#define FMOD_MEMBITS_DSP 0x00004000 /* DSP implementation objects */ +#define FMOD_MEMBITS_DSPCODEC 0x00008000 /* Realtime file format decoding DSP objects */ +#define FMOD_MEMBITS_PROFILE 0x00010000 /* Profiler memory footprint. */ +#define FMOD_MEMBITS_RECORDBUFFER 0x00020000 /* Buffer used to store recorded data from microphone */ +#define FMOD_MEMBITS_REVERB 0x00040000 /* Reverb implementation objects */ +#define FMOD_MEMBITS_REVERBCHANNELPROPS 0x00080000 /* Reverb channel properties structs */ +#define FMOD_MEMBITS_GEOMETRY 0x00100000 /* Geometry objects and internals */ +#define FMOD_MEMBITS_SYNCPOINT 0x00200000 /* Sync point memory. */ +#define FMOD_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Ex */ +/* [DEFINE_END] */ + + +/* +[DEFINE] +[ + [NAME] + FMOD_EVENT_MEMBITS + + [DESCRIPTION] + Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Event System class. + Use with the "event_memorybits" parameter of getMemoryInfo to get information on FMOD Event System memory usage. + + [REMARKS] + Every public FMOD Event System class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + The FMOD_EVENT_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See EventSystem::getMemoryInfo for an example. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_MEMBITS + System::getMemoryInfo +] +*/ +#define FMOD_EVENT_MEMBITS_EVENTSYSTEM 0x00000001 /* EventSystem and various internals */ +#define FMOD_EVENT_MEMBITS_MUSICSYSTEM 0x00000002 /* MusicSystem and various internals */ +#define FMOD_EVENT_MEMBITS_FEV 0x00000004 /* Definition of objects contained in all loaded projects e.g. events, groups, categories */ +#define FMOD_EVENT_MEMBITS_MEMORYFSB 0x00000008 /* Data loaded with preloadFSB */ +#define FMOD_EVENT_MEMBITS_EVENTPROJECT 0x00000010 /* EventProject objects and internals */ +#define FMOD_EVENT_MEMBITS_EVENTGROUPI 0x00000020 /* EventGroup objects and internals */ +#define FMOD_EVENT_MEMBITS_SOUNDBANKCLASS 0x00000040 /* Objects used to manage wave banks */ +#define FMOD_EVENT_MEMBITS_SOUNDBANKLIST 0x00000080 /* Data used to manage lists of wave bank usage */ +#define FMOD_EVENT_MEMBITS_STREAMINSTANCE 0x00000100 /* Stream objects and internals */ +#define FMOD_EVENT_MEMBITS_SOUNDDEFCLASS 0x00000200 /* Sound definition objects */ +#define FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS 0x00000400 /* Sound definition static data objects */ +#define FMOD_EVENT_MEMBITS_SOUNDDEFPOOL 0x00000800 /* Sound definition pool data */ +#define FMOD_EVENT_MEMBITS_REVERBDEF 0x00001000 /* Reverb definition objects */ +#define FMOD_EVENT_MEMBITS_EVENTREVERB 0x00002000 /* Reverb objects */ +#define FMOD_EVENT_MEMBITS_USERPROPERTY 0x00004000 /* User property objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE 0x00008000 /* Event instance base objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX 0x00010000 /* Complex event instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE 0x00020000 /* Simple event instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER 0x00040000 /* Event layer instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND 0x00080000 /* Event sound instance objects */ +#define FMOD_EVENT_MEMBITS_EVENTENVELOPE 0x00100000 /* Event envelope objects */ +#define FMOD_EVENT_MEMBITS_EVENTENVELOPEDEF 0x00200000 /* Event envelope definition objects */ +#define FMOD_EVENT_MEMBITS_EVENTPARAMETER 0x00400000 /* Event parameter objects */ +#define FMOD_EVENT_MEMBITS_EVENTCATEGORY 0x00800000 /* Event category objects */ +#define FMOD_EVENT_MEMBITS_EVENTENVELOPEPOINT 0x01000000 /* Event envelope point object+s */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCEPOOL 0x02000000 /* Event instance pool data */ +#define FMOD_EVENT_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Event System */ + +/* All event instance memory */ +#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_GROUP (FMOD_EVENT_MEMBITS_EVENTINSTANCE | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER | \ + FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND) + +/* All sound definition memory */ +#define FMOD_EVENT_MEMBITS_SOUNDDEF_GROUP (FMOD_EVENT_MEMBITS_SOUNDDEFCLASS | \ + FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS | \ + FMOD_EVENT_MEMBITS_SOUNDDEFPOOL) +/* [DEFINE_END] */ + +#endif diff --git a/engine/fmod-4/inc/fmod_output.h b/engine/fmod-4/inc/fmod_output.h new file mode 100644 index 0000000..33919d7 --- /dev/null +++ b/engine/fmod-4/inc/fmod_output.h @@ -0,0 +1,93 @@ +/* ==================================================================================================== */ +/* FMOD Ex - output development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */ +/* */ +/* Use this header if you are wanting to develop your own output plugin to use with */ +/* FMOD's output system. With this header you can make your own output plugin that FMOD */ +/* can register and use. See the documentation and examples on how to make a working plugin. */ +/* */ +/* ==================================================================================================== */ + +#ifndef _FMOD_OUTPUT_H +#define _FMOD_OUTPUT_H + +#include "fmod.h" + +typedef struct FMOD_OUTPUT_STATE FMOD_OUTPUT_STATE; + +/* + Output callbacks +*/ +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETNUMDRIVERSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int *numdrivers); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERNAMECALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, char *name, int namelen); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERCAPSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, FMOD_CAPS *caps); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_INITCALLBACK) (FMOD_OUTPUT_STATE *output_state, int selecteddriver, FMOD_INITFLAGS flags, int *outputrate, int outputchannels, FMOD_SOUND_FORMAT *outputformat, int dspbufferlength, int dspnumbuffers, void *extradriverdata); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_CLOSECALLBACK) (FMOD_OUTPUT_STATE *output_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UPDATECALLBACK) (FMOD_OUTPUT_STATE *output_state); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETHANDLECALLBACK) (FMOD_OUTPUT_STATE *output_state, void **handle); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETPOSITIONCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int *pcm); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_LOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UNLOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); +typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_READFROMMIXER) (FMOD_OUTPUT_STATE *output_state, void *buffer, unsigned int length); + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + When creating an output, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file of this type. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_OUTPUT_STATE +] +*/ +typedef struct FMOD_OUTPUT_DESCRIPTION +{ + const char *name; /* [in] Name of the output. */ + unsigned int version; /* [in] Plugin writer's version number. */ + int polling; /* [in] If TRUE (non zero), this tells FMOD to start a thread and call getposition / lock / unlock for feeding data. If 0, the output is probably callback based, so all the plugin needs to do is call readfrommixer to the appropriate pointer. */ + FMOD_OUTPUT_GETNUMDRIVERSCALLBACK getnumdrivers; /* [in] For sound device enumeration. This callback is to give System::getNumDrivers somthing to return. */ + FMOD_OUTPUT_GETDRIVERNAMECALLBACK getdrivername; /* [in] For sound device enumeration. This callback is to give System::getDriverName somthing to return. */ + FMOD_OUTPUT_GETDRIVERCAPSCALLBACK getdrivercaps; /* [in] For sound device enumeration. This callback is to give System::getDriverCaps somthing to return. */ + FMOD_OUTPUT_INITCALLBACK init; /* [in] Initialization function for the output device. This is called from System::init. */ + FMOD_OUTPUT_CLOSECALLBACK close; /* [in] Cleanup / close down function for the output device. This is called from System::close. */ + FMOD_OUTPUT_UPDATECALLBACK update; /* [in] Update function that is called once a frame by the user. This is called from System::update. */ + FMOD_OUTPUT_GETHANDLECALLBACK gethandle; /* [in] This is called from System::getOutputHandle. This is just to return a pointer to the internal system device object that the system may be using.*/ + FMOD_OUTPUT_GETPOSITIONCALLBACK getposition; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This returns a position value in samples so that FMOD knows where and when to fill its buffer. */ + FMOD_OUTPUT_LOCKCALLBACK lock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This function provides a pointer to data that FMOD can write to when software mixing. */ + FMOD_OUTPUT_UNLOCKCALLBACK unlock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This optional function accepts the data that has been mixed and copies it or does whatever it needs to before sending it to the hardware. */ +} FMOD_OUTPUT_DESCRIPTION; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Output plugin structure that is passed into each callback. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value. + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android + + [SEE_ALSO] + FMOD_OUTPUT_DESCRIPTION +] +*/ +struct FMOD_OUTPUT_STATE +{ + void *plugindata; /* [in] Plugin writer created data the output author wants to attach to this object. */ + FMOD_OUTPUT_READFROMMIXER readfrommixer; /* [out] Function to update mixer and write the result to the provided pointer. Used from callback based output only. Polling based output uses lock/unlock/getposition. */ +}; + +#endif + + diff --git a/engine/jpeg-6/README b/engine/jpeg-6/README new file mode 100644 index 0000000..86cc206 --- /dev/null +++ b/engine/jpeg-6/README @@ -0,0 +1,385 @@ +The Independent JPEG Group's JPEG software +========================================== + +README for release 6b of 27-Mar-1998 +==================================== + +This distribution contains the sixth public release of the Independent JPEG +Group's free JPEG software. You are welcome to redistribute this software and +to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. + +Serious users of this software (particularly those incorporating it into +larger programs) should contact IJG at jpeg-info@uunet.uu.net to be added to +our electronic mailing list. Mailing list members are notified of updates +and have a chance to participate in technical discussions, etc. + +This software is the work of Tom Lane, Philip Gladstone, Jim Boucher, +Lee Crocker, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, +Guido Vollbeding, Ge' Weijers, and other members of the Independent JPEG +Group. + +IJG is not affiliated with the official ISO JPEG standards committee. + + +DOCUMENTATION ROADMAP +===================== + +This file contains the following sections: + +OVERVIEW General description of JPEG and the IJG software. +LEGAL ISSUES Copyright, lack of warranty, terms of distribution. +REFERENCES Where to learn more about JPEG. +ARCHIVE LOCATIONS Where to find newer versions of this software. +RELATED SOFTWARE Other stuff you should get. +FILE FORMAT WARS Software *not* to get. +TO DO Plans for future IJG releases. + +Other documentation files in the distribution are: + +User documentation: + install.doc How to configure and install the IJG software. + usage.doc Usage instructions for cjpeg, djpeg, jpegtran, + rdjpgcom, and wrjpgcom. + *.1 Unix-style man pages for programs (same info as usage.doc). + wizard.doc Advanced usage instructions for JPEG wizards only. + change.log Version-to-version change highlights. +Programmer and internal documentation: + libjpeg.doc How to use the JPEG library in your own programs. + example.c Sample code for calling the JPEG library. + structure.doc Overview of the JPEG library's internal structure. + filelist.doc Road map of IJG files. + coderules.doc Coding style rules --- please read if you contribute code. + +Please read at least the files install.doc and usage.doc. Useful information +can also be found in the JPEG FAQ (Frequently Asked Questions) article. See +ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. + +If you want to understand how the JPEG code works, we suggest reading one or +more of the REFERENCES, then looking at the documentation files (in roughly +the order listed) before diving into the code. + + +OVERVIEW +======== + +This package contains C software to implement JPEG image compression and +decompression. JPEG (pronounced "jay-peg") is a standardized compression +method for full-color and gray-scale images. JPEG is intended for compressing +"real-world" scenes; line drawings, cartoons and other non-realistic images +are not its strong suit. JPEG is lossy, meaning that the output image is not +exactly identical to the input image. Hence you must not use JPEG if you +have to have identical output bits. However, on typical photographic images, +very good compression levels can be obtained with no visible change, and +remarkably high compression levels are possible if you can tolerate a +low-quality image. For more details, see the references, or just experiment +with various compression settings. + +This software implements JPEG baseline, extended-sequential, and progressive +compression processes. Provision is made for supporting all variants of these +processes, although some uncommon parameter settings aren't implemented yet. +For legal reasons, we are not distributing code for the arithmetic-coding +variants of JPEG; see LEGAL ISSUES. We have made no provision for supporting +the hierarchical or lossless processes defined in the standard. + +We provide a set of library routines for reading and writing JPEG image files, +plus two sample applications "cjpeg" and "djpeg", which use the library to +perform conversion between JPEG and some other popular image file formats. +The library is intended to be reused in other applications. + +In order to support file conversion and viewing software, we have included +considerable functionality beyond the bare JPEG coding/decoding capability; +for example, the color quantization modules are not strictly part of JPEG +decoding, but they are essential for output to colormapped file formats or +colormapped displays. These extra functions can be compiled out of the +library if not required for a particular application. We have also included +"jpegtran", a utility for lossless transcoding between different JPEG +processes, and "rdjpgcom" and "wrjpgcom", two simple applications for +inserting and extracting textual comments in JFIF files. + +The emphasis in designing this software has been on achieving portability and +flexibility, while also making it fast enough to be useful. In particular, +the software is not intended to be read as a tutorial on JPEG. (See the +REFERENCES section for introductory material.) Rather, it is intended to +be reliable, portable, industrial-strength code. We do not claim to have +achieved that goal in every aspect of the software, but we strive for it. + +We welcome the use of this software as a component of commercial products. +No royalty is required, but we do ask for an acknowledgement in product +documentation, as described under LEGAL ISSUES. + + +LEGAL ISSUES +============ + +In plain English: + +1. We don't promise that this software works. (But if you find any bugs, + please let us know!) +2. You can use this software for whatever you want. You don't have to pay us. +3. You may not pretend that you wrote this software. If you use it in a + program, you must acknowledge somewhere in your documentation that + you've used the IJG code. + +In legalese: + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-1998, Thomas G. Lane. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, +sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. +ansi2knr.c is NOT covered by the above copyright and conditions, but instead +by the usual distribution terms of the Free Software Foundation; principally, +that you must include source code if you redistribute it. (See the file +ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part +of any program generated from the IJG code, this does not limit you more than +the foregoing paragraphs do. + +The Unix configuration script "configure" was produced with GNU Autoconf. +It is copyright by the Free Software Foundation but is freely distributable. +The same holds for its supporting scripts (config.guess, config.sub, +ltconfig, ltmain.sh). Another support script, install-sh, is copyright +by M.I.T. but is also freely distributable. + +It appears that the arithmetic coding option of the JPEG spec is covered by +patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot +legally be used without obtaining one or more licenses. For this reason, +support for arithmetic coding has been removed from the free JPEG software. +(Since arithmetic coding provides only a marginal gain over the unpatented +Huffman mode, it is unlikely that very many implementations will support it.) +So far as we are aware, there are no patent restrictions on the remaining +code. + +The IJG distribution formerly included code to read and write GIF files. +To avoid entanglement with the Unisys LZW patent, GIF reading support has +been removed altogether, and the GIF writer has been simplified to produce +"uncompressed GIFs". This technique does not use the LZW algorithm; the +resulting GIF files are larger than usual, but are readable by all standard +GIF decoders. + +We are required to state that + "The Graphics Interchange Format(c) is the Copyright property of + CompuServe Incorporated. GIF(sm) is a Service Mark property of + CompuServe Incorporated." + + +REFERENCES +========== + +We highly recommend reading one or more of these references before trying to +understand the innards of the JPEG software. + +The best short technical introduction to the JPEG compression algorithm is + Wallace, Gregory K. "The JPEG Still Picture Compression Standard", + Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. +(Adjacent articles in that issue discuss MPEG motion picture compression, +applications of JPEG, and related topics.) If you don't have the CACM issue +handy, a PostScript file containing a revised version of Wallace's article is +available at ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz. The file (actually +a preprint for an article that appeared in IEEE Trans. Consumer Electronics) +omits the sample images that appeared in CACM, but it includes corrections +and some added material. Note: the Wallace article is copyright ACM and IEEE, +and it may not be used for commercial purposes. + +A somewhat less technical, more leisurely introduction to JPEG can be found in +"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by +M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides +good explanations and example C code for a multitude of compression methods +including JPEG. It is an excellent source if you are comfortable reading C +code but don't know much about data compression in general. The book's JPEG +sample code is far from industrial-strength, but when you are ready to look +at a full implementation, you've got one here... + +The best full description of JPEG is the textbook "JPEG Still Image Data +Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published +by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. Price US$59.95, 638 pp. +The book includes the complete text of the ISO JPEG standards (DIS 10918-1 +and draft DIS 10918-2). This is by far the most complete exposition of JPEG +in existence, and we highly recommend it. + +The JPEG standard itself is not available electronically; you must order a +paper copy through ISO or ITU. (Unless you feel a need to own a certified +official copy, we recommend buying the Pennebaker and Mitchell book instead; +it's much cheaper and includes a great deal of useful explanatory material.) +In the USA, copies of the standard may be ordered from ANSI Sales at (212) +642-4900, or from Global Engineering Documents at (800) 854-7179. (ANSI +doesn't take credit card orders, but Global does.) It's not cheap: as of +1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7% +shipping/handling. The standard is divided into two parts, Part 1 being the +actual specification, while Part 2 covers compliance testing methods. Part 1 +is titled "Digital Compression and Coding of Continuous-tone Still Images, +Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS +10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of +Continuous-tone Still Images, Part 2: Compliance testing" and has document +numbers ISO/IEC IS 10918-2, ITU-T T.83. + +Some extensions to the original JPEG standard are defined in JPEG Part 3, +a newer ISO standard numbered ISO/IEC IS 10918-3 and ITU-T T.84. IJG +currently does not support any Part 3 extensions. + +The JPEG standard does not specify all details of an interchangeable file +format. For the omitted details we follow the "JFIF" conventions, revision +1.02. A copy of the JFIF spec is available from: + Literature Department + C-Cube Microsystems, Inc. + 1778 McCarthy Blvd. + Milpitas, CA 95035 + phone (408) 944-6300, fax (408) 944-6314 +A PostScript version of this document is available by FTP at +ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz. There is also a plain text +version at ftp://ftp.uu.net/graphics/jpeg/jfif.txt.gz, but it is missing +the figures. + +The TIFF 6.0 file format specification can be obtained by FTP from +ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme +found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. +IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). +Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 +(Compression tag 7). Copies of this Note can be obtained from ftp.sgi.com or +from ftp://ftp.uu.net/graphics/jpeg/. It is expected that the next revision +of the TIFF spec will replace the 6.0 JPEG design with the Note's design. +Although IJG's own code does not support TIFF/JPEG, the free libtiff library +uses our library to implement TIFF/JPEG per the Note. libtiff is available +from ftp://ftp.sgi.com/graphics/tiff/. + + +ARCHIVE LOCATIONS +================= + +The "official" archive site for this software is ftp.uu.net (Internet +address 192.48.96.9). The most recent released version can always be found +there in directory graphics/jpeg. This particular version will be archived +as ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz. If you don't have +direct Internet access, UUNET's archives are also available via UUCP; contact +help@uunet.uu.net for information on retrieving files that way. + +Numerous Internet sites maintain copies of the UUNET files. However, only +ftp.uu.net is guaranteed to have the latest official version. + +You can also obtain this software in DOS-compatible "zip" archive format from +the SimTel archives (ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/), or +on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), library 12 +"JPEG Tools". Again, these versions may sometimes lag behind the ftp.uu.net +release. + +The JPEG FAQ (Frequently Asked Questions) article is a useful source of +general information about JPEG. It is updated constantly and therefore is +not included in this distribution. The FAQ is posted every two weeks to +Usenet newsgroups comp.graphics.misc, news.answers, and other groups. +It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/ +and other news.answers archive sites, including the official news.answers +archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/. +If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu +with body + send usenet/news.answers/jpeg-faq/part1 + send usenet/news.answers/jpeg-faq/part2 + + +RELATED SOFTWARE +================ + +Numerous viewing and image manipulation programs now support JPEG. (Quite a +few of them use this library to do so.) The JPEG FAQ described above lists +some of the more popular free and shareware viewers, and tells where to +obtain them on Internet. + +If you are on a Unix machine, we highly recommend Jef Poskanzer's free +PBMPLUS software, which provides many useful operations on PPM-format image +files. In particular, it can convert PPM images to and from a wide range of +other formats, thus making cjpeg/djpeg considerably more useful. The latest +version is distributed by the NetPBM group, and is available from numerous +sites, notably ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/. +Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software is; +you are likely to have difficulty making it work on any non-Unix machine. + +A different free JPEG implementation, written by the PVRG group at Stanford, +is available from ftp://havefun.stanford.edu/pub/jpeg/. This program +is designed for research and experimentation rather than production use; +it is slower, harder to use, and less portable than the IJG code, but it +is easier to read and modify. Also, the PVRG code supports lossless JPEG, +which we do not. (On the other hand, it doesn't do progressive JPEG.) + + +FILE FORMAT WARS +================ + +Some JPEG programs produce files that are not compatible with our library. +The root of the problem is that the ISO JPEG committee failed to specify a +concrete file format. Some vendors "filled in the blanks" on their own, +creating proprietary formats that no one else could read. (For example, none +of the early commercial JPEG implementations for the Macintosh were able to +exchange compressed files.) + +The file format we have adopted is called JFIF (see REFERENCES). This format +has been agreed to by a number of major commercial JPEG vendors, and it has +become the de facto standard. JFIF is a minimal or "low end" representation. +We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF +Technical Note #2) for "high end" applications that need to record a lot of +additional data about an image. TIFF/JPEG is fairly new and not yet widely +supported, unfortunately. + +The upcoming JPEG Part 3 standard defines a file format called SPIFF. +SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should +be able to read the most common variant of SPIFF. SPIFF has some technical +advantages over JFIF, but its major claim to fame is simply that it is an +official standard rather than an informal one. At this point it is unclear +whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto +standard. IJG intends to support SPIFF once the standard is frozen, but we +have not decided whether it should become our default output format or not. +(In any case, our decoder will remain capable of reading JFIF indefinitely.) + +Various proprietary file formats incorporating JPEG compression also exist. +We have little or no sympathy for the existence of these formats. Indeed, +one of the original reasons for developing this free software was to help +force convergence on common, open format standards for JPEG files. Don't +use a proprietary file format! + + +TO DO +===== + +The major thrust for v7 will probably be improvement of visual quality. +The current method for scaling the quantization tables is known not to be +very good at low Q values. We also intend to investigate block boundary +smoothing, "poor man's variable quantization", and other means of improving +quality-vs-file-size performance without sacrificing compatibility. + +In future versions, we are considering supporting some of the upcoming JPEG +Part 3 extensions --- principally, variable quantization and the SPIFF file +format. + +As always, speeding things up is of great interest. + +Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net. diff --git a/engine/jpeg-6/jcapimin.c b/engine/jpeg-6/jcapimin.c new file mode 100644 index 0000000..1cd9736 --- /dev/null +++ b/engine/jpeg-6/jcapimin.c @@ -0,0 +1,228 @@ +/* + * jcapimin.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-compression case or the transcoding-only + * case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jcapistd.c. But also see jcparam.c for + * parameter-setup helper routines, jcomapi.c for routines shared by + * compression and decompression, and jctrans.c for the transcoding case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG compression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL void +jpeg_create_compress (j_compress_ptr cinfo) +{ + int i; + + /* For debugging purposes, zero the whole master structure. + * But error manager pointer is already there, so save and restore it. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct)); + cinfo->err = err; + } + cinfo->is_decompressor = FALSE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->dest = NULL; + + cinfo->comp_info = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + cinfo->input_gamma = 1.0; /* in case application forgets */ + + /* OK, I'm ready */ + cinfo->global_state = CSTATE_START; +} + + +/* + * Destruction of a JPEG compression object + */ + +GLOBAL void +jpeg_destroy_compress (j_compress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG compression operation, + * but don't destroy the object itself. + */ + +GLOBAL void +jpeg_abort_compress (j_compress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Forcibly suppress or un-suppress all quantization and Huffman tables. + * Marks all currently defined tables as already written (if suppress) + * or not written (if !suppress). This will control whether they get emitted + * by a subsequent jpeg_start_compress call. + * + * This routine is exported for use by applications that want to produce + * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but + * since it is called by jpeg_start_compress, we put it here --- otherwise + * jcparam.o would be linked whether the application used it or not. + */ + +GLOBAL void +jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress) +{ + int i; + JQUANT_TBL * qtbl; + JHUFF_TBL * htbl; + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL) + qtbl->sent_table = suppress; + } + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + } +} + + +/* + * Finish JPEG compression. + * + * If a multipass operating mode was selected, this may do a great deal of + * work including most of the actual output. + */ + +GLOBAL void +jpeg_finish_compress (j_compress_ptr cinfo) +{ + JDIMENSION iMCU_row; + + if (cinfo->global_state == CSTATE_SCANNING || + cinfo->global_state == CSTATE_RAW_OK) { + /* Terminate first pass */ + if (cinfo->next_scanline < cinfo->image_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_pass) (cinfo); + } else if (cinfo->global_state != CSTATE_WRCOEFS) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any remaining passes */ + while (! cinfo->master->is_last_pass) { + (*cinfo->master->prepare_for_pass) (cinfo); + for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) { + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) iMCU_row; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* We bypass the main controller and invoke coef controller directly; + * all work is being done from the coefficient buffer. + */ + if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } + (*cinfo->master->finish_pass) (cinfo); + } + /* Write EOI, do final cleanup */ + (*cinfo->marker->write_file_trailer) (cinfo); + (*cinfo->dest->term_destination) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); +} + + +/* + * Write a special marker. + * This is only recommended for writing COM or APPn markers. + * Must be called after jpeg_start_compress() and before + * first call to jpeg_write_scanlines() or jpeg_write_raw_data(). + */ + +GLOBAL void +jpeg_write_marker (j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen) +{ + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_any_marker) (cinfo, marker, dataptr, datalen); +} + + +/* + * Alternate compression function: just write an abbreviated table file. + * Before calling this, all parameters and a data destination must be set up. + * + * To produce a pair of files containing abbreviated tables and abbreviated + * image data, one would proceed as follows: + * + * initialize JPEG object + * set JPEG parameters + * set destination to table file + * jpeg_write_tables(cinfo); + * set destination to image file + * jpeg_start_compress(cinfo, FALSE); + * write data... + * jpeg_finish_compress(cinfo); + * + * jpeg_write_tables has the side effect of marking all tables written + * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress + * will not re-emit the tables unless it is passed write_all_tables=TRUE. + */ + +GLOBAL void +jpeg_write_tables (j_compress_ptr cinfo) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Initialize the marker writer ... bit of a crock to do it here. */ + jinit_marker_writer(cinfo); + /* Write them tables! */ + (*cinfo->marker->write_tables_only) (cinfo); + /* And clean up. */ + (*cinfo->dest->term_destination) (cinfo); + /* We can use jpeg_abort to release memory. */ + jpeg_abort((j_common_ptr) cinfo); +} diff --git a/engine/jpeg-6/jcapistd.c b/engine/jpeg-6/jcapistd.c new file mode 100644 index 0000000..b99e560 --- /dev/null +++ b/engine/jpeg-6/jcapistd.c @@ -0,0 +1,161 @@ +/* + * jcapistd.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-compression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_compress, it will end up linking in the entire compressor. + * We thus must separate this file from jcapimin.c to avoid linking the + * whole compression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Compression initialization. + * Before calling this, all parameters and a data destination must be set up. + * + * We require a write_all_tables parameter as a failsafe check when writing + * multiple datastreams from the same compression object. Since prior runs + * will have left all the tables marked sent_table=TRUE, a subsequent run + * would emit an abbreviated stream (no tables) by default. This may be what + * is wanted, but for safety's sake it should not be the default behavior: + * programmers should have to make a deliberate choice to emit abbreviated + * images. Therefore the documentation and examples should encourage people + * to pass write_all_tables=TRUE; then it will take active thought to do the + * wrong thing. + */ + +GLOBAL void +jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (write_all_tables) + jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */ + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + jinit_compress_master(cinfo); + /* Set up for the first pass */ + (*cinfo->master->prepare_for_pass) (cinfo); + /* Ready for application to drive first pass through jpeg_write_scanlines + * or jpeg_write_raw_data. + */ + cinfo->next_scanline = 0; + cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING); +} + + +/* + * Write some scanlines of data to the JPEG compressor. + * + * The return value will be the number of lines actually written. + * This should be less than the supplied num_lines only in case that + * the data destination module has requested suspension of the compressor, + * or if more than image_height scanlines are passed in. + * + * Note: we warn about excess calls to jpeg_write_scanlines() since + * this likely signals an application programmer error. However, + * excess scanlines passed in the last valid call are *silently* ignored, + * so that the application need not adjust num_lines for end-of-image + * when using a multiple-scanline buffer. + */ + +GLOBAL JDIMENSION +jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION num_lines) +{ + JDIMENSION row_ctr, rows_left; + + if (cinfo->global_state != CSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_scanlines. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_scanlines. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Ignore any extra scanlines at bottom of image. */ + rows_left = cinfo->image_height - cinfo->next_scanline; + if (num_lines > rows_left) + num_lines = rows_left; + + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines); + cinfo->next_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to write raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL JDIMENSION +jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION num_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != CSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_raw_data. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_raw_data. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Verify that at least one iMCU row has been passed. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE; + if (num_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Directly compress the row. */ + if (! (*cinfo->coef->compress_data) (cinfo, data)) { + /* If compressor did not consume the whole row, suspend processing. */ + return 0; + } + + /* OK, we processed one iMCU row. */ + cinfo->next_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} diff --git a/engine/jpeg-6/jccoefct.c b/engine/jpeg-6/jccoefct.c new file mode 100644 index 0000000..ea3169b --- /dev/null +++ b/engine/jpeg-6/jccoefct.c @@ -0,0 +1,448 @@ +/* + * jccoefct.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for compression. + * This controller is the top level of the JPEG compressor proper. + * The coefficient buffer lies between forward-DCT and entropy encoding steps. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* We use a full-image coefficient buffer when doing Huffman optimization, + * and also for writing multiple-scan JPEG files. In all cases, the DCT + * step is run during the first pass, and subsequent passes need only read + * the buffered coefficients. + */ +#ifdef ENTROPY_OPT_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#else +#ifdef C_MULTISCAN_FILES_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#endif +#endif + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_coef_controller pub; /* public fields */ + + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* For single-pass compression, it's sufficient to buffer just one MCU + * (although this may prove a bit slow in practice). We allocate a + * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each + * MCU constructed and sent. (On 80x86, the workspace is FAR even though + * it's not really very big; this is to keep the module interfaces unchanged + * when a large coefficient buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays. + */ + JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; + + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +/* Forward declarations */ +METHODDEF boolean compress_data + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#ifdef FULL_COEF_BUFFER_SUPPORTED +METHODDEF boolean compress_first_pass + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +METHODDEF boolean compress_output + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#endif + + +LOCAL void +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF void +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (coef->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_data; + break; +#ifdef FULL_COEF_BUFFER_SUPPORTED + case JBUF_SAVE_AND_PASS: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_first_pass; + break; + case JBUF_CRANK_DEST: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_output; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data in the single-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf contains a plane for each component in image. + * For single pass, this is the same as the components in the scan. + */ + +METHODDEF boolean +compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, bi, ci, yindex, yoffset, blockcnt; + JDIMENSION ypos, xpos; + jpeg_component_info *compptr; + + /* Loop to write as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Determine where data comes from in input_buf and do the DCT thing. + * Each call on forward_DCT processes a horizontal row of DCT blocks + * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks + * sequentially. Dummy blocks at the right or bottom edge are filled in + * specially. The data in them does not matter for image reconstruction, + * so we fill them with values that will encode to the smallest amount of + * data, viz: all zeroes in the AC entries, DC entries equal to previous + * block's DC value. (Thanks to Thomas Kinsman for this idea.) + */ + blkn = 0; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + xpos = MCU_col_num * compptr->MCU_sample_width; + ypos = yoffset * DCTSIZE; /* ypos == (yoffset+yindex) * DCTSIZE */ + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + (*cinfo->fdct->forward_DCT) (cinfo, compptr, + input_buf[ci], coef->MCU_buffer[blkn], + ypos, xpos, (JDIMENSION) blockcnt); + if (blockcnt < compptr->MCU_width) { + /* Create some dummy blocks at the right edge of the image. */ + jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt], + (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK)); + for (bi = blockcnt; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0]; + } + } + } else { + /* Create a row of dummy blocks at the bottom of the image. */ + jzero_far((void FAR *) coef->MCU_buffer[blkn], + compptr->MCU_width * SIZEOF(JBLOCK)); + for (bi = 0; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0]; + } + } + blkn += compptr->MCU_width; + ypos += DCTSIZE; + } + } + /* Try to write the MCU. In event of a suspension failure, we will + * re-DCT the MCU on restart (a bit inefficient, could be fixed...) + */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +#ifdef FULL_COEF_BUFFER_SUPPORTED + +/* + * Process some data in the first pass of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * This amount of data is read from the source buffer, DCT'd and quantized, + * and saved into the virtual arrays. We also generate suitable dummy blocks + * as needed at the right and lower edges. (The dummy blocks are constructed + * in the virtual arrays, which have been padded appropriately.) This makes + * it possible for subsequent passes not to worry about real vs. dummy blocks. + * + * We must also emit the data to the entropy encoder. This is conveniently + * done by calling compress_output() after we've loaded the current strip + * of the virtual arrays. + * + * NB: input_buf contains a plane for each component in image. All + * components are DCT'd and loaded into the virtual arrays in this pass. + * However, it may be that only a subset of the components are emitted to + * the entropy encoder during this first pass; be careful about looking + * at the scan-dependent variables (MCU dimensions, etc). + */ + +METHODDEF boolean +compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION blocks_across, MCUs_across, MCUindex; + int bi, ci, h_samp_factor, block_row, block_rows, ndummy; + JCOEF lastDC; + jpeg_component_info *compptr; + JBLOCKARRAY buffer; + JBLOCKROW thisblockrow, lastblockrow; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (coef->iMCU_row_num < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here, since may not be set! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + blocks_across = compptr->width_in_blocks; + h_samp_factor = compptr->h_samp_factor; + /* Count number of dummy blocks to be added at the right margin. */ + ndummy = (int) (blocks_across % h_samp_factor); + if (ndummy > 0) + ndummy = h_samp_factor - ndummy; + /* Perform DCT for all non-dummy blocks in this iMCU row. Each call + * on forward_DCT processes a complete horizontal row of DCT blocks. + */ + for (block_row = 0; block_row < block_rows; block_row++) { + thisblockrow = buffer[block_row]; + (*cinfo->fdct->forward_DCT) (cinfo, compptr, + input_buf[ci], thisblockrow, + (JDIMENSION) (block_row * DCTSIZE), + (JDIMENSION) 0, blocks_across); + if (ndummy > 0) { + /* Create dummy blocks at the right edge of the image. */ + thisblockrow += blocks_across; /* => first dummy block */ + jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK)); + lastDC = thisblockrow[-1][0]; + for (bi = 0; bi < ndummy; bi++) { + thisblockrow[bi][0] = lastDC; + } + } + } + /* If at end of image, create dummy block rows as needed. + * The tricky part here is that within each MCU, we want the DC values + * of the dummy blocks to match the last real block's DC value. + * This squeezes a few more bytes out of the resulting file... + */ + if (coef->iMCU_row_num == last_iMCU_row) { + blocks_across += ndummy; /* include lower right corner */ + MCUs_across = blocks_across / h_samp_factor; + for (block_row = block_rows; block_row < compptr->v_samp_factor; + block_row++) { + thisblockrow = buffer[block_row]; + lastblockrow = buffer[block_row-1]; + jzero_far((void FAR *) thisblockrow, + (size_t) (blocks_across * SIZEOF(JBLOCK))); + for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) { + lastDC = lastblockrow[h_samp_factor-1][0]; + for (bi = 0; bi < h_samp_factor; bi++) { + thisblockrow[bi][0] = lastDC; + } + thisblockrow += h_samp_factor; /* advance to next MCU in row */ + lastblockrow += h_samp_factor; + } + } + } + } + /* NB: compress_output will increment iMCU_row_num if successful. + * A suspension return will result in redoing all the work above next time. + */ + + /* Emit data to the entropy encoder, sharing code with subsequent passes */ + return compress_output(cinfo, input_buf); +} + + +/* + * Process some data in subsequent passes of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF boolean +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. + * NB: during first pass, this is safe only because the buffers will + * already be aligned properly, so jmemmgr.c won't need to do any I/O. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to write the MCU. */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + +#endif /* FULL_COEF_BUFFER_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL void +jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_coef_ptr coef; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_c_coef_controller *) coef; + coef->pub.start_pass = start_pass_coef; + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef FULL_COEF_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + int ci; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + coef->whole_image[0] = NULL; /* flag for no virtual arrays */ + } +} diff --git a/engine/jpeg-6/jccolor.c b/engine/jpeg-6/jccolor.c new file mode 100644 index 0000000..6707911 --- /dev/null +++ b/engine/jpeg-6/jccolor.c @@ -0,0 +1,459 @@ +/* + * jccolor.c + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_converter pub; /* public fields */ + + /* Private state for RGB->YCC conversion */ + INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */ +} my_color_converter; + +typedef my_color_converter * my_cconvert_ptr; + + +/**************** RGB -> YCbCr conversion: most common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B + * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE + * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2, + * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and + * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0) + * were not represented exactly. Now we sacrifice exact representation of + * maximum red and maximum blue in order to get exact grayscales. + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times R,G,B for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included + * in the tables to save adding them separately in the inner loop. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS) +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L< Y section */ +#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */ +#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */ +#define R_CB_OFF (3*(MAXJSAMPLE+1)) +#define G_CB_OFF (4*(MAXJSAMPLE+1)) +#define B_CB_OFF (5*(MAXJSAMPLE+1)) +#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */ +#define G_CR_OFF (6*(MAXJSAMPLE+1)) +#define B_CR_OFF (7*(MAXJSAMPLE+1)) +#define TABLE_SIZE (8*(MAXJSAMPLE+1)) + + +/* + * Initialize for RGB->YCC colorspace conversion. + */ + +METHODDEF void +rgb_ycc_start (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + INT32 * rgb_ycc_tab; + INT32 i; + + /* Allocate and fill in the conversion tables. */ + cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (TABLE_SIZE * SIZEOF(INT32))); + + for (i = 0; i <= MAXJSAMPLE; i++) { + rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i; + rgb_ycc_tab[i+G_Y_OFF] = FIX(0.58700) * i; + rgb_ycc_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF; + rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i; + rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i; + /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr. + * This ensures that the maximum output will round to MAXJSAMPLE + * not MAXJSAMPLE+1, and thus that we don't have to range-limit. + */ + rgb_ycc_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +/* B=>Cb and R=>Cr tables are the same + rgb_ycc_tab[i+R_CR_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +*/ + rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i; + rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i; + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * + * Note that we change from the application's interleaved-pixel format + * to our internal noninterleaved, one-plane-per-component format. + * The input buffer is therefore three times as wide as the output buffer. + * + * A starting row offset is provided only for the output buffer. The caller + * can easily adjust the passed input_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF void +rgb_ycc_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/**************** Cases other than RGB -> YCbCr **************/ + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles RGB->grayscale conversion, which is the same + * as the RGB->Y portion of RGB->YCbCr. + * We assume rgb_ycc_start has been called (we only use the Y tables). + */ + +METHODDEF void +rgb_gray_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* Y */ + outptr[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles Adobe-style CMYK->YCCK conversion, + * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same + * conversion as above, while passing K (black) unchanged. + * We assume rgb_ycc_start has been called. + */ + +METHODDEF void +cmyk_ycck_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2, outptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + outptr3 = output_buf[3][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = MAXJSAMPLE - GETJSAMPLE(inptr[0]); + g = MAXJSAMPLE - GETJSAMPLE(inptr[1]); + b = MAXJSAMPLE - GETJSAMPLE(inptr[2]); + /* K passes through as-is */ + outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */ + inptr += 4; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles grayscale output with no conversion. + * The source can be either plain grayscale or YCbCr (since Y == gray). + */ + +METHODDEF void +grayscale_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + int instride = cinfo->input_components; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */ + inptr += instride; + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles multi-component colorspaces without conversion. + * We assume input_components == num_components. + */ + +METHODDEF void +null_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + register int ci; + int nc = cinfo->num_components; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + /* It seems fastest to make a separate pass for each component. */ + for (ci = 0; ci < nc; ci++) { + inptr = *input_buf; + outptr = output_buf[ci][output_row]; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */ + inptr += nc; + } + } + input_buf++; + output_row++; + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF void +null_method (j_compress_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Module initialization routine for input colorspace conversion. + */ + +GLOBAL void +jinit_color_converter (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_converter)); + cinfo->cconvert = (struct jpeg_color_converter *) cconvert; + /* set start_pass to null method until we find out differently */ + cconvert->pub.start_pass = null_method; + + /* Make sure input_components agrees with in_color_space */ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + if (cinfo->input_components != 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + if (cinfo->input_components != RGB_PIXELSIZE) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; +#endif /* else share code with YCbCr */ + + case JCS_YCbCr: + if (cinfo->input_components != 3) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->input_components != 4) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->input_components < 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + } + + /* Check num_components, set conversion method based on requested space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_GRAYSCALE) + cconvert->pub.color_convert = grayscale_convert; + else if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_gray_convert; + } else if (cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = grayscale_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB && RGB_PIXELSIZE == 3) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_ycc_convert; + } else if (cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = cmyk_ycck_convert; + } else if (cinfo->in_color_space == JCS_YCCK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: /* allow null conversion of JCS_UNKNOWN */ + if (cinfo->jpeg_color_space != cinfo->in_color_space || + cinfo->num_components != cinfo->input_components) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + cconvert->pub.color_convert = null_convert; + break; + } +} diff --git a/engine/jpeg-6/jcdctmgr.c b/engine/jpeg-6/jcdctmgr.c new file mode 100644 index 0000000..f31a96f --- /dev/null +++ b/engine/jpeg-6/jcdctmgr.c @@ -0,0 +1,391 @@ +/* + * jcdctmgr.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the forward-DCT management logic. + * This code selects a particular DCT implementation to be used, + * and it performs related housekeeping chores including coefficient + * quantization. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* Private subobject for this module */ + +typedef struct { + struct jpeg_forward_dct pub; /* public fields */ + + /* Pointer to the DCT routine actually in use */ + forward_DCT_method_ptr do_dct; + + /* The actual post-DCT divisors --- not identical to the quant table + * entries, because of scaling (especially for an unnormalized DCT). + * Each table is given in normal array order; note that this must + * be converted from the zigzag order of the quantization tables. + */ + DCTELEM * divisors[NUM_QUANT_TBLS]; + +#ifdef DCT_FLOAT_SUPPORTED + /* Same as above for the floating-point case. */ + float_DCT_method_ptr do_float_dct; + FAST_FLOAT * float_divisors[NUM_QUANT_TBLS]; +#endif +} my_fdct_controller; + +typedef my_fdct_controller * my_fdct_ptr; + + +/* + * Initialize for a processing pass. + * Verify that all referenced Q-tables are present, and set up + * the divisor table for each one. + * In the current implementation, DCT of all components is done during + * the first pass, even if only some components will be output in the + * first scan. Hence all components should be examined here. + */ + +METHODDEF void +start_pass_fdctmgr (j_compress_ptr cinfo) +{ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + int ci, qtblno, i; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; +#ifdef DCT_ISLOW_SUPPORTED + DCTELEM * dtbl; +#endif + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + qtblno = compptr->quant_tbl_no; + /* Make sure specified quantization table is present */ + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + qtbl = cinfo->quant_tbl_ptrs[qtblno]; + /* Compute divisors for this quant table */ + /* We may do this more than once for same table, but it's not a big deal */ + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + /* For LL&M IDCT method, divisors are equal to raw quantization + * coefficients multiplied by 8 (to counteract scaling). + */ + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = ((DCTELEM) qtbl->quantval[jpeg_zigzag_order[i]]) << 3; + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + */ +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits: in natural order */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = (DCTELEM) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[jpeg_zigzag_order[i]], + (INT32) aanscales[i]), + CONST_BITS-3); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + * What's actually stored is 1/divisor so that the inner loop can + * use a multiplication rather than a division. + */ + FAST_FLOAT * fdtbl; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + if (fdct->float_divisors[qtblno] == NULL) { + fdct->float_divisors[qtblno] = (FAST_FLOAT *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(FAST_FLOAT)); + } + fdtbl = fdct->float_divisors[qtblno]; + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fdtbl[i] = (FAST_FLOAT) + (1.0 / (((double) qtbl->quantval[jpeg_zigzag_order[i]] * + aanscalefactor[row] * aanscalefactor[col] * 8.0))); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Perform forward DCT on one or more blocks of a component. + * + * The input samples are taken from the sample_data[] array starting at + * position start_row/start_col, and moving to the right for any additional + * blocks. The quantized coefficients are returned in coef_blocks[]. + */ + +#if 0 // bk001204 +METHODDEF void +forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for integer DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + forward_DCT_method_ptr do_dct = fdct->do_dct; + DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no]; + DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { + /* Load data into workspace, applying unsigned->signed conversion */ + { register DCTELEM *workspaceptr; + register JSAMPROW elemptr; + register int elemr; + + workspaceptr = workspace; + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = sample_data[elemr] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; +#else + { register int elemc; + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + } + } +#endif + } + } + + /* Perform the DCT */ + (*do_dct) (workspace); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register DCTELEM temp, qval; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + qval = divisors[i]; + temp = workspace[i]; + /* Divide the coefficient value by qval, ensuring proper rounding. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * + * In most files, at least half of the output values will be zero + * (at default quantization settings, more like three-quarters...) + * so we should ensure that this case is fast. On many machines, + * a comparison is enough cheaper than a divide to make a special test + * a win. Since both inputs will be nonnegative, we need only test + * for a < b to discover whether a/b is 0. + * If your machine's division is fast enough, define FAST_DIVIDE. + */ +#ifdef FAST_DIVIDE +#define DIVIDE_BY(a,b) a /= b +#else +#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0 +#endif + if (temp < 0) { + temp = -temp; + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + temp = -temp; + } else { + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + } + output_ptr[i] = (JCOEF) temp; + } + } + } +} +#endif // 0 + +#ifdef DCT_FLOAT_SUPPORTED + +METHODDEF void +forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for floating-point DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + float_DCT_method_ptr do_dct = fdct->do_float_dct; + FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no]; + FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { + /* Load data into workspace, applying unsigned->signed conversion */ + { register FAST_FLOAT *workspaceptr; + register JSAMPROW elemptr; + register int elemr; + + workspaceptr = workspace; + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = sample_data[elemr] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); +#else + { register int elemc; + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *workspaceptr++ = (FAST_FLOAT) + (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + } + } +#endif + } + } + + /* Perform the DCT */ + (*do_dct) (workspace); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register FAST_FLOAT temp; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + /* Apply the quantization and scaling factor */ + temp = workspace[i] * divisors[i]; + /* Round to nearest integer. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * The maximum coefficient size is +-16K (for 12-bit data), so this + * code should work for either 16-bit or 32-bit ints. + */ + output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384); + } + } + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ + + +/* + * Initialize FDCT manager. + */ + +GLOBAL void +jinit_forward_dct (j_compress_ptr cinfo) +{ + my_fdct_ptr fdct; + int i; + + fdct = (my_fdct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_fdct_controller)); + cinfo->fdct = (struct jpeg_forward_dct *) fdct; + fdct->pub.start_pass = start_pass_fdctmgr; + + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + fdct->pub.forward_DCT = forward_DCT; + fdct->do_dct = jpeg_fdct_islow; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + fdct->pub.forward_DCT = forward_DCT; + fdct->do_dct = jpeg_fdct_ifast; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + fdct->pub.forward_DCT = forward_DCT_float; + fdct->do_float_dct = jpeg_fdct_float; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + + /* Mark divisor tables unallocated */ + for (i = 0; i < NUM_QUANT_TBLS; i++) { + fdct->divisors[i] = NULL; +#ifdef DCT_FLOAT_SUPPORTED + fdct->float_divisors[i] = NULL; +#endif + } +} diff --git a/engine/jpeg-6/jchuff.c b/engine/jpeg-6/jchuff.c new file mode 100644 index 0000000..59f7865 --- /dev/null +++ b/engine/jpeg-6/jchuff.c @@ -0,0 +1,846 @@ +/* + * jchuff.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines. + * + * Much of the complexity here has to do with supporting output suspension. + * If the data destination module demands suspension, we want to be able to + * back up to the start of the current MCU. To do this, we copy state + * variables into local working storage, and update them back to the + * permanent JPEG objects only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jchuff.h" /* Declarations shared with jcphuff.c */ + + +/* Expanded entropy encoder object for Huffman encoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).put_buffer = (src).put_buffer, \ + (dest).put_bits = (src).put_bits, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_encoder pub; /* public fields */ + + savable_state saved; /* Bit buffer & DC state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + +#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */ + long * dc_count_ptrs[NUM_HUFF_TBLS]; + long * ac_count_ptrs[NUM_HUFF_TBLS]; +#endif +} huff_entropy_encoder; + +typedef huff_entropy_encoder * huff_entropy_ptr; + +/* Working state while writing an MCU. + * This struct contains all the fields that are needed by subroutines. + */ + +typedef struct { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + savable_state cur; /* Current bit buffer & DC state */ + j_compress_ptr cinfo; /* dump_buffer needs access to this */ +} working_state; + + +/* Forward declarations */ +METHODDEF boolean encode_mcu_huff JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF void finish_pass_huff JPP((j_compress_ptr cinfo)); +#ifdef ENTROPY_OPT_SUPPORTED +METHODDEF boolean encode_mcu_gather JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF void finish_pass_gather JPP((j_compress_ptr cinfo)); +#endif + + +/* + * Initialize for a Huffman-compressed scan. + * If gather_statistics is TRUE, we do not output anything during the scan, + * just count the Huffman symbols used and generate Huffman code tables. + */ + +METHODDEF void +start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + entropy->pub.encode_mcu = encode_mcu_gather; + entropy->pub.finish_pass = finish_pass_gather; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + entropy->pub.encode_mcu = encode_mcu_huff; + entropy->pub.finish_pass = finish_pass_huff; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + /* Make sure requested tables are present */ + /* (In gather mode, tables need not be allocated yet) */ + if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS || + (cinfo->dc_huff_tbl_ptrs[dctbl] == NULL && !gather_statistics)) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); + if (actbl < 0 || actbl >= NUM_HUFF_TBLS || + (cinfo->ac_huff_tbl_ptrs[actbl] == NULL && !gather_statistics)) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl); + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->dc_count_ptrs[dctbl] == NULL) + entropy->dc_count_ptrs[dctbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * SIZEOF(long)); + if (entropy->ac_count_ptrs[actbl] == NULL) + entropy->ac_count_ptrs[actbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->ac_count_ptrs[actbl], 257 * SIZEOF(long)); +#endif + } else { + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, cinfo->dc_huff_tbl_ptrs[dctbl], + & entropy->dc_derived_tbls[dctbl]); + jpeg_make_c_derived_tbl(cinfo, cinfo->ac_huff_tbl_ptrs[actbl], + & entropy->ac_derived_tbls[actbl]); + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bit buffer to empty */ + entropy->saved.put_buffer = 0; + entropy->saved.put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* + * Compute the derived values for a Huffman table. + * Note this is also used by jcphuff.c. + */ + +GLOBAL void +jpeg_make_c_derived_tbl (j_compress_ptr cinfo, JHUFF_TBL * htbl, + c_derived_tbl ** pdtbl) +{ + c_derived_tbl *dtbl; + int p, i, l, lastp, si; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (c_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_derived_tbl)); + dtbl = *pdtbl; + + /* Figure C.1: make table of Huffman code length for each symbol */ + /* Note that this is in code-length order. */ + + p = 0; + for (l = 1; l <= 16; l++) { + for (i = 1; i <= (int) htbl->bits[l]; i++) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + lastp = p; + + /* Figure C.2: generate the codes themselves */ + /* Note that this is in code-length order. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + code <<= 1; + si++; + } + + /* Figure C.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + /* Set any codeless symbols to have code length 0; + * this allows emit_bits to detect any attempt to emit such symbols. + */ + MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi)); + + for (p = 0; p < lastp; p++) { + dtbl->ehufco[htbl->huffval[p]] = huffcode[p]; + dtbl->ehufsi[htbl->huffval[p]] = huffsize[p]; + } +} + + +/* Outputting bytes to the file */ + +/* Emit a byte, taking 'action' if must suspend. */ +#define emit_byte(state,val,action) \ + { *(state)->next_output_byte++ = (JOCTET) (val); \ + if (--(state)->free_in_buffer == 0) \ + if (! dump_buffer(state)) \ + { action; } } + + +LOCAL boolean +dump_buffer (working_state * state) +/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */ +{ + struct jpeg_destination_mgr * dest = state->cinfo->dest; + + if (! (*dest->empty_output_buffer) (state->cinfo)) + return FALSE; + /* After a successful buffer dump, must reset buffer pointers */ + state->next_output_byte = dest->next_output_byte; + state->free_in_buffer = dest->free_in_buffer; + return TRUE; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL boolean +emit_bits (working_state * state, unsigned int code, int size) +/* Emit some bits; return TRUE if successful, FALSE if must suspend */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = state->cur.put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE); + + put_buffer &= (((INT32) 1)<cur.put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(state, c, return FALSE); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(state, 0, return FALSE); + } + put_buffer <<= 8; + put_bits -= 8; + } + + state->cur.put_buffer = put_buffer; /* update state variables */ + state->cur.put_bits = put_bits; + + return TRUE; +} + + +LOCAL boolean +flush_bits (working_state * state) +{ + if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */ + return FALSE; + state->cur.put_buffer = 0; /* and reset bit-buffer to empty */ + state->cur.put_bits = 0; + return TRUE; +} + + +/* Encode a single block's worth of coefficients */ + +LOCAL boolean +encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val, + c_derived_tbl *dctbl, c_derived_tbl *actbl) +{ + register int temp, temp2; + register int nbits; + register int k, r, i; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = temp2 = block[0] - last_dc_val; + + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + if (! emit_bits(state, (unsigned int) temp2, nbits)) + return FALSE; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[jpeg_natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + if (! emit_bits(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0])) + return FALSE; + r -= 16; + } + + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + + /* Emit Huffman symbol for run length / number of bits */ + i = (r << 4) + nbits; + if (! emit_bits(state, actbl->ehufco[i], actbl->ehufsi[i])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (! emit_bits(state, (unsigned int) temp2, nbits)) + return FALSE; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + if (! emit_bits(state, actbl->ehufco[0], actbl->ehufsi[0])) + return FALSE; + + return TRUE; +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL boolean +emit_restart (working_state * state, int restart_num) +{ + int ci; + + if (! flush_bits(state)) + return FALSE; + + emit_byte(state, 0xFF, return FALSE); + emit_byte(state, JPEG_RST0 + restart_num, return FALSE); + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < state->cinfo->comps_in_scan; ci++) + state->cur.last_dc_val[ci] = 0; + + /* The restart counter is not updated until we successfully write the MCU. */ + + return TRUE; +} + + +/* + * Encode and output one MCU's worth of Huffman-compressed coefficients. + */ + +METHODDEF boolean +encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + working_state state; + int blkn, ci; + jpeg_component_info * compptr; + + /* Load up working state */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! emit_restart(&state, entropy->next_restart_num)) + return FALSE; + } + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + if (! encode_one_block(&state, + MCU_data[blkn][0], state.cur.last_dc_val[ci], + entropy->dc_derived_tbls[compptr->dc_tbl_no], + entropy->ac_derived_tbls[compptr->ac_tbl_no])) + return FALSE; + /* Update last_dc_val */ + state.cur.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + /* Completed MCU, so update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF void +finish_pass_huff (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + working_state state; + + /* Load up working state ... flush_bits needs it */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Flush out the last data */ + if (! flush_bits(&state)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + + /* Update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); +} + + +/* + * Huffman coding optimization. + * + * This actually is optimization, in the sense that we find the best possible + * Huffman table(s) for the given data. We first scan the supplied data and + * count the number of uses of each symbol that is to be Huffman-coded. + * (This process must agree with the code above.) Then we build an + * optimal Huffman coding tree for the observed counts. + * + * The JPEG standard requires Huffman codes to be no more than 16 bits long. + * If some symbols have a very small but nonzero probability, the Huffman tree + * must be adjusted to meet the code length restriction. We currently use + * the adjustment method suggested in the JPEG spec. This method is *not* + * optimal; it may not choose the best possible limited-length code. But + * since the symbols involved are infrequently used, it's not clear that + * going to extra trouble is worthwhile. + */ + +#ifdef ENTROPY_OPT_SUPPORTED + + +/* Process a single block's worth of coefficients */ + +LOCAL void +htest_one_block (JCOEFPTR block, int last_dc_val, + long dc_counts[], long ac_counts[]) +{ + register int temp; + register int nbits; + register int k, r; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = block[0] - last_dc_val; + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + + /* Count the Huffman symbol for the number of bits */ + dc_counts[nbits]++; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[jpeg_natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + ac_counts[0xF0]++; + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + + /* Count Huffman symbol for run length / number of bits */ + ac_counts[(r << 4) + nbits]++; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + ac_counts[0]++; +} + + +/* + * Trial-encode one MCU's worth of Huffman-compressed coefficients. + * No data is actually output, so no suspension return is possible. + */ + +METHODDEF boolean +encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn, ci; + jpeg_component_info * compptr; + + /* Take care of restart intervals if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Update restart state */ + entropy->restarts_to_go = cinfo->restart_interval; + } + entropy->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + htest_one_block(MCU_data[blkn][0], entropy->saved.last_dc_val[ci], + entropy->dc_count_ptrs[compptr->dc_tbl_no], + entropy->ac_count_ptrs[compptr->ac_tbl_no]); + entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + return TRUE; +} + + +/* + * Generate the optimal coding for the given counts, fill htbl. + * Note this is also used by jcphuff.c. + */ + +GLOBAL void +jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]) +{ +#define MAX_CLEN 32 /* assumed maximum initial code length */ + UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */ + int codesize[257]; /* codesize[k] = code length of symbol k */ + int others[257]; /* next symbol in current branch of tree */ + int c1, c2; + int p, i, j; + long v; + + /* This algorithm is explained in section K.2 of the JPEG standard */ + + MEMZERO(bits, SIZEOF(bits)); + MEMZERO(codesize, SIZEOF(codesize)); + for (i = 0; i < 257; i++) + others[i] = -1; /* init links to empty */ + + freq[256] = 1; /* make sure there is a nonzero count */ + /* Including the pseudo-symbol 256 in the Huffman procedure guarantees + * that no real symbol is given code-value of all ones, because 256 + * will be placed in the largest codeword category. + */ + + /* Huffman's basic algorithm to assign optimal code lengths to symbols */ + + for (;;) { + /* Find the smallest nonzero frequency, set c1 = its symbol */ + /* In case of ties, take the larger symbol number */ + c1 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v) { + v = freq[i]; + c1 = i; + } + } + + /* Find the next smallest nonzero frequency, set c2 = its symbol */ + /* In case of ties, take the larger symbol number */ + c2 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v && i != c1) { + v = freq[i]; + c2 = i; + } + } + + /* Done if we've merged everything into one frequency */ + if (c2 < 0) + break; + + /* Else merge the two counts/trees */ + freq[c1] += freq[c2]; + freq[c2] = 0; + + /* Increment the codesize of everything in c1's tree branch */ + codesize[c1]++; + while (others[c1] >= 0) { + c1 = others[c1]; + codesize[c1]++; + } + + others[c1] = c2; /* chain c2 onto c1's tree branch */ + + /* Increment the codesize of everything in c2's tree branch */ + codesize[c2]++; + while (others[c2] >= 0) { + c2 = others[c2]; + codesize[c2]++; + } + } + + /* Now count the number of symbols of each code length */ + for (i = 0; i <= 256; i++) { + if (codesize[i]) { + /* The JPEG standard seems to think that this can't happen, */ + /* but I'm paranoid... */ + if (codesize[i] > MAX_CLEN) + ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW); + + bits[codesize[i]]++; + } + } + + /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure + * Huffman procedure assigned any such lengths, we must adjust the coding. + * Here is what the JPEG spec says about how this next bit works: + * Since symbols are paired for the longest Huffman code, the symbols are + * removed from this length category two at a time. The prefix for the pair + * (which is one bit shorter) is allocated to one of the pair; then, + * skipping the BITS entry for that prefix length, a code word from the next + * shortest nonzero BITS entry is converted into a prefix for two code words + * one bit longer. + */ + + for (i = MAX_CLEN; i > 16; i--) { + while (bits[i] > 0) { + j = i - 2; /* find length of new prefix to be used */ + while (bits[j] == 0) + j--; + + bits[i] -= 2; /* remove two symbols */ + bits[i-1]++; /* one goes in this length */ + bits[j+1] += 2; /* two new symbols in this length */ + bits[j]--; /* symbol of this length is now a prefix */ + } + } + + /* Remove the count for the pseudo-symbol 256 from the largest codelength */ + while (bits[i] == 0) /* find largest codelength still in use */ + i--; + bits[i]--; + + /* Return final symbol counts (only for lengths 0..16) */ + MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits)); + + /* Return a list of the symbols sorted by code length */ + /* It's not real clear to me why we don't need to consider the codelength + * changes made above, but the JPEG spec seems to think this works. + */ + p = 0; + for (i = 1; i <= MAX_CLEN; i++) { + for (j = 0; j <= 255; j++) { + if (codesize[j] == i) { + htbl->huffval[p] = (UINT8) j; + p++; + } + } + } + + /* Set sent_table FALSE so updated table will be written to JPEG file. */ + htbl->sent_table = FALSE; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF void +finish_pass_gather (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did_dc[NUM_HUFF_TBLS]; + boolean did_ac[NUM_HUFF_TBLS]; + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did_dc, SIZEOF(did_dc)); + MEMZERO(did_ac, SIZEOF(did_ac)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + if (! did_dc[dctbl]) { + htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[dctbl]); + did_dc[dctbl] = TRUE; + } + if (! did_ac[actbl]) { + htblptr = & cinfo->ac_huff_tbl_ptrs[actbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[actbl]); + did_ac[actbl] = TRUE; + } + } +} + + +#endif /* ENTROPY_OPT_SUPPORTED */ + + +/* + * Module initialization routine for Huffman entropy encoding. + */ + +GLOBAL void +jinit_huff_encoder (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(huff_entropy_encoder)); + cinfo->entropy = (struct jpeg_entropy_encoder *) entropy; + entropy->pub.start_pass = start_pass_huff; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; +#ifdef ENTROPY_OPT_SUPPORTED + entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL; +#endif + } +} diff --git a/engine/jpeg-6/jchuff.h b/engine/jpeg-6/jchuff.h new file mode 100644 index 0000000..f43d571 --- /dev/null +++ b/engine/jpeg-6/jchuff.h @@ -0,0 +1,34 @@ +/* + * jchuff.h + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy encoding routines + * that are shared between the sequential encoder (jchuff.c) and the + * progressive encoder (jcphuff.c). No other modules need to see these. + */ + +/* Derived data constructed for each Huffman table */ + +typedef struct { + unsigned int ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ +} c_derived_tbl; + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_c_derived_tbl jMkCDerived +#define jpeg_gen_optimal_table jGenOptTbl +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Expand a Huffman table definition into the derived format */ +EXTERN void jpeg_make_c_derived_tbl JPP((j_compress_ptr cinfo, + JHUFF_TBL * htbl, c_derived_tbl ** pdtbl)); + +/* Generate an optimal table definition given the specified counts */ +EXTERN void jpeg_gen_optimal_table JPP((j_compress_ptr cinfo, + JHUFF_TBL * htbl, long freq[])); diff --git a/engine/jpeg-6/jcinit.c b/engine/jpeg-6/jcinit.c new file mode 100644 index 0000000..2cc82b2 --- /dev/null +++ b/engine/jpeg-6/jcinit.c @@ -0,0 +1,72 @@ +/* + * jcinit.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains initialization logic for the JPEG compressor. + * This routine is in charge of selecting the modules to be executed and + * making an initialization call to each one. + * + * Logically, this code belongs in jcmaster.c. It's split out because + * linking this routine implies linking the entire compression library. + * For a transcoding-only application, we want to be able to use jcmaster.c + * without linking in the whole library. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Master selection of compression modules. + * This is done once at the start of processing an image. We determine + * which modules will be used and give them appropriate initialization calls. + */ + +GLOBAL void +jinit_compress_master (j_compress_ptr cinfo) +{ + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, FALSE /* full compression */); + + /* Preprocessing */ + if (! cinfo->raw_data_in) { + jinit_color_converter(cinfo); + jinit_downsampler(cinfo); + jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */); + } + /* Forward DCT */ + jinit_forward_dct(cinfo); + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + jinit_phuff_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_encoder(cinfo); + } + + /* Need a full-image coefficient buffer in any multi-pass mode. */ + jinit_c_coef_controller(cinfo, + (cinfo->num_scans > 1 || cinfo->optimize_coding)); + jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} diff --git a/engine/jpeg-6/jcmainct.c b/engine/jpeg-6/jcmainct.c new file mode 100644 index 0000000..42a02d0 --- /dev/null +++ b/engine/jpeg-6/jcmainct.c @@ -0,0 +1,296 @@ +/* + * jcmainct.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for compression. + * The main buffer lies between the pre-processor and the JPEG + * compressor proper; it holds downsampled data in the JPEG colorspace. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Note: currently, there is no operating mode in which a full-image buffer + * is needed at this step. If there were, that mode could not be used with + * "raw data" input, since this module is bypassed in that case. However, + * we've left the code here for possible use in special applications. + */ +#undef FULL_MAIN_BUFFER_SUPPORTED + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_main_controller pub; /* public fields */ + + JDIMENSION cur_iMCU_row; /* number of current iMCU row */ + JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */ + boolean suspended; /* remember if we suspended output */ + J_BUF_MODE pass_mode; /* current operating mode */ + + /* If using just a strip buffer, this points to the entire set of buffers + * (we allocate one for each component). In the full-image case, this + * points to the currently accessible strips of the virtual arrays. + */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* If using full-image storage, this array holds pointers to virtual-array + * control blocks for each component. Unused if not full-image storage. + */ + jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; +#endif +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + + +/* Forward declarations */ +METHODDEF void process_data_simple_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#ifdef FULL_MAIN_BUFFER_SUPPORTED +METHODDEF void process_data_buffer_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF void +start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + // bk001204 - don't use main... + my_main_ptr jmain = (my_main_ptr) cinfo->main; + + /* Do nothing in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + jmain->cur_iMCU_row = 0; /* initialize counters */ + jmain->rowgroup_ctr = 0; + jmain->suspended = FALSE; + jmain->pass_mode = pass_mode; /* save mode for use by process_data */ + + switch (pass_mode) { + case JBUF_PASS_THRU: +#ifdef FULL_MAIN_BUFFER_SUPPORTED + if (jmain->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + jmain->pub.process_data = process_data_simple_main; + break; +#ifdef FULL_MAIN_BUFFER_SUPPORTED + case JBUF_SAVE_SOURCE: + case JBUF_CRANK_DEST: + case JBUF_SAVE_AND_PASS: + if (jmain->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + jmain->pub.process_data = process_data_buffer_main; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This routine handles the simple pass-through mode, + * where we have only a strip buffer. + */ + +METHODDEF void +process_data_simple_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + // bk001204 - don't use main + my_main_ptr jmain = (my_main_ptr) cinfo->main; + + while (jmain->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Read input data if we haven't filled the main buffer yet */ + if (jmain->rowgroup_ctr < DCTSIZE) + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + jmain->buffer, &jmain->rowgroup_ctr, + (JDIMENSION) DCTSIZE); + + /* If we don't have a full iMCU row buffered, return to application for + * more data. Note that preprocessor will always pad to fill the iMCU row + * at the bottom of the image. + */ + if (jmain->rowgroup_ctr != DCTSIZE) + return; + + /* Send the completed row to the compressor */ + if (! (*cinfo->coef->compress_data) (cinfo, jmain->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! jmain->suspended) { + (*in_row_ctr)--; + jmain->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (jmain->suspended) { + (*in_row_ctr)++; + jmain->suspended = FALSE; + } + jmain->rowgroup_ctr = 0; + jmain->cur_iMCU_row++; + } +} + + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + +/* + * Process some data. + * This routine handles all of the modes that use a full-size buffer. + */ + +METHODDEF void +process_data_buffer_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci; + jpeg_component_info *compptr; + boolean writing = (main->pass_mode != JBUF_CRANK_DEST); + + while (main->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Realign the virtual buffers if at the start of an iMCU row. */ + if (main->rowgroup_ctr == 0) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + main->buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, main->whole_image[ci], + main->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE), + (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing); + } + /* In a read pass, pretend we just read some source data. */ + if (! writing) { + *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE; + main->rowgroup_ctr = DCTSIZE; + } + } + + /* If a write pass, read input data until the current iMCU row is full. */ + /* Note: preprocessor will pad if necessary to fill the last iMCU row. */ + if (writing) { + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + main->buffer, &main->rowgroup_ctr, + (JDIMENSION) DCTSIZE); + /* Return to application if we need more data to fill the iMCU row. */ + if (main->rowgroup_ctr < DCTSIZE) + return; + } + + /* Emit data, unless this is a sink-only pass. */ + if (main->pass_mode != JBUF_SAVE_SOURCE) { + if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! main->suspended) { + (*in_row_ctr)--; + main->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (main->suspended) { + (*in_row_ctr)++; + main->suspended = FALSE; + } + } + + /* If get here, we are done with this iMCU row. Mark buffer empty. */ + main->rowgroup_ctr = 0; + main->cur_iMCU_row++; + } +} + +#endif /* FULL_MAIN_BUFFER_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL void +jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + // bk001204 - don't use main + my_main_ptr jmain; + int ci; + jpeg_component_info *compptr; + + jmain = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_c_main_controller *) jmain; + jmain->pub.start_pass = start_pass_main; + + /* We don't need to create a buffer in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + /* Create the buffer. It holds downsampled data, so each component + * may be of a different size. + */ + if (need_full_buffer) { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component */ + /* Note we pad the bottom to a multiple of the iMCU height */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + jmain->whole_image[ci] = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + compptr->width_in_blocks * DCTSIZE, + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor) * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor * DCTSIZE)); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + jmain->whole_image[0] = NULL; /* flag for no virtual arrays */ +#endif + /* Allocate a strip buffer for each component */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + jmain->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_blocks * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor * DCTSIZE)); + } + } +} diff --git a/engine/jpeg-6/jcmarker.c b/engine/jpeg-6/jcmarker.c new file mode 100644 index 0000000..f4d290b --- /dev/null +++ b/engine/jpeg-6/jcmarker.c @@ -0,0 +1,639 @@ +/* + * jcmarker.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write JPEG datastream markers. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* + * Basic output routines. + * + * Note that we do not support suspension while writing a marker. + * Therefore, an application using suspension must ensure that there is + * enough buffer space for the initial markers (typ. 600-700 bytes) before + * calling jpeg_start_compress, and enough space to write the trailing EOI + * (a few bytes) before calling jpeg_finish_compress. Multipass compression + * modes are not supported at all with suspension, so those two are the only + * points where markers will be written. + */ + +LOCAL void +emit_byte (j_compress_ptr cinfo, int val) +/* Emit a byte */ +{ + struct jpeg_destination_mgr * dest = cinfo->dest; + + *(dest->next_output_byte)++ = (JOCTET) val; + if (--dest->free_in_buffer == 0) { + if (! (*dest->empty_output_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } +} + + +LOCAL void +emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark) +/* Emit a marker code */ +{ + emit_byte(cinfo, 0xFF); + emit_byte(cinfo, (int) mark); +} + + +LOCAL void +emit_2bytes (j_compress_ptr cinfo, int value) +/* Emit a 2-byte integer; these are always MSB first in JPEG files */ +{ + emit_byte(cinfo, (value >> 8) & 0xFF); + emit_byte(cinfo, value & 0xFF); +} + + +/* + * Routines to write specific marker types. + */ + +LOCAL int +emit_dqt (j_compress_ptr cinfo, int index) +/* Emit a DQT marker */ +/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */ +{ + JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index]; + int prec; + int i; + + if (qtbl == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index); + + prec = 0; + for (i = 0; i < DCTSIZE2; i++) { + if (qtbl->quantval[i] > 255) + prec = 1; + } + + if (! qtbl->sent_table) { + emit_marker(cinfo, M_DQT); + + emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2); + + emit_byte(cinfo, index + (prec<<4)); + + for (i = 0; i < DCTSIZE2; i++) { + if (prec) + emit_byte(cinfo, qtbl->quantval[i] >> 8); + emit_byte(cinfo, qtbl->quantval[i] & 0xFF); + } + + qtbl->sent_table = TRUE; + } + + return prec; +} + + +LOCAL void +emit_dht (j_compress_ptr cinfo, int index, boolean is_ac) +/* Emit a DHT marker */ +{ + JHUFF_TBL * htbl; + int length, i; + + if (is_ac) { + htbl = cinfo->ac_huff_tbl_ptrs[index]; + index += 0x10; /* output index has AC bit set */ + } else { + htbl = cinfo->dc_huff_tbl_ptrs[index]; + } + + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index); + + if (! htbl->sent_table) { + emit_marker(cinfo, M_DHT); + + length = 0; + for (i = 1; i <= 16; i++) + length += htbl->bits[i]; + + emit_2bytes(cinfo, length + 2 + 1 + 16); + emit_byte(cinfo, index); + + for (i = 1; i <= 16; i++) + emit_byte(cinfo, htbl->bits[i]); + + for (i = 0; i < length; i++) + emit_byte(cinfo, htbl->huffval[i]); + + htbl->sent_table = TRUE; + } +} + + +LOCAL void +emit_dac (j_compress_ptr cinfo) +/* Emit a DAC marker */ +/* Since the useful info is so small, we want to emit all the tables in */ +/* one DAC marker. Therefore this routine does its own scan of the table. */ +{ +#ifdef C_ARITH_CODING_SUPPORTED + char dc_in_use[NUM_ARITH_TBLS]; + char ac_in_use[NUM_ARITH_TBLS]; + int length, i; + jpeg_component_info *compptr; + + for (i = 0; i < NUM_ARITH_TBLS; i++) + dc_in_use[i] = ac_in_use[i] = 0; + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + dc_in_use[compptr->dc_tbl_no] = 1; + ac_in_use[compptr->ac_tbl_no] = 1; + } + + length = 0; + for (i = 0; i < NUM_ARITH_TBLS; i++) + length += dc_in_use[i] + ac_in_use[i]; + + emit_marker(cinfo, M_DAC); + + emit_2bytes(cinfo, length*2 + 2); + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + if (dc_in_use[i]) { + emit_byte(cinfo, i); + emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4)); + } + if (ac_in_use[i]) { + emit_byte(cinfo, i + 0x10); + emit_byte(cinfo, cinfo->arith_ac_K[i]); + } + } +#endif /* C_ARITH_CODING_SUPPORTED */ +} + + +LOCAL void +emit_dri (j_compress_ptr cinfo) +/* Emit a DRI marker */ +{ + emit_marker(cinfo, M_DRI); + + emit_2bytes(cinfo, 4); /* fixed length */ + + emit_2bytes(cinfo, (int) cinfo->restart_interval); +} + + +LOCAL void +emit_sof (j_compress_ptr cinfo, JPEG_MARKER code) +/* Emit a SOF marker */ +{ + int ci; + jpeg_component_info *compptr; + + emit_marker(cinfo, code); + + emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */ + + /* Make sure image isn't bigger than SOF field can handle */ + if ((long) cinfo->image_height > 65535L || + (long) cinfo->image_width > 65535L) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535); + + emit_byte(cinfo, cinfo->data_precision); + emit_2bytes(cinfo, (int) cinfo->image_height); + emit_2bytes(cinfo, (int) cinfo->image_width); + + emit_byte(cinfo, cinfo->num_components); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + emit_byte(cinfo, compptr->component_id); + emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor); + emit_byte(cinfo, compptr->quant_tbl_no); + } +} + + +LOCAL void +emit_sos (j_compress_ptr cinfo) +/* Emit a SOS marker */ +{ + int i, td, ta; + jpeg_component_info *compptr; + + emit_marker(cinfo, M_SOS); + + emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */ + + emit_byte(cinfo, cinfo->comps_in_scan); + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + emit_byte(cinfo, compptr->component_id); + td = compptr->dc_tbl_no; + ta = compptr->ac_tbl_no; + if (cinfo->progressive_mode) { + /* Progressive mode: only DC or only AC tables are used in one scan; + * furthermore, Huffman coding of DC refinement uses no table at all. + * We emit 0 for unused field(s); this is recommended by the P&M text + * but does not seem to be specified in the standard. + */ + if (cinfo->Ss == 0) { + ta = 0; /* DC scan */ + if (cinfo->Ah != 0 && !cinfo->arith_code) + td = 0; /* no DC table either */ + } else { + td = 0; /* AC scan */ + } + } + emit_byte(cinfo, (td << 4) + ta); + } + + emit_byte(cinfo, cinfo->Ss); + emit_byte(cinfo, cinfo->Se); + emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al); +} + + +LOCAL void +emit_jfif_app0 (j_compress_ptr cinfo) +/* Emit a JFIF-compliant APP0 marker */ +{ + /* + * Length of APP0 block (2 bytes) + * Block ID (4 bytes - ASCII "JFIF") + * Zero byte (1 byte to terminate the ID string) + * Version Major, Minor (2 bytes - 0x01, 0x01) + * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm) + * Xdpu (2 bytes - dots per unit horizontal) + * Ydpu (2 bytes - dots per unit vertical) + * Thumbnail X size (1 byte) + * Thumbnail Y size (1 byte) + */ + + emit_marker(cinfo, M_APP0); + + emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */ + + emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */ + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0x49); + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0); + /* We currently emit version code 1.01 since we use no 1.02 features. + * This may avoid complaints from some older decoders. + */ + emit_byte(cinfo, 1); /* Major version */ + emit_byte(cinfo, 1); /* Minor version */ + emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */ + emit_2bytes(cinfo, (int) cinfo->X_density); + emit_2bytes(cinfo, (int) cinfo->Y_density); + emit_byte(cinfo, 0); /* No thumbnail image */ + emit_byte(cinfo, 0); +} + + +LOCAL void +emit_adobe_app14 (j_compress_ptr cinfo) +/* Emit an Adobe APP14 marker */ +{ + /* + * Length of APP14 block (2 bytes) + * Block ID (5 bytes - ASCII "Adobe") + * Version Number (2 bytes - currently 100) + * Flags0 (2 bytes - currently 0) + * Flags1 (2 bytes - currently 0) + * Color transform (1 byte) + * + * Although Adobe TN 5116 mentions Version = 101, all the Adobe files + * now in circulation seem to use Version = 100, so that's what we write. + * + * We write the color transform byte as 1 if the JPEG color space is + * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with + * whether the encoder performed a transformation, which is pretty useless. + */ + + emit_marker(cinfo, M_APP14); + + emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */ + + emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */ + emit_byte(cinfo, 0x64); + emit_byte(cinfo, 0x6F); + emit_byte(cinfo, 0x62); + emit_byte(cinfo, 0x65); + emit_2bytes(cinfo, 100); /* Version */ + emit_2bytes(cinfo, 0); /* Flags0 */ + emit_2bytes(cinfo, 0); /* Flags1 */ + switch (cinfo->jpeg_color_space) { + case JCS_YCbCr: + emit_byte(cinfo, 1); /* Color transform = 1 */ + break; + case JCS_YCCK: + emit_byte(cinfo, 2); /* Color transform = 2 */ + break; + default: + emit_byte(cinfo, 0); /* Color transform = 0 */ + break; + } +} + + +/* + * This routine is exported for possible use by applications. + * The intended use is to emit COM or APPn markers after calling + * jpeg_start_compress() and before the first jpeg_write_scanlines() call + * (hence, after write_file_header but before write_frame_header). + * Other uses are not guaranteed to produce desirable results. + */ + +METHODDEF void +write_any_marker (j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen) +/* Emit an arbitrary marker with parameters */ +{ + if (datalen <= (unsigned int) 65533) { /* safety check */ + emit_marker(cinfo, (JPEG_MARKER) marker); + + emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */ + + while (datalen--) { + emit_byte(cinfo, *dataptr); + dataptr++; + } + } +} + + +/* + * Write datastream header. + * This consists of an SOI and optional APPn markers. + * We recommend use of the JFIF marker, but not the Adobe marker, + * when using YCbCr or grayscale data. The JFIF marker should NOT + * be used for any other JPEG colorspace. The Adobe marker is helpful + * to distinguish RGB, CMYK, and YCCK colorspaces. + * Note that an application can write additional header markers after + * jpeg_start_compress returns. + */ + +METHODDEF void +write_file_header (j_compress_ptr cinfo) +{ + emit_marker(cinfo, M_SOI); /* first the SOI */ + + if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */ + emit_jfif_app0(cinfo); + if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */ + emit_adobe_app14(cinfo); +} + + +/* + * Write frame header. + * This consists of DQT and SOFn markers. + * Note that we do not emit the SOF until we have emitted the DQT(s). + * This avoids compatibility problems with incorrect implementations that + * try to error-check the quant table numbers as soon as they see the SOF. + */ + +METHODDEF void +write_frame_header (j_compress_ptr cinfo) +{ + int ci, prec; + boolean is_baseline; + jpeg_component_info *compptr; + + /* Emit DQT for each quantization table. + * Note that emit_dqt() suppresses any duplicate tables. + */ + prec = 0; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prec += emit_dqt(cinfo, compptr->quant_tbl_no); + } + /* now prec is nonzero iff there are any 16-bit quant tables. */ + + /* Check for a non-baseline specification. + * Note we assume that Huffman table numbers won't be changed later. + */ + if (cinfo->arith_code || cinfo->progressive_mode || + cinfo->data_precision != 8) { + is_baseline = FALSE; + } else { + is_baseline = TRUE; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1) + is_baseline = FALSE; + } + if (prec && is_baseline) { + is_baseline = FALSE; + /* If it's baseline except for quantizer size, warn the user */ + TRACEMS(cinfo, 0, JTRC_16BIT_TABLES); + } + } + + /* Emit the proper SOF marker */ + if (cinfo->arith_code) { + emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */ + } else { + if (cinfo->progressive_mode) + emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */ + else if (is_baseline) + emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */ + else + emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */ + } +} + + +/* + * Write scan header. + * This consists of DHT or DAC markers, optional DRI, and SOS. + * Compressed data will be written following the SOS. + */ + +METHODDEF void +write_scan_header (j_compress_ptr cinfo) +{ + int i; + jpeg_component_info *compptr; + + if (cinfo->arith_code) { + /* Emit arith conditioning info. We may have some duplication + * if the file has multiple scans, but it's so small it's hardly + * worth worrying about. + */ + emit_dac(cinfo); + } else { + /* Emit Huffman tables. + * Note that emit_dht() suppresses any duplicate tables. + */ + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + if (cinfo->progressive_mode) { + /* Progressive mode: only DC or only AC tables are used in one scan */ + if (cinfo->Ss == 0) { + if (cinfo->Ah == 0) /* DC needs no table for refinement scan */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + } else { + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } else { + /* Sequential mode: need both DC and AC tables */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } + } + + /* Emit DRI if required --- note that DRI value could change for each scan. + * If it doesn't, a tiny amount of space is wasted in multiple-scan files. + * We assume DRI will never be nonzero for one scan and zero for a later one. + */ + if (cinfo->restart_interval) + emit_dri(cinfo); + + emit_sos(cinfo); +} + + +/* + * Write datastream trailer. + */ + +METHODDEF void +write_file_trailer (j_compress_ptr cinfo) +{ + emit_marker(cinfo, M_EOI); +} + + +/* + * Write an abbreviated table-specification datastream. + * This consists of SOI, DQT and DHT tables, and EOI. + * Any table that is defined and not marked sent_table = TRUE will be + * emitted. Note that all tables will be marked sent_table = TRUE at exit. + */ + +METHODDEF void +write_tables_only (j_compress_ptr cinfo) +{ + int i; + + emit_marker(cinfo, M_SOI); + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if (cinfo->quant_tbl_ptrs[i] != NULL) + (void) emit_dqt(cinfo, i); + } + + if (! cinfo->arith_code) { + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if (cinfo->dc_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, FALSE); + if (cinfo->ac_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, TRUE); + } + } + + emit_marker(cinfo, M_EOI); +} + + +/* + * Initialize the marker writer module. + */ + +GLOBAL void +jinit_marker_writer (j_compress_ptr cinfo) +{ + /* Create the subobject */ + cinfo->marker = (struct jpeg_marker_writer *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(struct jpeg_marker_writer)); + /* Initialize method pointers */ + cinfo->marker->write_any_marker = write_any_marker; + cinfo->marker->write_file_header = write_file_header; + cinfo->marker->write_frame_header = write_frame_header; + cinfo->marker->write_scan_header = write_scan_header; + cinfo->marker->write_file_trailer = write_file_trailer; + cinfo->marker->write_tables_only = write_tables_only; +} diff --git a/engine/jpeg-6/jcmaster.c b/engine/jpeg-6/jcmaster.c new file mode 100644 index 0000000..84494e6 --- /dev/null +++ b/engine/jpeg-6/jcmaster.c @@ -0,0 +1,578 @@ +/* + * jcmaster.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG compressor. + * These routines are concerned with parameter validation, initial setup, + * and inter-pass control (determining the number of passes and the work + * to be done in each pass). + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef enum { + main_pass, /* input data, also do first output step */ + huff_opt_pass, /* Huffman code optimization pass */ + output_pass /* data output pass */ +} c_pass_type; + +typedef struct { + struct jpeg_comp_master pub; /* public fields */ + + c_pass_type pass_type; /* the type of the current pass */ + + int pass_number; /* # of passes completed */ + int total_passes; /* total # of passes needed */ + + int scan_number; /* current index in scan_info[] */ +} my_comp_master; + +typedef my_comp_master * my_master_ptr; + + +/* + * Support routines that do various essential calculations. + */ + +LOCAL void +initial_setup (j_compress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ + int ci; + jpeg_component_info *compptr; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* Sanity check on image dimensions */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0 || cinfo->input_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* Width of an input scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Fill in the correct component_index value; don't rely on application */ + compptr->component_index = ci; + /* For compression, we never do DCT scaling. */ + compptr->DCT_scaled_size = DCTSIZE; + /* Size in DCT blocks */ + compptr->width_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->height_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed (this flag isn't actually used for compression) */ + compptr->component_needed = TRUE; + } + + /* Compute number of fully interleaved MCU rows (number of times that + * main controller will call coefficient controller). + */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); +} + + +#ifdef C_MULTISCAN_FILES_SUPPORTED + +LOCAL void +validate_script (j_compress_ptr cinfo) +/* Verify that the scan script in cinfo->scan_info[] is valid; also + * determine whether it uses progressive JPEG, and set cinfo->progressive_mode. + */ +{ + const jpeg_scan_info * scanptr; + int scanno, ncomps, ci, coefi, thisi; + int Ss, Se, Ah, Al; + boolean component_sent[MAX_COMPONENTS]; +#ifdef C_PROGRESSIVE_SUPPORTED + int * last_bitpos_ptr; + int last_bitpos[MAX_COMPONENTS][DCTSIZE2]; + /* -1 until that coefficient has been seen; then last Al for it */ +#endif + + if (cinfo->num_scans <= 0) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0); + + /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1; + * for progressive JPEG, no scan can have this. + */ + scanptr = cinfo->scan_info; + if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) { +#ifdef C_PROGRESSIVE_SUPPORTED + cinfo->progressive_mode = TRUE; + last_bitpos_ptr = & last_bitpos[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (coefi = 0; coefi < DCTSIZE2; coefi++) + *last_bitpos_ptr++ = -1; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->progressive_mode = FALSE; + for (ci = 0; ci < cinfo->num_components; ci++) + component_sent[ci] = FALSE; + } + + for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) { + /* Validate component indexes */ + ncomps = scanptr->comps_in_scan; + if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN); + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (thisi < 0 || thisi >= cinfo->num_components) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + /* Components must appear in SOF order within each scan */ + if (ci > 0 && thisi <= scanptr->component_index[ci-1]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + } + /* Validate progression parameters */ + Ss = scanptr->Ss; + Se = scanptr->Se; + Ah = scanptr->Ah; + Al = scanptr->Al; + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 || + Ah < 0 || Ah > 13 || Al < 0 || Al > 13) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + if (Ss == 0) { + if (Se != 0) /* DC and AC together not OK */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + if (ncomps != 1) /* AC scans must be for only one component */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + for (ci = 0; ci < ncomps; ci++) { + last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0]; + if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + for (coefi = Ss; coefi <= Se; coefi++) { + if (last_bitpos_ptr[coefi] < 0) { + /* first scan of this coefficient */ + if (Ah != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + /* not first scan */ + if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + last_bitpos_ptr[coefi] = Al; + } + } +#endif + } else { + /* For sequential JPEG, all progression parameters must be these: */ + if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + /* Make sure components are not sent twice */ + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (component_sent[thisi]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + component_sent[thisi] = TRUE; + } + } + } + + /* Now verify that everything got sent. */ + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* For progressive mode, we only check that at least some DC data + * got sent for each component; the spec does not require that all bits + * of all coefficients be transmitted. Would it be wiser to enforce + * transmission of all coefficient bits?? + */ + for (ci = 0; ci < cinfo->num_components; ci++) { + if (last_bitpos[ci][0] < 0) + ERREXIT(cinfo, JERR_MISSING_DATA); + } +#endif + } else { + for (ci = 0; ci < cinfo->num_components; ci++) { + if (! component_sent[ci]) + ERREXIT(cinfo, JERR_MISSING_DATA); + } + } +} + +#endif /* C_MULTISCAN_FILES_SUPPORTED */ + + +LOCAL void +select_scan_parameters (j_compress_ptr cinfo) +/* Set up the scan parameters for the current scan */ +{ + int ci; + +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (cinfo->scan_info != NULL) { + /* Prepare for current scan --- the script is already validated */ + my_master_ptr master = (my_master_ptr) cinfo->master; + const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number; + + cinfo->comps_in_scan = scanptr->comps_in_scan; + for (ci = 0; ci < scanptr->comps_in_scan; ci++) { + cinfo->cur_comp_info[ci] = + &cinfo->comp_info[scanptr->component_index[ci]]; + } + cinfo->Ss = scanptr->Ss; + cinfo->Se = scanptr->Se; + cinfo->Ah = scanptr->Ah; + cinfo->Al = scanptr->Al; + } + else +#endif + { + /* Prepare for single sequential-JPEG scan containing all components */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPS_IN_SCAN); + cinfo->comps_in_scan = cinfo->num_components; + for (ci = 0; ci < cinfo->num_components; ci++) { + cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; + } + cinfo->Ss = 0; + cinfo->Se = DCTSIZE2-1; + cinfo->Ah = 0; + cinfo->Al = 0; + } +} + + +LOCAL void +per_scan_setup (j_compress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_blocks; + cinfo->MCU_rows_in_scan = compptr->height_in_blocks; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + compptr->MCU_sample_width = DCTSIZE; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor*DCTSIZE)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * DCTSIZE; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + } + + /* Convert restart specified in rows to actual MCU count. */ + /* Note that count must fit in 16 bits, so we provide limiting. */ + if (cinfo->restart_in_rows > 0) { + long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row; + cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L); + } +} + + +/* + * Per-pass setup. + * This is called at the beginning of each pass. We determine which modules + * will be active during this pass and give them appropriate start_pass calls. + * We also set is_last_pass to indicate whether any more passes will be + * required. + */ + +METHODDEF void +prepare_for_pass (j_compress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + switch (master->pass_type) { + case main_pass: + /* Initial pass: will collect input data, and do either Huffman + * optimization or data output for the first scan. + */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (! cinfo->raw_data_in) { + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->downsample->start_pass) (cinfo); + (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU); + } + (*cinfo->fdct->start_pass) (cinfo); + (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding); + (*cinfo->coef->start_pass) (cinfo, + (master->total_passes > 1 ? + JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + if (cinfo->optimize_coding) { + /* No immediate data output; postpone writing frame/scan headers */ + master->pub.call_pass_startup = FALSE; + } else { + /* Will write frame/scan headers at first jpeg_write_scanlines call */ + master->pub.call_pass_startup = TRUE; + } + break; +#ifdef ENTROPY_OPT_SUPPORTED + case huff_opt_pass: + /* Do Huffman optimization for a scan after the first one. */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code) { + (*cinfo->entropy->start_pass) (cinfo, TRUE); + (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); + master->pub.call_pass_startup = FALSE; + break; + } + /* Special case: Huffman DC refinement scans need no Huffman table + * and therefore we can skip the optimization pass for them. + */ + master->pass_type = output_pass; + master->pass_number++; + /*FALLTHROUGH*/ +#endif + case output_pass: + /* Do a data-output pass. */ + /* We need not repeat per-scan setup if prior optimization pass did it. */ + if (! cinfo->optimize_coding) { + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + } + (*cinfo->entropy->start_pass) (cinfo, FALSE); + (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); + /* We emit frame/scan headers now */ + if (master->scan_number == 0) + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); + master->pub.call_pass_startup = FALSE; + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + } + + master->pub.is_last_pass = (master->pass_number == master->total_passes-1); + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->total_passes; + } +} + + +/* + * Special start-of-pass hook. + * This is called by jpeg_write_scanlines if call_pass_startup is TRUE. + * In single-pass processing, we need this hook because we don't want to + * write frame/scan headers during jpeg_start_compress; we want to let the + * application write COM markers etc. between jpeg_start_compress and the + * jpeg_write_scanlines loop. + * In multi-pass processing, this routine is not used. + */ + +METHODDEF void +pass_startup (j_compress_ptr cinfo) +{ + cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */ + + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); +} + + +/* + * Finish up at end of pass. + */ + +METHODDEF void +finish_pass_master (j_compress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* The entropy coder always needs an end-of-pass call, + * either to analyze statistics or to flush its output buffer. + */ + (*cinfo->entropy->finish_pass) (cinfo); + + /* Update state for next pass */ + switch (master->pass_type) { + case main_pass: + /* next pass is either output of scan 0 (after optimization) + * or output of scan 1 (if no optimization). + */ + master->pass_type = output_pass; + if (! cinfo->optimize_coding) + master->scan_number++; + break; + case huff_opt_pass: + /* next pass is always output of current scan */ + master->pass_type = output_pass; + break; + case output_pass: + /* next pass is either optimization or output of next scan */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + master->scan_number++; + break; + } + + master->pass_number++; +} + + +/* + * Initialize master compression control. + */ + +GLOBAL void +jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_comp_master)); + cinfo->master = (struct jpeg_comp_master *) master; + master->pub.prepare_for_pass = prepare_for_pass; + master->pub.pass_startup = pass_startup; + master->pub.finish_pass = finish_pass_master; + master->pub.is_last_pass = FALSE; + + /* Validate parameters, determine derived values */ + initial_setup(cinfo); + + if (cinfo->scan_info != NULL) { +#ifdef C_MULTISCAN_FILES_SUPPORTED + validate_script(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->progressive_mode = FALSE; + cinfo->num_scans = 1; + } + + if (cinfo->progressive_mode) /* TEMPORARY HACK ??? */ + cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */ + + /* Initialize my private state */ + if (transcode_only) { + /* no main pass in transcoding */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + else + master->pass_type = output_pass; + } else { + /* for normal compression, first pass is always this type: */ + master->pass_type = main_pass; + } + master->scan_number = 0; + master->pass_number = 0; + if (cinfo->optimize_coding) + master->total_passes = cinfo->num_scans * 2; + else + master->total_passes = cinfo->num_scans; +} diff --git a/engine/jpeg-6/jcomapi.c b/engine/jpeg-6/jcomapi.c new file mode 100644 index 0000000..c10903f --- /dev/null +++ b/engine/jpeg-6/jcomapi.c @@ -0,0 +1,94 @@ +/* + * jcomapi.c + * + * Copyright (C) 1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface routines that are used for both + * compression and decompression. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Abort processing of a JPEG compression or decompression operation, + * but don't destroy the object itself. + * + * For this, we merely clean up all the nonpermanent memory pools. + * Note that temp files (virtual arrays) are not allowed to belong to + * the permanent pool, so we will be able to close all temp files here. + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL void +jpeg_abort (j_common_ptr cinfo) +{ + int pool; + + /* Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) { + (*cinfo->mem->free_pool) (cinfo, pool); + } + + /* Reset overall state for possible reuse of object */ + cinfo->global_state = (cinfo->is_decompressor ? DSTATE_START : CSTATE_START); +} + + +/* + * Destruction of a JPEG object. + * + * Everything gets deallocated except the master jpeg_compress_struct itself + * and the error manager struct. Both of these are supplied by the application + * and must be freed, if necessary, by the application. (Often they are on + * the stack and so don't need to be freed anyway.) + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL void +jpeg_destroy (j_common_ptr cinfo) +{ + /* We need only tell the memory manager to release everything. */ + /* NB: mem pointer is NULL if memory mgr failed to initialize. */ + if (cinfo->mem != NULL) + (*cinfo->mem->self_destruct) (cinfo); + cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */ + cinfo->global_state = 0; /* mark it destroyed */ +} + + +/* + * Convenience routines for allocating quantization and Huffman tables. + * (Would jutils.c be a more reasonable place to put these?) + */ + +GLOBAL JQUANT_TBL * +jpeg_alloc_quant_table (j_common_ptr cinfo) +{ + JQUANT_TBL *tbl; + + tbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} + + +GLOBAL JHUFF_TBL * +jpeg_alloc_huff_table (j_common_ptr cinfo) +{ + JHUFF_TBL *tbl; + + tbl = (JHUFF_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} diff --git a/engine/jpeg-6/jconfig.h b/engine/jpeg-6/jconfig.h new file mode 100644 index 0000000..7d2f733 --- /dev/null +++ b/engine/jpeg-6/jconfig.h @@ -0,0 +1,41 @@ +/* jconfig.wat --- jconfig.h for Watcom C/C++ on MS-DOS or OS/2. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#define CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS /* Watcom uses flat 32-bit addressing */ +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +#define JDCT_DEFAULT JDCT_FLOAT +#define JDCT_FASTEST JDCT_FLOAT + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#undef TWO_FILE_COMMANDLINE /* optional */ +#define USE_SETMODE /* Needed to make one-file style work in Watcom */ +#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */ +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/engine/jpeg-6/jcparam.c b/engine/jpeg-6/jcparam.c new file mode 100644 index 0000000..29862d3 --- /dev/null +++ b/engine/jpeg-6/jcparam.c @@ -0,0 +1,575 @@ +/* + * jcparam.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains optional default-setting code for the JPEG compressor. + * Applications do not have to use this file, but those that don't use it + * must know a lot more about the innards of the JPEG code. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Quantization table setup routines + */ + +GLOBAL void +jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, boolean force_baseline) +/* Define a quantization table equal to the basic_table times + * a scale factor (given as a percentage). + * If force_baseline is TRUE, the computed quantization table entries + * are limited to 1..255 for JPEG baseline compatibility. + */ +{ + JQUANT_TBL ** qtblptr = & cinfo->quant_tbl_ptrs[which_tbl]; + int i; + long temp; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo); + + for (i = 0; i < DCTSIZE2; i++) { + temp = ((long) basic_table[i] * scale_factor + 50L) / 100L; + /* limit the values to the valid range */ + if (temp <= 0L) temp = 1L; + if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */ + if (force_baseline && temp > 255L) + temp = 255L; /* limit to baseline range if requested */ + (*qtblptr)->quantval[i] = (UINT16) temp; + } + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*qtblptr)->sent_table = FALSE; +} + + +GLOBAL void +jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables + * and a straight percentage-scaling quality scale. In most cases it's better + * to use jpeg_set_quality (below); this entry point is provided for + * applications that insist on a linear percentage scaling. + */ +{ + /* This is the sample quantization table given in the JPEG spec section K.1, + * but expressed in zigzag order (as are all of our quant. tables). + * The spec says that the values given produce "good" quality, and + * when divided by 2, "very good" quality. + */ + static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = { + 16, 11, 12, 14, 12, 10, 16, 14, + 13, 14, 18, 17, 16, 19, 24, 40, + 26, 24, 22, 22, 24, 49, 35, 37, + 29, 40, 58, 51, 61, 60, 57, 51, + 56, 55, 64, 72, 92, 78, 64, 68, + 87, 69, 55, 56, 80, 109, 81, 87, + 95, 98, 103, 104, 103, 62, 77, 113, + 121, 112, 100, 120, 92, 101, 103, 99 + }; + static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = { + 17, 18, 18, 24, 21, 24, 47, 26, + 26, 47, 99, 66, 56, 66, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 + }; + + /* Set up two quantization tables using the specified scaling */ + jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, + scale_factor, force_baseline); + jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, + scale_factor, force_baseline); +} + + +GLOBAL int +jpeg_quality_scaling (int quality) +/* Convert a user-specified quality rating to a percentage scaling factor + * for an underlying quantization table, using our recommended scaling curve. + * The input 'quality' factor should be 0 (terrible) to 100 (very good). + */ +{ + /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */ + if (quality <= 0) quality = 1; + if (quality > 100) quality = 100; + + /* The basic table is used as-is (scaling 100) for a quality of 50. + * Qualities 50..100 are converted to scaling percentage 200 - 2*Q; + * note that at Q=100 the scaling is 0, which will cause j_add_quant_table + * to make all the table entries 1 (hence, no quantization loss). + * Qualities 1..50 are converted to scaling percentage 5000/Q. + */ + if (quality < 50) + quality = 5000 / quality; + else + quality = 200 - quality*2; + + return quality; +} + + +GLOBAL void +jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables. + * This is the standard quality-adjusting entry point for typical user + * interfaces; only those who want detailed control over quantization tables + * would use the preceding three routines directly. + */ +{ + /* Convert user 0-100 rating to percentage scaling */ + quality = jpeg_quality_scaling(quality); + + /* Set up standard quality tables */ + jpeg_set_linear_quality(cinfo, quality, force_baseline); +} + + +/* + * Huffman table setup routines + */ + +LOCAL void +add_huff_table (j_compress_ptr cinfo, + JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) +/* Define a Huffman table */ +{ + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + MEMCOPY((*htblptr)->huffval, val, SIZEOF((*htblptr)->huffval)); + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*htblptr)->sent_table = FALSE; +} + + +LOCAL void +std_huff_tables (j_compress_ptr cinfo) +/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */ +/* IMPORTANT: these are only valid for 8-bit data precision! */ +{ + static const UINT8 bits_dc_luminance[17] = + { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_luminance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_dc_chrominance[17] = + { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_chrominance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_ac_luminance[17] = + { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; + static const UINT8 val_ac_luminance[] = + { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + static const UINT8 bits_ac_chrominance[17] = + { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; + static const UINT8 val_ac_chrominance[] = + { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0], + bits_dc_luminance, val_dc_luminance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0], + bits_ac_luminance, val_ac_luminance); + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1], + bits_dc_chrominance, val_dc_chrominance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1], + bits_ac_chrominance, val_ac_chrominance); +} + + +/* + * Default parameter setup for compression. + * + * Applications that don't choose to use this routine must do their + * own setup of all these parameters. Alternately, you can call this + * to establish defaults and then alter parameters selectively. This + * is the recommended approach since, if we add any new parameters, + * your code will still work (they'll be set to reasonable defaults). + */ + +GLOBAL void +jpeg_set_defaults (j_compress_ptr cinfo) +{ + int i; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Allocate comp_info array large enough for maximum component count. + * Array is made permanent in case application wants to compress + * multiple images at same param settings. + */ + if (cinfo->comp_info == NULL) + cinfo->comp_info = (jpeg_component_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + MAX_COMPONENTS * SIZEOF(jpeg_component_info)); + + /* Initialize everything not dependent on the color space */ + + cinfo->data_precision = BITS_IN_JSAMPLE; + /* Set up two quantization tables using default quality of 75 */ + jpeg_set_quality(cinfo, 75, TRUE); + /* Set up two Huffman tables */ + std_huff_tables(cinfo); + + /* Initialize default arithmetic coding conditioning */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + + /* Default is no multiple-scan output */ + cinfo->scan_info = NULL; + cinfo->num_scans = 0; + + /* Expect normal source image, not raw downsampled data */ + cinfo->raw_data_in = FALSE; + + /* Use Huffman coding, not arithmetic coding, by default */ + cinfo->arith_code = FALSE; + + /* By default, don't do extra passes to optimize entropy coding */ + cinfo->optimize_coding = FALSE; + /* The standard Huffman tables are only valid for 8-bit data precision. + * If the precision is higher, force optimization on so that usable + * tables will be computed. This test can be removed if default tables + * are supplied that are valid for the desired precision. + */ + if (cinfo->data_precision > 8) + cinfo->optimize_coding = TRUE; + + /* By default, use the simpler non-cosited sampling alignment */ + cinfo->CCIR601_sampling = FALSE; + + /* No input smoothing */ + cinfo->smoothing_factor = 0; + + /* DCT algorithm preference */ + cinfo->dct_method = JDCT_DEFAULT; + + /* No restart markers */ + cinfo->restart_interval = 0; + cinfo->restart_in_rows = 0; + + /* Fill in default JFIF marker parameters. Note that whether the marker + * will actually be written is determined by jpeg_set_colorspace. + */ + cinfo->density_unit = 0; /* Pixel size is unknown by default */ + cinfo->X_density = 1; /* Pixel aspect ratio is square by default */ + cinfo->Y_density = 1; + + /* Choose JPEG colorspace based on input space, set defaults accordingly */ + + jpeg_default_colorspace(cinfo); +} + + +/* + * Select an appropriate JPEG colorspace for in_color_space. + */ + +GLOBAL void +jpeg_default_colorspace (j_compress_ptr cinfo) +{ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); + break; + case JCS_RGB: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_YCbCr: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_CMYK: + jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */ + break; + case JCS_YCCK: + jpeg_set_colorspace(cinfo, JCS_YCCK); + break; + case JCS_UNKNOWN: + jpeg_set_colorspace(cinfo, JCS_UNKNOWN); + break; + default: + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + } +} + + +/* + * Set the JPEG colorspace, and choose colorspace-dependent default values. + */ + +GLOBAL void +jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace) +{ + jpeg_component_info * compptr; + int ci; + +#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \ + (compptr = &cinfo->comp_info[index], \ + compptr->component_id = (id), \ + compptr->h_samp_factor = (hsamp), \ + compptr->v_samp_factor = (vsamp), \ + compptr->quant_tbl_no = (quant), \ + compptr->dc_tbl_no = (dctbl), \ + compptr->ac_tbl_no = (actbl) ) + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* For all colorspaces, we use Q and Huff tables 0 for luminance components, + * tables 1 for chrominance components. + */ + + cinfo->jpeg_color_space = colorspace; + + cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */ + cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */ + + switch (colorspace) { + case JCS_GRAYSCALE: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 1; + /* JFIF specifies component ID 1 */ + SET_COMP(0, 1, 1,1, 0, 0,0); + break; + case JCS_RGB: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */ + cinfo->num_components = 3; + SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0); + SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0); + SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0); + break; + case JCS_YCbCr: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 3; + /* JFIF specifies component IDs 1,2,3 */ + /* We default to 2x2 subsamples of chrominance */ + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + break; + case JCS_CMYK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */ + cinfo->num_components = 4; + SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0); + SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0); + SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0); + SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0); + break; + case JCS_YCCK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */ + cinfo->num_components = 4; + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + SET_COMP(3, 4, 2,2, 0, 0,0); + break; + case JCS_UNKNOWN: + cinfo->num_components = cinfo->input_components; + if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + for (ci = 0; ci < cinfo->num_components; ci++) { + SET_COMP(ci, ci, 1,1, 0, 0,0); + } + break; + default: + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + } +} + + +#ifdef C_PROGRESSIVE_SUPPORTED + +LOCAL jpeg_scan_info * +fill_a_scan (jpeg_scan_info * scanptr, int ci, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for specified component */ +{ + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + return scanptr; +} + +LOCAL jpeg_scan_info * +fill_scans (jpeg_scan_info * scanptr, int ncomps, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for each component */ +{ + int ci; + + for (ci = 0; ci < ncomps; ci++) { + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } + return scanptr; +} + +LOCAL jpeg_scan_info * +fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al) +/* Support routine: generate interleaved DC scan if possible, else N scans */ +{ + int ci; + + if (ncomps <= MAX_COMPS_IN_SCAN) { + /* Single interleaved DC scan */ + scanptr->comps_in_scan = ncomps; + for (ci = 0; ci < ncomps; ci++) + scanptr->component_index[ci] = ci; + scanptr->Ss = scanptr->Se = 0; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } else { + /* Noninterleaved DC scan for each component */ + scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al); + } + return scanptr; +} + + +/* + * Create a recommended progressive-JPEG script. + * cinfo->num_components and cinfo->jpeg_color_space must be correct. + */ + +GLOBAL void +jpeg_simple_progression (j_compress_ptr cinfo) +{ + int ncomps = cinfo->num_components; + int nscans; + jpeg_scan_info * scanptr; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Figure space needed for script. Calculation must match code below! */ + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + nscans = 10; + } else { + /* All-purpose script for other color spaces. */ + if (ncomps > MAX_COMPS_IN_SCAN) + nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */ + else + nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */ + } + + /* Allocate space for script. */ + /* We use permanent pool just in case application re-uses script. */ + scanptr = (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + nscans * SIZEOF(jpeg_scan_info)); + cinfo->scan_info = scanptr; + cinfo->num_scans = nscans; + + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + /* Initial DC scan */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + /* Initial AC scan: get some luma data out in a hurry */ + scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2); + /* Chroma data is too small to be worth expending many scans on */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1); + /* Complete spectral selection for luma AC */ + scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2); + /* Refine next bit of luma AC */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1); + /* Finish DC successive approximation */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + /* Finish AC successive approximation */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0); + /* Luma bottom bit comes last since it's usually largest scan */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0); + } else { + /* All-purpose script for other color spaces. */ + /* Successive approximation first pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2); + scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2); + /* Successive approximation second pass */ + scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1); + /* Successive approximation final pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0); + } +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/engine/jpeg-6/jcphuff.c b/engine/jpeg-6/jcphuff.c new file mode 100644 index 0000000..922c17c --- /dev/null +++ b/engine/jpeg-6/jcphuff.c @@ -0,0 +1,829 @@ +/* + * jcphuff.c + * + * Copyright (C) 1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines for progressive JPEG. + * + * We do not support output suspension in this module, since the library + * currently does not allow multiple-scan files to be written with output + * suspension. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jchuff.h" /* Declarations shared with jchuff.c */ + +#ifdef C_PROGRESSIVE_SUPPORTED + +/* Expanded entropy encoder object for progressive Huffman encoding. */ + +typedef struct { + struct jpeg_entropy_encoder pub; /* public fields */ + + /* Mode flag: TRUE for optimization, FALSE for actual data output */ + boolean gather_statistics; + + /* Bit-level coding status. + * next_output_byte/free_in_buffer are local copies of cinfo->dest fields. + */ + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */ + + /* Coding status for DC components */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ + + /* Coding status for AC components */ + int ac_tbl_no; /* the table number of the single component */ + unsigned int EOBRUN; /* run length of EOBs */ + unsigned int BE; /* # of buffered correction bits before MCU */ + char * bit_buffer; /* buffer for correction bits (1 per char) */ + /* packing correction bits tightly would save some space but cost time... */ + + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan). + * Since any one scan codes only DC or only AC, we only need one set + * of tables, not one for DC and one for AC. + */ + c_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + /* Statistics tables for optimization; again, one set is enough */ + long * count_ptrs[NUM_HUFF_TBLS]; +} phuff_entropy_encoder; + +typedef phuff_entropy_encoder * phuff_entropy_ptr; + +/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit + * buffer can hold. Larger sizes may slightly improve compression, but + * 1000 is already well into the realm of overkill. + * The minimum safe size is 64 bits. + */ + +#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */ + +/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32. + * We assume that int right shift is unsigned if INT32 right shift is, + * which should be safe. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS int ishift_temp; +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +/* Forward declarations */ +METHODDEF boolean encode_mcu_DC_first JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF boolean encode_mcu_AC_first JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF boolean encode_mcu_DC_refine JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF boolean encode_mcu_AC_refine JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF void finish_pass_phuff JPP((j_compress_ptr cinfo)); +METHODDEF void finish_pass_gather_phuff JPP((j_compress_ptr cinfo)); + + +/* + * Initialize for a Huffman-compressed scan using progressive JPEG. + */ + +METHODDEF void +start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + boolean is_DC_band; + int ci, tbl; + jpeg_component_info * compptr; + + entropy->cinfo = cinfo; + entropy->gather_statistics = gather_statistics; + + is_DC_band = (cinfo->Ss == 0); + + /* We assume jcmaster.c already validated the scan parameters. */ + + /* Select execution routines */ + if (cinfo->Ah == 0) { + if (is_DC_band) + entropy->pub.encode_mcu = encode_mcu_DC_first; + else + entropy->pub.encode_mcu = encode_mcu_AC_first; + } else { + if (is_DC_band) + entropy->pub.encode_mcu = encode_mcu_DC_refine; + else { + entropy->pub.encode_mcu = encode_mcu_AC_refine; + /* AC refinement needs a correction bit buffer */ + if (entropy->bit_buffer == NULL) + entropy->bit_buffer = (char *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + MAX_CORR_BITS * SIZEOF(char)); + } + } + if (gather_statistics) + entropy->pub.finish_pass = finish_pass_gather_phuff; + else + entropy->pub.finish_pass = finish_pass_phuff; + + /* Only DC coefficients may be interleaved, so cinfo->comps_in_scan = 1 + * for AC coefficients. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Initialize DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + /* Make sure requested tables are present */ + /* (In gather mode, tables need not be allocated yet) */ + if (is_DC_band) { + if (cinfo->Ah != 0) /* DC refinement needs no table */ + continue; + tbl = compptr->dc_tbl_no; + if (tbl < 0 || tbl >= NUM_HUFF_TBLS || + (cinfo->dc_huff_tbl_ptrs[tbl] == NULL && !gather_statistics)) + ERREXIT1(cinfo,JERR_NO_HUFF_TABLE, tbl); + } else { + entropy->ac_tbl_no = tbl = compptr->ac_tbl_no; + if (tbl < 0 || tbl >= NUM_HUFF_TBLS || + (cinfo->ac_huff_tbl_ptrs[tbl] == NULL && !gather_statistics)) + ERREXIT1(cinfo,JERR_NO_HUFF_TABLE, tbl); + } + if (gather_statistics) { + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->count_ptrs[tbl] == NULL) + entropy->count_ptrs[tbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->count_ptrs[tbl], 257 * SIZEOF(long)); + } else { + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + if (is_DC_band) + jpeg_make_c_derived_tbl(cinfo, cinfo->dc_huff_tbl_ptrs[tbl], + & entropy->derived_tbls[tbl]); + else + jpeg_make_c_derived_tbl(cinfo, cinfo->ac_huff_tbl_ptrs[tbl], + & entropy->derived_tbls[tbl]); + } + } + + /* Initialize AC stuff */ + entropy->EOBRUN = 0; + entropy->BE = 0; + + /* Initialize bit buffer to empty */ + entropy->put_buffer = 0; + entropy->put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* Outputting bytes to the file. + * NB: these must be called only when actually outputting, + * that is, entropy->gather_statistics == FALSE. + */ + +/* Emit a byte */ +#define emit_byte(entropy,val) \ + { *(entropy)->next_output_byte++ = (JOCTET) (val); \ + if (--(entropy)->free_in_buffer == 0) \ + dump_buffer(entropy); } + + +LOCAL void +dump_buffer (phuff_entropy_ptr entropy) +/* Empty the output buffer; we do not support suspension in this module. */ +{ + struct jpeg_destination_mgr * dest = entropy->cinfo->dest; + + if (! (*dest->empty_output_buffer) (entropy->cinfo)) + ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND); + /* After a successful buffer dump, must reset buffer pointers */ + entropy->next_output_byte = dest->next_output_byte; + entropy->free_in_buffer = dest->free_in_buffer; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL void +emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size) +/* Emit some bits, unless we are in gather mode */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = entropy->put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + if (entropy->gather_statistics) + return; /* do nothing if we're only getting stats */ + + put_buffer &= (((INT32) 1)<put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(entropy, c); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(entropy, 0); + } + put_buffer <<= 8; + put_bits -= 8; + } + + entropy->put_buffer = put_buffer; /* update variables */ + entropy->put_bits = put_bits; +} + + +LOCAL void +flush_bits (phuff_entropy_ptr entropy) +{ + emit_bits(entropy, 0x7F, 7); /* fill any partial byte with ones */ + entropy->put_buffer = 0; /* and reset bit-buffer to empty */ + entropy->put_bits = 0; +} + + +/* + * Emit (or just count) a Huffman symbol. + */ + +INLINE +LOCAL void +emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol) +{ + if (entropy->gather_statistics) + entropy->count_ptrs[tbl_no][symbol]++; + else { + c_derived_tbl * tbl = entropy->derived_tbls[tbl_no]; + emit_bits(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]); + } +} + + +/* + * Emit bits from a correction bit buffer. + */ + +LOCAL void +emit_buffered_bits (phuff_entropy_ptr entropy, char * bufstart, + unsigned int nbits) +{ + if (entropy->gather_statistics) + return; /* no real work */ + + while (nbits > 0) { + emit_bits(entropy, (unsigned int) (*bufstart), 1); + bufstart++; + nbits--; + } +} + + +/* + * Emit any pending EOBRUN symbol. + */ + +LOCAL void +emit_eobrun (phuff_entropy_ptr entropy) +{ + register int temp, nbits; + + if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */ + temp = entropy->EOBRUN; + nbits = 0; + while ((temp >>= 1)) + nbits++; + + emit_symbol(entropy, entropy->ac_tbl_no, nbits << 4); + if (nbits) + emit_bits(entropy, entropy->EOBRUN, nbits); + + entropy->EOBRUN = 0; + + /* Emit any buffered correction bits */ + emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE); + entropy->BE = 0; + } +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL void +emit_restart (phuff_entropy_ptr entropy, int restart_num) +{ + int ci; + + emit_eobrun(entropy); + + if (! entropy->gather_statistics) { + flush_bits(entropy); + emit_byte(entropy, 0xFF); + emit_byte(entropy, JPEG_RST0 + restart_num); + } + + if (entropy->cinfo->Ss == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++) + entropy->last_dc_val[ci] = 0; + } else { + /* Re-initialize all AC-related fields to 0 */ + entropy->EOBRUN = 0; + entropy->BE = 0; + } +} + + +/* + * MCU encoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF boolean +encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp, temp2; + register int nbits; + int blkn, ci; + int Al = cinfo->Al; + JBLOCKROW block; + jpeg_component_info * compptr; + ISHIFT_TEMPS + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + + /* Compute the DC value after the required point transform by Al. + * This is simply an arithmetic right shift. + */ + temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al); + + /* DC differences are figured on the point-transformed values. */ + temp = temp2 - entropy->last_dc_val[ci]; + entropy->last_dc_val[ci] = temp2; + + /* Encode the DC coefficient difference per section G.1.2.1 */ + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + + /* Count/emit the Huffman-coded symbol for the number of bits */ + emit_symbol(entropy, compptr->dc_tbl_no, nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + emit_bits(entropy, (unsigned int) temp2, nbits); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF boolean +encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp, temp2; + register int nbits; + register int r, k; + int Se = cinfo->Se; + int Al = cinfo->Al; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */ + + r = 0; /* r = run length of zeros */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = (*block)[jpeg_natural_order[k]]) == 0) { + r++; + continue; + } + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value; so the code is + * interwoven with finding the abs value (temp) and output bits (temp2). + */ + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ + temp2 = ~temp; + } else { + temp >>= Al; /* apply the point transform */ + temp2 = temp; + } + /* Watch out for case that nonzero coef is zero after point transform */ + if (temp == 0) { + r++; + continue; + } + + /* Emit any pending EOBRUN */ + if (entropy->EOBRUN > 0) + emit_eobrun(entropy); + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + emit_bits(entropy, (unsigned int) temp2, nbits); + + r = 0; /* reset zero run length */ + } + + if (r > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + if (entropy->EOBRUN == 0x7FFF) + emit_eobrun(entropy); /* force it out to avoid overflow */ + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF boolean +encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp; + int blkn; + int Al = cinfo->Al; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* We simply emit the Al'th bit of the DC coefficient value. */ + temp = (*block)[0]; + emit_bits(entropy, (unsigned int) (temp >> Al), 1); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC successive approximation refinement scan. + */ + +METHODDEF boolean +encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp; + register int r, k; + int EOB; + char *BR_buffer; + unsigned int BR; + int Se = cinfo->Se; + int Al = cinfo->Al; + JBLOCKROW block; + int absvalues[DCTSIZE2]; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* It is convenient to make a pre-pass to determine the transformed + * coefficients' absolute values and the EOB position. + */ + EOB = 0; + for (k = cinfo->Ss; k <= Se; k++) { + temp = (*block)[jpeg_natural_order[k]]; + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value. + */ + if (temp < 0) + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + absvalues[k] = temp; /* save abs value for main pass */ + if (temp == 1) + EOB = k; /* EOB = index of last newly-nonzero coef */ + } + + /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */ + + r = 0; /* r = run length of zeros */ + BR = 0; /* BR = count of buffered bits added now */ + BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = absvalues[k]) == 0) { + r++; + continue; + } + + /* Emit any required ZRLs, but not if they can be folded into EOB */ + while (r > 15 && k <= EOB) { + /* emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + /* Emit ZRL */ + emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + /* Emit buffered correction bits that must be associated with ZRL */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + } + + /* If the coef was previously nonzero, it only needs a correction bit. + * NOTE: a straight translation of the spec's figure G.7 would suggest + * that we also need to test r > 15. But if r > 15, we can only get here + * if k > EOB, which implies that this coefficient is not 1. + */ + if (temp > 1) { + /* The correction bit is the next bit of the absolute value. */ + BR_buffer[BR++] = (char) (temp & 1); + continue; + } + + /* Emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1); + + /* Emit output bit for newly-nonzero coef */ + temp = ((*block)[jpeg_natural_order[k]] < 0) ? 0 : 1; + emit_bits(entropy, (unsigned int) temp, 1); + + /* Emit buffered correction bits that must be associated with this code */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + r = 0; /* reset zero run length */ + } + + if (r > 0 || BR > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + entropy->BE += BR; /* concat my correction bits to older ones */ + /* We force out the EOB if we risk either: + * 1. overflow of the EOB counter; + * 2. overflow of the correction bit buffer during the next MCU. + */ + if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1)) + emit_eobrun(entropy); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed progressive scan. + */ + +METHODDEF void +finish_pass_phuff (j_compress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Flush out any buffered data */ + emit_eobrun(entropy); + flush_bits(entropy); + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF void +finish_pass_gather_phuff (j_compress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + boolean is_DC_band; + int ci, tbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did[NUM_HUFF_TBLS]; + + /* Flush out buffered data (all we care about is counting the EOB symbol) */ + emit_eobrun(entropy); + + is_DC_band = (cinfo->Ss == 0); + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did, SIZEOF(did)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (is_DC_band) { + if (cinfo->Ah != 0) /* DC refinement needs no table */ + continue; + tbl = compptr->dc_tbl_no; + } else { + tbl = compptr->ac_tbl_no; + } + if (! did[tbl]) { + if (is_DC_band) + htblptr = & cinfo->dc_huff_tbl_ptrs[tbl]; + else + htblptr = & cinfo->ac_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[tbl]); + did[tbl] = TRUE; + } + } +} + + +/* + * Module initialization routine for progressive Huffman entropy encoding. + */ + +GLOBAL void +jinit_phuff_encoder (j_compress_ptr cinfo) +{ + phuff_entropy_ptr entropy; + int i; + + entropy = (phuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(phuff_entropy_encoder)); + cinfo->entropy = (struct jpeg_entropy_encoder *) entropy; + entropy->pub.start_pass = start_pass_phuff; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + entropy->count_ptrs[i] = NULL; + } + entropy->bit_buffer = NULL; /* needed only in AC refinement scan */ +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/engine/jpeg-6/jcprepct.c b/engine/jpeg-6/jcprepct.c new file mode 100644 index 0000000..7e60946 --- /dev/null +++ b/engine/jpeg-6/jcprepct.c @@ -0,0 +1,371 @@ +/* + * jcprepct.c + * + * Copyright (C) 1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the compression preprocessing controller. + * This controller manages the color conversion, downsampling, + * and edge expansion steps. + * + * Most of the complexity here is associated with buffering input rows + * as required by the downsampler. See the comments at the head of + * jcsample.c for the downsampler's needs. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* At present, jcsample.c can request context rows only for smoothing. + * In the future, we might also need context rows for CCIR601 sampling + * or other more-complex downsampling procedures. The code to support + * context rows should be compiled only if needed. + */ +#ifdef INPUT_SMOOTHING_SUPPORTED +#define CONTEXT_ROWS_SUPPORTED +#endif + + +/* + * For the simple (no-context-row) case, we just need to buffer one + * row group's worth of pixels for the downsampling step. At the bottom of + * the image, we pad to a full row group by replicating the last pixel row. + * The downsampler's last output row is then replicated if needed to pad + * out to a full iMCU row. + * + * When providing context rows, we must buffer three row groups' worth of + * pixels. Three row groups are physically allocated, but the row pointer + * arrays are made five row groups high, with the extra pointers above and + * below "wrapping around" to point to the last and first real row groups. + * This allows the downsampler to access the proper context rows. + * At the top and bottom of the image, we create dummy context rows by + * copying the first or last real pixel row. This copying could be avoided + * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the + * trouble on the compression side. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_prep_controller pub; /* public fields */ + + /* Downsampling input buffer. This buffer holds color-converted data + * until we have enough to do a downsample step. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + JDIMENSION rows_to_go; /* counts rows remaining in source image */ + int next_buf_row; /* index of next row to store in color_buf */ + +#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */ + int this_row_group; /* starting row index of group to process */ + int next_buf_stop; /* downsample when we reach this index */ +#endif +} my_prep_controller; + +typedef my_prep_controller * my_prep_ptr; + + +/* + * Initialize for a processing pass. + */ + +METHODDEF void +start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + + if (pass_mode != JBUF_PASS_THRU) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Initialize total-height counter for detecting bottom of image */ + prep->rows_to_go = cinfo->image_height; + /* Mark the conversion buffer empty */ + prep->next_buf_row = 0; +#ifdef CONTEXT_ROWS_SUPPORTED + /* Preset additional state variables for context mode. + * These aren't used in non-context mode, so we needn't test which mode. + */ + prep->this_row_group = 0; + /* Set next_buf_stop to stop after two row groups have been read in. */ + prep->next_buf_stop = 2 * cinfo->max_v_samp_factor; +#endif +} + + +/* + * Expand an image vertically from height input_rows to height output_rows, + * by duplicating the bottom row. + */ + +LOCAL void +expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols, + int input_rows, int output_rows) +{ + register int row; + + for (row = input_rows; row < output_rows; row++) { + jcopy_sample_rows(image_data, input_rows-1, image_data, row, + 1, num_cols); + } +} + + +/* + * Process some data in the simple no-context case. + * + * Preprocessor output data is counted in "row groups". A row group + * is defined to be v_samp_factor sample rows of each component. + * Downsampling will produce this much data from each max_v_samp_factor + * input rows. + */ + +METHODDEF void +pre_process_data (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + JDIMENSION inrows; + jpeg_component_info * compptr; + + while (*in_row_ctr < in_rows_avail && + *out_row_group_ctr < out_row_groups_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = cinfo->max_v_samp_factor - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + /* If at bottom of image, pad to fill the conversion buffer. */ + if (prep->rows_to_go == 0 && + prep->next_buf_row < cinfo->max_v_samp_factor) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, cinfo->max_v_samp_factor); + } + prep->next_buf_row = cinfo->max_v_samp_factor; + } + /* If we've filled the conversion buffer, empty it. */ + if (prep->next_buf_row == cinfo->max_v_samp_factor) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, (JDIMENSION) 0, + output_buf, *out_row_group_ctr); + prep->next_buf_row = 0; + (*out_row_group_ctr)++; + } + /* If at bottom of image, pad the output to a full iMCU height. + * Note we assume the caller is providing a one-iMCU-height output buffer! + */ + if (prep->rows_to_go == 0 && + *out_row_group_ctr < out_row_groups_avail) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + expand_bottom_edge(output_buf[ci], + compptr->width_in_blocks * DCTSIZE, + (int) (*out_row_group_ctr * compptr->v_samp_factor), + (int) (out_row_groups_avail * compptr->v_samp_factor)); + } + *out_row_group_ctr = out_row_groups_avail; + break; /* can exit outer loop without test */ + } + } +} + + +#ifdef CONTEXT_ROWS_SUPPORTED + +/* + * Process some data in the context case. + */ + +METHODDEF void +pre_process_context (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + int buf_height = cinfo->max_v_samp_factor * 3; + JDIMENSION inrows; + jpeg_component_info * compptr; + + while (*out_row_group_ctr < out_row_groups_avail) { + if (*in_row_ctr < in_rows_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = prep->next_buf_stop - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + /* Pad at top of image, if first time through */ + if (prep->rows_to_go == cinfo->image_height) { + for (ci = 0; ci < cinfo->num_components; ci++) { + int row; + for (row = 1; row <= cinfo->max_v_samp_factor; row++) { + jcopy_sample_rows(prep->color_buf[ci], 0, + prep->color_buf[ci], -row, + 1, cinfo->image_width); + } + } + } + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + } else { + /* Return for more data, unless we are at the bottom of the image. */ + if (prep->rows_to_go != 0) + break; + } + /* If at bottom of image, pad to fill the conversion buffer. */ + if (prep->rows_to_go == 0 && + prep->next_buf_row < prep->next_buf_stop) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, prep->next_buf_stop); + } + prep->next_buf_row = prep->next_buf_stop; + } + /* If we've gotten enough data, downsample a row group. */ + if (prep->next_buf_row == prep->next_buf_stop) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, + (JDIMENSION) prep->this_row_group, + output_buf, *out_row_group_ctr); + (*out_row_group_ctr)++; + /* Advance pointers with wraparound as necessary. */ + prep->this_row_group += cinfo->max_v_samp_factor; + if (prep->this_row_group >= buf_height) + prep->this_row_group = 0; + if (prep->next_buf_row >= buf_height) + prep->next_buf_row = 0; + prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor; + } + /* If at bottom of image, pad the output to a full iMCU height. + * Note we assume the caller is providing a one-iMCU-height output buffer! + */ + if (prep->rows_to_go == 0 && + *out_row_group_ctr < out_row_groups_avail) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + expand_bottom_edge(output_buf[ci], + compptr->width_in_blocks * DCTSIZE, + (int) (*out_row_group_ctr * compptr->v_samp_factor), + (int) (out_row_groups_avail * compptr->v_samp_factor)); + } + *out_row_group_ctr = out_row_groups_avail; + break; /* can exit outer loop without test */ + } + } +} + + +/* + * Create the wrapped-around downsampling input buffer needed for context mode. + */ + +LOCAL void +create_context_buffer (j_compress_ptr cinfo) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int rgroup_height = cinfo->max_v_samp_factor; + int ci, i; + jpeg_component_info * compptr; + JSAMPARRAY true_buffer, fake_buffer; + + /* Grab enough space for fake row pointers for all the components; + * we need five row groups' worth of pointers for each component. + */ + fake_buffer = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (cinfo->num_components * 5 * rgroup_height) * + SIZEOF(JSAMPROW)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate the actual buffer space (3 row groups) for this component. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + true_buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) (3 * rgroup_height)); + /* Copy true buffer row pointers into the middle of the fake row array */ + MEMCOPY(fake_buffer + rgroup_height, true_buffer, + 3 * rgroup_height * SIZEOF(JSAMPROW)); + /* Fill in the above and below wraparound pointers */ + for (i = 0; i < rgroup_height; i++) { + fake_buffer[i] = true_buffer[2 * rgroup_height + i]; + fake_buffer[4 * rgroup_height + i] = true_buffer[i]; + } + prep->color_buf[ci] = fake_buffer + rgroup_height; + fake_buffer += 5 * rgroup_height; /* point to space for next component */ + } +} + +#endif /* CONTEXT_ROWS_SUPPORTED */ + + +/* + * Initialize preprocessing controller. + */ + +GLOBAL void +jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_prep_ptr prep; + int ci; + jpeg_component_info * compptr; + + if (need_full_buffer) /* safety check */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + prep = (my_prep_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_prep_controller)); + cinfo->prep = (struct jpeg_c_prep_controller *) prep; + prep->pub.start_pass = start_pass_prep; + + /* Allocate the color conversion buffer. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + if (cinfo->downsample->need_context_rows) { + /* Set up to provide context rows */ +#ifdef CONTEXT_ROWS_SUPPORTED + prep->pub.pre_process_data = pre_process_context; + create_context_buffer(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* No context, just make it tall enough for one row group */ + prep->pub.pre_process_data = pre_process_data; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prep->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/engine/jpeg-6/jcsample.c b/engine/jpeg-6/jcsample.c new file mode 100644 index 0000000..bf0fb46 --- /dev/null +++ b/engine/jpeg-6/jcsample.c @@ -0,0 +1,519 @@ +/* + * jcsample.c + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains downsampling routines. + * + * Downsampling input data is counted in "row groups". A row group + * is defined to be max_v_samp_factor pixel rows of each component, + * from which the downsampler produces v_samp_factor sample rows. + * A single row group is processed in each call to the downsampler module. + * + * The downsampler is responsible for edge-expansion of its output data + * to fill an integral number of DCT blocks horizontally. The source buffer + * may be modified if it is helpful for this purpose (the source buffer is + * allocated wide enough to correspond to the desired output width). + * The caller (the prep controller) is responsible for vertical padding. + * + * The downsampler may request "context rows" by setting need_context_rows + * during startup. In this case, the input arrays will contain at least + * one row group's worth of pixels above and below the passed-in data; + * the caller will create dummy rows at image top and bottom by replicating + * the first or last real pixel row. + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + * + * The downsampling algorithm used here is a simple average of the source + * pixels covered by the output pixel. The hi-falutin sampling literature + * refers to this as a "box filter". In general the characteristics of a box + * filter are not very good, but for the specific cases we normally use (1:1 + * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not + * nearly so bad. If you intend to use other sampling ratios, you'd be well + * advised to improve this code. + * + * A simple input-smoothing capability is provided. This is mainly intended + * for cleaning up color-dithered GIF input files (if you find it inadequate, + * we suggest using an external filtering program such as pnmconvol). When + * enabled, each input pixel P is replaced by a weighted sum of itself and its + * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF, + * where SF = (smoothing_factor / 1024). + * Currently, smoothing is only supported for 2h2v sampling factors. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to downsample a single component */ +typedef JMETHOD(void, downsample1_ptr, + (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data)); + +/* Private subobject */ + +typedef struct { + struct jpeg_downsampler pub; /* public fields */ + + /* Downsampling method pointers, one per component */ + downsample1_ptr methods[MAX_COMPONENTS]; +} my_downsampler; + +typedef my_downsampler * my_downsample_ptr; + + +/* + * Initialize for a downsampling pass. + */ + +METHODDEF void +start_pass_downsample (j_compress_ptr cinfo) +{ + /* no work for now */ +} + + +/* + * Expand a component horizontally from width input_cols to width output_cols, + * by duplicating the rightmost samples. + */ + +LOCAL void +expand_right_edge (JSAMPARRAY image_data, int num_rows, + JDIMENSION input_cols, JDIMENSION output_cols) +{ + register JSAMPROW ptr; + register JSAMPLE pixval; + register int count; + int row; + int numcols = (int) (output_cols - input_cols); + + if (numcols > 0) { + for (row = 0; row < num_rows; row++) { + ptr = image_data[row] + input_cols; + pixval = ptr[-1]; /* don't need GETJSAMPLE() here */ + for (count = numcols; count > 0; count--) + *ptr++ = pixval; + } + } +} + + +/* + * Do downsampling for a whole row group (all components). + * + * In this version we simply downsample each component independently. + */ + +METHODDEF void +sep_downsample (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, JDIMENSION out_row_group_index) +{ + my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample; + int ci; + jpeg_component_info * compptr; + JSAMPARRAY in_ptr, out_ptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + in_ptr = input_buf[ci] + in_row_index; + out_ptr = output_buf[ci] + (out_row_group_index * compptr->v_samp_factor); + (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr); + } +} + + +/* + * Downsample pixel values of a single component. + * One row group is processed per call. + * This version handles arbitrary integral sampling ratios, without smoothing. + * Note that this version is not actually used for customary sampling ratios. + */ + +METHODDEF void +int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v; + JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */ + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + JSAMPROW inptr, outptr; + INT32 outvalue; + + h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor; + v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor; + numpix = h_expand * v_expand; + numpix2 = numpix/2; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * h_expand); + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + for (outcol = 0, outcol_h = 0; outcol < output_cols; + outcol++, outcol_h += h_expand) { + outvalue = 0; + for (v = 0; v < v_expand; v++) { + inptr = input_data[inrow+v] + outcol_h; + for (h = 0; h < h_expand; h++) { + outvalue += (INT32) GETJSAMPLE(*inptr++); + } + } + *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix); + } + inrow += v_expand; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * without smoothing. + */ + +METHODDEF void +fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + /* Copy the data */ + jcopy_sample_rows(input_data, 0, output_data, 0, + cinfo->max_v_samp_factor, cinfo->image_width); + /* Edge-expand */ + expand_right_edge(output_data, cinfo->max_v_samp_factor, + cinfo->image_width, compptr->width_in_blocks * DCTSIZE); +} + + +/* + * Downsample pixel values of a single component. + * This version handles the common case of 2:1 horizontal and 1:1 vertical, + * without smoothing. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF void +h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr = input_data[outrow]; + bias = 0; /* bias = 0,1,0,1,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1]) + + bias) >> 1); + bias ^= 1; /* 0=>1, 1=>0 */ + inptr += 2; + } + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * without smoothing. + */ + +METHODDEF void +h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr0, inptr1, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + bias = 1; /* bias = 1,2,1,2,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]) + + bias) >> 2); + bias ^= 3; /* 1=>2, 2=>1 */ + inptr0 += 2; inptr1 += 2; + } + inrow += 2; + } +} + + +#ifdef INPUT_SMOOTHING_SUPPORTED + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * with smoothing. One row of context is required. + */ + +METHODDEF void +h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols * 2); + + /* We don't bother to form the individual "smoothed" input pixel values; + * we can directly compute the output which is the average of the four + * smoothed values. Each of the four member pixels contributes a fraction + * (1-8*SF) to its own smoothed image and a fraction SF to each of the three + * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final + * output. The four corner-adjacent neighbor pixels contribute a fraction + * SF to just one smoothed pixel, or SF/4 to the final output; while the + * eight edge-adjacent neighbors contribute SF to each of two smoothed + * pixels, or SF/2 overall. In order to use integer arithmetic, these + * factors are scaled by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */ + neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */ + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + above_ptr = input_data[inrow-1]; + below_ptr = input_data[inrow+2]; + + /* Special case for first column: pretend column -1 is same as column 0 */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]); + neighsum += neighsum; + neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + /* sum of pixels directly mapped to this output element */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + /* sum of edge-neighbor pixels */ + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]); + /* The edge-neighbors count twice as much as corner-neighbors */ + neighsum += neighsum; + /* Add in the corner-neighbors */ + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]); + /* form final output scaled up by 2^16 */ + membersum = membersum * memberscale + neighsum * neighscale; + /* round, descale and output it */ + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]); + neighsum += neighsum; + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + inrow += 2; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * with smoothing. One row of context is required. + */ + +METHODDEF void +fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + int colsum, lastcolsum, nextcolsum; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols); + + /* Each of the eight neighbor pixels contributes a fraction SF to the + * smoothed pixel, while the main pixel contributes (1-8*SF). In order + * to use integer arithmetic, these factors are multiplied by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */ + neighscale = cinfo->smoothing_factor * 64; /* scaled SF */ + + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr = input_data[outrow]; + above_ptr = input_data[outrow-1]; + below_ptr = input_data[outrow+1]; + + /* Special case for first column */ + colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) + + GETJSAMPLE(*inptr); + membersum = GETJSAMPLE(*inptr++); + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = colsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + membersum = GETJSAMPLE(*inptr++); + above_ptr++; below_ptr++; + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + colsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + } +} + +#endif /* INPUT_SMOOTHING_SUPPORTED */ + + +/* + * Module initialization routine for downsampling. + * Note that we must select a routine for each component. + */ + +GLOBAL void +jinit_downsampler (j_compress_ptr cinfo) +{ + my_downsample_ptr downsample; + int ci; + jpeg_component_info * compptr; + boolean smoothok = TRUE; + + downsample = (my_downsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_downsampler)); + cinfo->downsample = (struct jpeg_downsampler *) downsample; + downsample->pub.start_pass = start_pass_downsample; + downsample->pub.downsample = sep_downsample; + downsample->pub.need_context_rows = FALSE; + + if (cinfo->CCIR601_sampling) + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* Verify we can handle the sampling factors, and set up method pointers */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = fullsize_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = fullsize_downsample; + } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) { + smoothok = FALSE; + downsample->methods[ci] = h2v1_downsample; + } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && + compptr->v_samp_factor * 2 == cinfo->max_v_samp_factor) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = h2v2_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = h2v2_downsample; + } else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 && + (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) { + smoothok = FALSE; + downsample->methods[ci] = int_downsample; + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + } + +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor && !smoothok) + TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL); +#endif +} diff --git a/engine/jpeg-6/jctrans.c b/engine/jpeg-6/jctrans.c new file mode 100644 index 0000000..8fc53b1 --- /dev/null +++ b/engine/jpeg-6/jctrans.c @@ -0,0 +1,371 @@ +/* + * jctrans.c + * + * Copyright (C) 1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding compression, + * that is, writing raw DCT coefficient arrays to an output JPEG file. + * The routines in jcapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL void transencode_master_selection + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); +LOCAL void transencode_coef_controller + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); + + +/* + * Compression initialization for writing raw-coefficient data. + * Before calling this, all parameters and a data destination must be set up. + * Call jpeg_finish_compress() to actually write the data. + * + * The number of passed virtual arrays must match cinfo->num_components. + * Note that the virtual arrays need not be filled or even realized at + * the time write_coefficients is called; indeed, if the virtual arrays + * were requested from this compression object's memory manager, they + * typically will be realized during this routine and filled afterwards. + */ + +GLOBAL void +jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Mark all tables to be written */ + jpeg_suppress_tables(cinfo, FALSE); + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + transencode_master_selection(cinfo, coef_arrays); + /* Wait for jpeg_finish_compress() call */ + cinfo->next_scanline = 0; /* so jpeg_write_marker works */ + cinfo->global_state = CSTATE_WRCOEFS; +} + + +/* + * Initialize the compression object with default parameters, + * then copy from the source object all parameters needed for lossless + * transcoding. Parameters that can be varied without loss (such as + * scan script and Huffman optimization) are left in their default states. + */ + +GLOBAL void +jpeg_copy_critical_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo) +{ + JQUANT_TBL ** qtblptr; + jpeg_component_info *incomp, *outcomp; + JQUANT_TBL *c_quant, *slot_quant; + int tblno, ci, coefi; + + /* Safety check to ensure start_compress not called yet. */ + if (dstinfo->global_state != CSTATE_START) + ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state); + /* Copy fundamental image dimensions */ + dstinfo->image_width = srcinfo->image_width; + dstinfo->image_height = srcinfo->image_height; + dstinfo->input_components = srcinfo->num_components; + dstinfo->in_color_space = srcinfo->jpeg_color_space; + /* Initialize all parameters to default values */ + jpeg_set_defaults(dstinfo); + /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB. + * Fix it to get the right header markers for the image colorspace. + */ + jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space); + dstinfo->data_precision = srcinfo->data_precision; + dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling; + /* Copy the source's quantization tables. */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + if (srcinfo->quant_tbl_ptrs[tblno] != NULL) { + qtblptr = & dstinfo->quant_tbl_ptrs[tblno]; + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo); + MEMCOPY((*qtblptr)->quantval, + srcinfo->quant_tbl_ptrs[tblno]->quantval, + SIZEOF((*qtblptr)->quantval)); + (*qtblptr)->sent_table = FALSE; + } + } + /* Copy the source's per-component info. + * Note we assume jpeg_set_defaults has allocated the dest comp_info array. + */ + dstinfo->num_components = srcinfo->num_components; + if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS) + ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components, + MAX_COMPONENTS); + for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info; + ci < dstinfo->num_components; ci++, incomp++, outcomp++) { + outcomp->component_id = incomp->component_id; + outcomp->h_samp_factor = incomp->h_samp_factor; + outcomp->v_samp_factor = incomp->v_samp_factor; + outcomp->quant_tbl_no = incomp->quant_tbl_no; + /* Make sure saved quantization table for component matches the qtable + * slot. If not, the input file re-used this qtable slot. + * IJG encoder currently cannot duplicate this. + */ + tblno = outcomp->quant_tbl_no; + if (tblno < 0 || tblno >= NUM_QUANT_TBLS || + srcinfo->quant_tbl_ptrs[tblno] == NULL) + ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno); + slot_quant = srcinfo->quant_tbl_ptrs[tblno]; + c_quant = incomp->quant_table; + if (c_quant != NULL) { + for (coefi = 0; coefi < DCTSIZE2; coefi++) { + if (c_quant->quantval[coefi] != slot_quant->quantval[coefi]) + ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno); + } + } + /* Note: we do not copy the source's Huffman table assignments; + * instead we rely on jpeg_set_colorspace to have made a suitable choice. + */ + } +} + + +/* + * Master selection of compression modules for transcoding. + * This substitutes for jcinit.c's initialization of the full compressor. + */ + +LOCAL void +transencode_master_selection (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + /* Although we don't actually use input_components for transcoding, + * jcmaster.c's initial_setup will complain if input_components is 0. + */ + cinfo->input_components = 1; + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, TRUE /* transcode only */); + + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + jinit_phuff_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_encoder(cinfo); + } + + /* We need a special coefficient buffer controller. */ + transencode_coef_controller(cinfo, coef_arrays); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} + + +/* + * The rest of this file is a special implementation of the coefficient + * buffer controller. This is similar to jccoefct.c, but it handles only + * output from presupplied virtual arrays. Furthermore, we generate any + * dummy padding blocks on-the-fly rather than expecting them to be present + * in the arrays. + */ + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_coef_controller pub; /* public fields */ + + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* Virtual block array for each component. */ + jvirt_barray_ptr * whole_image; + + /* Workspace for constructing dummy blocks at right/bottom edges. */ + JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU]; +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +LOCAL void +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF void +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + if (pass_mode != JBUF_CRANK_DEST) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); +} + + +/* + * Process some data. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF boolean +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, blockcnt; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yindex+yoffset < compptr->last_row_height) { + /* Fill in pointers to real blocks in this row */ + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < blockcnt; xindex++) + MCU_buffer[blkn++] = buffer_ptr++; + } else { + /* At bottom of image, need a whole row of dummy blocks */ + xindex = 0; + } + /* Fill in any dummy blocks needed in this row. + * Dummy blocks are filled in the same way as in jccoefct.c: + * all zeroes in the AC entries, DC entries equal to previous + * block's DC value. The init routine has already zeroed the + * AC entries, so we need only set the DC entries correctly. + */ + for (; xindex < compptr->MCU_width; xindex++) { + MCU_buffer[blkn] = coef->dummy_buffer[blkn]; + MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0]; + blkn++; + } + } + } + /* Try to write the MCU. */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +/* + * Initialize coefficient buffer controller. + * + * Each passed coefficient array must be the right size for that + * coefficient: width_in_blocks wide and height_in_blocks high, + * with unitheight at least v_samp_factor. + */ + +LOCAL void +transencode_coef_controller (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + my_coef_ptr coef; + JBLOCKROW buffer; + int i; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_c_coef_controller *) coef; + coef->pub.start_pass = start_pass_coef; + coef->pub.compress_data = compress_output; + + /* Save pointer to virtual arrays */ + coef->whole_image = coef_arrays; + + /* Allocate and pre-zero space for dummy DCT blocks. */ + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + jzero_far((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) { + coef->dummy_buffer[i] = buffer + i; + } +} diff --git a/engine/jpeg-6/jdapimin.c b/engine/jpeg-6/jdapimin.c new file mode 100644 index 0000000..d568187 --- /dev/null +++ b/engine/jpeg-6/jdapimin.c @@ -0,0 +1,398 @@ +/* + * jdapimin.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-decompression case or the + * transcoding-only case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jdapistd.c. But also see jcomapi.c for routines + * shared by compression and decompression, and jdtrans.c for the transcoding + * case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG decompression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL void +jpeg_create_decompress (j_decompress_ptr cinfo) +{ + int i; + + /* For debugging purposes, zero the whole master structure. + * But error manager pointer is already there, so save and restore it. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct)); + cinfo->err = err; + } + cinfo->is_decompressor = TRUE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->src = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + /* Initialize marker processor so application can override methods + * for COM, APPn markers before calling jpeg_read_header. + */ + jinit_marker_reader(cinfo); + + /* And initialize the overall input controller. */ + jinit_input_controller(cinfo); + + /* OK, I'm ready */ + cinfo->global_state = DSTATE_START; +} + + +/* + * Destruction of a JPEG decompression object + */ + +GLOBAL void +jpeg_destroy_decompress (j_decompress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG decompression operation, + * but don't destroy the object itself. + */ + +GLOBAL void +jpeg_abort_decompress (j_decompress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Install a special processing method for COM or APPn markers. + */ + +GLOBAL void +jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine) +{ + if (marker_code == JPEG_COM) + cinfo->marker->process_COM = routine; + else if (marker_code >= JPEG_APP0 && marker_code <= JPEG_APP0+15) + cinfo->marker->process_APPn[marker_code-JPEG_APP0] = routine; + else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} + + +/* + * Set default decompression parameters. + */ + +LOCAL void +default_decompress_parms (j_decompress_ptr cinfo) +{ + /* Guess the input colorspace, and set output colorspace accordingly. */ + /* (Wish JPEG committee had provided a real way to specify this...) */ + /* Note application may override our guesses. */ + switch (cinfo->num_components) { + case 1: + cinfo->jpeg_color_space = JCS_GRAYSCALE; + cinfo->out_color_space = JCS_GRAYSCALE; + break; + + case 3: + if (cinfo->saw_JFIF_marker) { + cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */ + } else if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_RGB; + break; + case 1: + cinfo->jpeg_color_space = JCS_YCbCr; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + break; + } + } else { + /* Saw no special markers, try to guess from the component IDs */ + int cid0 = cinfo->comp_info[0].component_id; + int cid1 = cinfo->comp_info[1].component_id; + int cid2 = cinfo->comp_info[2].component_id; + + if (cid0 == 1 && cid1 == 2 && cid2 == 3) + cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */ + else if (cid0 == 82 && cid1 == 71 && cid2 == 66) + cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */ + else { + TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + } + } + /* Always guess RGB is proper output colorspace. */ + cinfo->out_color_space = JCS_RGB; + break; + + case 4: + if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_CMYK; + break; + case 2: + cinfo->jpeg_color_space = JCS_YCCK; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */ + break; + } + } else { + /* No special markers, assume straight CMYK. */ + cinfo->jpeg_color_space = JCS_CMYK; + } + cinfo->out_color_space = JCS_CMYK; + break; + + default: + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->out_color_space = JCS_UNKNOWN; + break; + } + + /* Set defaults for other decompression parameters. */ + cinfo->scale_num = 1; /* 1:1 scaling */ + cinfo->scale_denom = 1; + cinfo->output_gamma = 1.0; + cinfo->buffered_image = FALSE; + cinfo->raw_data_out = FALSE; + cinfo->dct_method = JDCT_DEFAULT; + cinfo->do_fancy_upsampling = TRUE; + cinfo->do_block_smoothing = TRUE; + cinfo->quantize_colors = FALSE; + /* We set these in case application only sets quantize_colors. */ + cinfo->dither_mode = JDITHER_FS; +#ifdef QUANT_2PASS_SUPPORTED + cinfo->two_pass_quantize = TRUE; +#else + cinfo->two_pass_quantize = FALSE; +#endif + cinfo->desired_number_of_colors = 256; + cinfo->colormap = NULL; + /* Initialize for no mode change in buffered-image mode. */ + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; +} + + +/* + * Decompression startup: read start of JPEG datastream to see what's there. + * Need only initialize JPEG object and supply a data source before calling. + * + * This routine will read as far as the first SOS marker (ie, actual start of + * compressed data), and will save all tables and parameters in the JPEG + * object. It will also initialize the decompression parameters to default + * values, and finally return JPEG_HEADER_OK. On return, the application may + * adjust the decompression parameters and then call jpeg_start_decompress. + * (Or, if the application only wanted to determine the image parameters, + * the data need not be decompressed. In that case, call jpeg_abort or + * jpeg_destroy to release any temporary space.) + * If an abbreviated (tables only) datastream is presented, the routine will + * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then + * re-use the JPEG object to read the abbreviated image datastream(s). + * It is unnecessary (but OK) to call jpeg_abort in this case. + * The JPEG_SUSPENDED return code only occurs if the data source module + * requests suspension of the decompressor. In this case the application + * should load more source data and then re-call jpeg_read_header to resume + * processing. + * If a non-suspending data source is used and require_image is TRUE, then the + * return code need not be inspected since only JPEG_HEADER_OK is possible. + * + * This routine is now just a front end to jpeg_consume_input, with some + * extra error checking. + */ + +GLOBAL int +jpeg_read_header (j_decompress_ptr cinfo, boolean require_image) +{ + int retcode; + + if (cinfo->global_state != DSTATE_START && + cinfo->global_state != DSTATE_INHEADER) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + retcode = jpeg_consume_input(cinfo); + + switch (retcode) { + case JPEG_REACHED_SOS: + retcode = JPEG_HEADER_OK; + break; + case JPEG_REACHED_EOI: + if (require_image) /* Complain if application wanted an image */ + ERREXIT(cinfo, JERR_NO_IMAGE); + /* Reset to start state; it would be safer to require the application to + * call jpeg_abort, but we can't change it now for compatibility reasons. + * A side effect is to free any temporary memory (there shouldn't be any). + */ + jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */ + retcode = JPEG_HEADER_TABLES_ONLY; + break; + case JPEG_SUSPENDED: + /* no work */ + break; + } + + return retcode; +} + + +/* + * Consume data in advance of what the decompressor requires. + * This can be called at any time once the decompressor object has + * been created and a data source has been set up. + * + * This routine is essentially a state machine that handles a couple + * of critical state-transition actions, namely initial setup and + * transition from header scanning to ready-for-start_decompress. + * All the actual input is done via the input controller's consume_input + * method. + */ + +GLOBAL int +jpeg_consume_input (j_decompress_ptr cinfo) +{ + int retcode = JPEG_SUSPENDED; + + /* NB: every possible DSTATE value should be listed in this switch */ + switch (cinfo->global_state) { + case DSTATE_START: + /* Start-of-datastream actions: reset appropriate modules */ + (*cinfo->inputctl->reset_input_controller) (cinfo); + /* Initialize application's data source module */ + (*cinfo->src->init_source) (cinfo); + cinfo->global_state = DSTATE_INHEADER; + /*FALLTHROUGH*/ + case DSTATE_INHEADER: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */ + /* Set up default parameters based on header data */ + default_decompress_parms(cinfo); + /* Set global state: ready for start_decompress */ + cinfo->global_state = DSTATE_READY; + } + break; + case DSTATE_READY: + /* Can't advance past first SOS until start_decompress is called */ + retcode = JPEG_REACHED_SOS; + break; + case DSTATE_PRELOAD: + case DSTATE_PRESCAN: + case DSTATE_SCANNING: + case DSTATE_RAW_OK: + case DSTATE_BUFIMAGE: + case DSTATE_BUFPOST: + case DSTATE_STOPPING: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + break; + default: + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + return retcode; +} + + +/* + * Have we finished reading the input file? + */ + +GLOBAL boolean +jpeg_input_complete (j_decompress_ptr cinfo) +{ + /* Check for valid jpeg object */ + if (cinfo->global_state < DSTATE_START || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->eoi_reached; +} + + +/* + * Is there more than one scan? + */ + +GLOBAL boolean +jpeg_has_multiple_scans (j_decompress_ptr cinfo) +{ + /* Only valid after jpeg_read_header completes */ + if (cinfo->global_state < DSTATE_READY || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->has_multiple_scans; +} + + +/* + * Finish JPEG decompression. + * + * This will normally just verify the file trailer and release temp storage. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL boolean +jpeg_finish_decompress (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { + /* Terminate final pass of non-buffered mode */ + if (cinfo->output_scanline < cinfo->output_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state == DSTATE_BUFIMAGE) { + /* Finishing after a buffered-image operation */ + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state != DSTATE_STOPPING) { + /* STOPPING = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read until EOI */ + while (! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + /* Do final cleanup */ + (*cinfo->src->term_source) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); + return TRUE; +} diff --git a/engine/jpeg-6/jdapistd.c b/engine/jpeg-6/jdapistd.c new file mode 100644 index 0000000..e36f25c --- /dev/null +++ b/engine/jpeg-6/jdapistd.c @@ -0,0 +1,275 @@ +/* + * jdapistd.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-decompression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_decompress, it will end up linking in the entire decompressor. + * We thus must separate this file from jdapimin.c to avoid linking the + * whole decompression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL boolean output_pass_setup JPP((j_decompress_ptr cinfo)); + + +/* + * Decompression initialization. + * jpeg_read_header must be completed before calling this. + * + * If a multipass operating mode was selected, this will do all but the + * last pass, and thus may take a great deal of time. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL boolean +jpeg_start_decompress (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize master control, select active modules */ + jinit_master_decompress(cinfo); + if (cinfo->buffered_image) { + /* No more work here; expecting jpeg_start_output next */ + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; + } + cinfo->global_state = DSTATE_PRELOAD; + } + if (cinfo->global_state == DSTATE_PRELOAD) { + /* If file has multiple scans, absorb them all into the coef buffer */ + if (cinfo->inputctl->has_multiple_scans) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return FALSE; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* jdmaster underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + } + cinfo->output_scan_number = cinfo->input_scan_number; + } else if (cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any dummy output passes, and set up for the final pass */ + return output_pass_setup(cinfo); +} + + +/* + * Set up for an output pass, and perform any dummy pass(es) needed. + * Common subroutine for jpeg_start_decompress and jpeg_start_output. + * Entry: global_state = DSTATE_PRESCAN only if previously suspended. + * Exit: If done, returns TRUE and sets global_state for proper output mode. + * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN. + */ + +LOCAL boolean +output_pass_setup (j_decompress_ptr cinfo) +{ + if (cinfo->global_state != DSTATE_PRESCAN) { + /* First call: do pass setup */ + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; + cinfo->global_state = DSTATE_PRESCAN; + } + /* Loop over any required dummy passes */ + while (cinfo->master->is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Crank through the dummy pass */ + while (cinfo->output_scanline < cinfo->output_height) { + JDIMENSION last_scanline; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* Process some data */ + last_scanline = cinfo->output_scanline; + (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL, + &cinfo->output_scanline, (JDIMENSION) 0); + if (cinfo->output_scanline == last_scanline) + return FALSE; /* No progress made, must suspend */ + } + /* Finish up dummy pass, and set up for another one */ + (*cinfo->master->finish_output_pass) (cinfo); + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } + /* Ready for application to drive output pass through + * jpeg_read_scanlines or jpeg_read_raw_data. + */ + cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING; + return TRUE; +} + + +/* + * Read some scanlines of data from the JPEG decompressor. + * + * The return value will be the number of lines actually read. + * This may be less than the number requested in several cases, + * including bottom of image, data source suspension, and operating + * modes that emit multiple scanlines at a time. + * + * Note: we warn about excess calls to jpeg_read_scanlines() since + * this likely signals an application programmer error. However, + * an oversize buffer (max_lines > scanlines remaining) is not an error. + */ + +GLOBAL JDIMENSION +jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION max_lines) +{ + JDIMENSION row_ctr; + + if (cinfo->global_state != DSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Process some data */ + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines); + cinfo->output_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to read raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL JDIMENSION +jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION max_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != DSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Verify that at least one iMCU row can be returned. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size; + if (max_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Decompress directly into user's buffer. */ + if (! (*cinfo->coef->decompress_data) (cinfo, data)) + return 0; /* suspension forced, can do nothing more */ + + /* OK, we processed one iMCU row. */ + cinfo->output_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} + + +/* Additional entry points for buffered-image mode. */ + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Initialize for an output pass in buffered-image mode. + */ + +GLOBAL boolean +jpeg_start_output (j_decompress_ptr cinfo, int scan_number) +{ + if (cinfo->global_state != DSTATE_BUFIMAGE && + cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Limit scan number to valid range */ + if (scan_number <= 0) + scan_number = 1; + if (cinfo->inputctl->eoi_reached && + scan_number > cinfo->input_scan_number) + scan_number = cinfo->input_scan_number; + cinfo->output_scan_number = scan_number; + /* Perform any dummy output passes, and set up for the real pass */ + return output_pass_setup(cinfo); +} + + +/* + * Finish up after an output pass in buffered-image mode. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL boolean +jpeg_finish_output (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) { + /* Terminate this pass. */ + /* We do not require the whole pass to have been completed. */ + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_BUFPOST; + } else if (cinfo->global_state != DSTATE_BUFPOST) { + /* BUFPOST = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read markers looking for SOS or EOI */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ diff --git a/engine/jpeg-6/jdatadst.c b/engine/jpeg-6/jdatadst.c new file mode 100644 index 0000000..08c4daf --- /dev/null +++ b/engine/jpeg-6/jdatadst.c @@ -0,0 +1,151 @@ +/* + * jdatadst.c + * + * Copyright (C) 1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains compression data destination routines for the case of + * emitting JPEG data to a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * destination manager. + * IMPORTANT: we assume that fwrite() will correctly transcribe an array of + * JOCTETs into 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data destination object for stdio output */ + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + FILE * outfile; /* target stream */ + JOCTET * buffer; /* start of buffer */ +} my_destination_mgr; + +typedef my_destination_mgr * my_dest_ptr; + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ + +METHODDEF void +init_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ + +METHODDEF boolean +empty_output_buffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != + (size_t) OUTPUT_BUF_SIZE) + ERREXIT(cinfo, JERR_FILE_WRITE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF void +term_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) { + if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) + ERREXIT(cinfo, JERR_FILE_WRITE); + } + fflush(dest->outfile); + /* Make sure we wrote the output file OK */ + if (ferror(dest->outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * Prepare for output to a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing compression. + */ + +GLOBAL void +jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile) +{ + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_destination_mgr)); + } + + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; +} diff --git a/engine/jpeg-6/jdatasrc.c b/engine/jpeg-6/jdatasrc.c new file mode 100644 index 0000000..0bf7866 --- /dev/null +++ b/engine/jpeg-6/jdatasrc.c @@ -0,0 +1,204 @@ +/* + * jdatasrc.c + * + * Copyright (C) 1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + unsigned char *infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF void +init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF boolean +fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + memcpy( src->buffer, src->infile, INPUT_BUF_SIZE ); + + src->infile += INPUT_BUF_SIZE; + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = INPUT_BUF_SIZE; + src->start_of_file = FALSE; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF void +skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF void +term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL void +jpeg_stdio_src (j_decompress_ptr cinfo, unsigned char *infile) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * SIZEOF(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} diff --git a/engine/jpeg-6/jdcoefct.c b/engine/jpeg-6/jdcoefct.c new file mode 100644 index 0000000..ba153f5 --- /dev/null +++ b/engine/jpeg-6/jdcoefct.c @@ -0,0 +1,725 @@ +/* + * jdcoefct.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for decompression. + * This controller is the top level of the JPEG decompressor proper. + * The coefficient buffer lies between entropy decoding and inverse-DCT steps. + * + * In buffered-image mode, this controller is the interface between + * input-oriented processing and output-oriented processing. + * Also, the input side (only) is used when reading a file for transcoding. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +/* Block smoothing is only applicable for progressive JPEG, so: */ +#ifndef D_PROGRESSIVE_SUPPORTED +#undef BLOCK_SMOOTHING_SUPPORTED +#endif + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_coef_controller pub; /* public fields */ + + /* These variables keep track of the current location of the input side. */ + /* cinfo->input_iMCU_row is also used for this. */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* The output side's location is represented by cinfo->output_iMCU_row. */ + + /* In single-pass modes, it's sufficient to buffer just one MCU. + * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks, + * and let the entropy decoder write into that workspace each time. + * (On 80x86, the workspace is FAR even though it's not really very big; + * this is to keep the module interfaces unchanged when a large coefficient + * buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays; it is used only by the input side. + */ + JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU]; + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +#endif + +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* When doing block smoothing, we latch coefficient Al values here */ + int * coef_bits_latch; +#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ +#endif +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + +/* Forward declarations */ +METHODDEF int decompress_onepass + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#ifdef D_MULTISCAN_FILES_SUPPORTED +METHODDEF int decompress_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif +#ifdef BLOCK_SMOOTHING_SUPPORTED +LOCAL boolean smoothing_ok JPP((j_decompress_ptr cinfo)); +METHODDEF int decompress_smooth_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif + + +LOCAL void +start_iMCU_row (j_decompress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row (input side) */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->MCU_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF void +start_input_pass (j_decompress_ptr cinfo) +{ + cinfo->input_iMCU_row = 0; + start_iMCU_row(cinfo); +} + + +/* + * Initialize for an output processing pass. + */ + +METHODDEF void +start_output_pass (j_decompress_ptr cinfo) +{ +#ifdef BLOCK_SMOOTHING_SUPPORTED + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* If multipass, check to see whether to use block smoothing on this pass */ + if (coef->pub.coef_arrays != NULL) { + if (cinfo->do_block_smoothing && smoothing_ok(cinfo)) + coef->pub.decompress_data = decompress_smooth_data; + else + coef->pub.decompress_data = decompress_data; + } +#endif + cinfo->output_iMCU_row = 0; +} + + +/* + * Decompress and return some data in the single-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Input and output must run in lockstep since we have only a one-MCU buffer. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image. + * For single pass, this is the same as the components in the scan. + */ + +METHODDEF int +decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, useful_width; + JSAMPARRAY output_ptr; + JDIMENSION start_col, output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Loop to process as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ + jzero_far((void FAR *) coef->MCU_buffer[0], + (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK))); + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + /* Determine where data should go in output_buf and do the IDCT thing. + * We skip dummy blocks at the right and bottom edges (but blkn gets + * incremented past them!). Note the inner loop relies on having + * allocated the MCU_buffer[] blocks sequentially. + */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) { + blkn += compptr->MCU_blocks; + continue; + } + inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index]; + useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + output_ptr = output_buf[ci] + yoffset * compptr->DCT_scaled_size; + start_col = MCU_col_num * compptr->MCU_sample_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (cinfo->input_iMCU_row < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + output_col = start_col; + for (xindex = 0; xindex < useful_width; xindex++) { + (*inverse_DCT) (cinfo, compptr, + (JCOEFPTR) coef->MCU_buffer[blkn+xindex], + output_ptr, output_col); + output_col += compptr->DCT_scaled_size; + } + } + blkn += compptr->MCU_width; + output_ptr += compptr->DCT_scaled_size; + } + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + cinfo->output_iMCU_row++; + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Dummy consume-input routine for single-pass operation. + */ + +METHODDEF int +dummy_consume_data (j_decompress_ptr cinfo) +{ + return JPEG_SUSPENDED; /* Always indicate nothing was done */ +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Consume input data and store it in the full-image coefficient buffer. + * We read as much as one fully interleaved MCU row ("iMCU" row) per call, + * ie, v_samp_factor block rows for each component in the scan. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + */ + +METHODDEF int +consume_data (j_decompress_ptr cinfo) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + cinfo->input_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Note: entropy decoder expects buffer to be zeroed, + * but this is handled automatically by the memory manager + * because we requested a pre-zeroed array. + */ + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to fetch the MCU. */ + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Decompress and return some data in the multi-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image. + */ + +METHODDEF int +decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num; + int ci, block_row, block_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number < cinfo->output_scan_number || + (cinfo->input_scan_number == cinfo->output_scan_number && + cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + cinfo->output_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + output_col = 0; + for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) { + (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, + output_ptr, output_col); + buffer_ptr++; + output_col += compptr->DCT_scaled_size; + } + output_ptr += compptr->DCT_scaled_size; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +#ifdef BLOCK_SMOOTHING_SUPPORTED + +/* + * This code applies interblock smoothing as described by section K.8 + * of the JPEG standard: the first 5 AC coefficients are estimated from + * the DC values of a DCT block and its 8 neighboring blocks. + * We apply smoothing only for progressive JPEG decoding, and only if + * the coefficients it can estimate are not yet known to full precision. + */ + +/* + * Determine whether block smoothing is applicable and safe. + * We also latch the current states of the coef_bits[] entries for the + * AC coefficients; otherwise, if the input side of the decompressor + * advances into a new scan, we might think the coefficients are known + * more accurately than they really are. + */ + +LOCAL boolean +smoothing_ok (j_decompress_ptr cinfo) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + boolean smoothing_useful = FALSE; + int ci, coefi; + jpeg_component_info *compptr; + JQUANT_TBL * qtable; + int * coef_bits; + int * coef_bits_latch; + + if (! cinfo->progressive_mode || cinfo->coef_bits == NULL) + return FALSE; + + /* Allocate latch area if not already done */ + if (coef->coef_bits_latch == NULL) + coef->coef_bits_latch = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * + (SAVED_COEFS * SIZEOF(int))); + coef_bits_latch = coef->coef_bits_latch; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* All components' quantization values must already be latched. */ + if ((qtable = compptr->quant_table) == NULL) + return FALSE; + /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */ + for (coefi = 0; coefi <= 5; coefi++) { + if (qtable->quantval[coefi] == 0) + return FALSE; + } + /* DC values must be at least partly known for all components. */ + coef_bits = cinfo->coef_bits[ci]; + if (coef_bits[0] < 0) + return FALSE; + /* Block smoothing is helpful if some AC coefficients remain inaccurate. */ + for (coefi = 1; coefi <= 5; coefi++) { + coef_bits_latch[coefi] = coef_bits[coefi]; + if (coef_bits[coefi] != 0) + smoothing_useful = TRUE; + } + coef_bits_latch += SAVED_COEFS; + } + + return smoothing_useful; +} + + +/* + * Variant of decompress_data for use when doing block smoothing. + */ + +METHODDEF int +decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num, last_block_column; + int ci, block_row, block_rows, access_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr, prev_block_row, next_block_row; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + boolean first_row, last_row; + JBLOCK workspace; + int *coef_bits; + JQUANT_TBL *quanttbl; + INT32 Q00,Q01,Q02,Q10,Q11,Q20, num; + int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9; + int Al, pred; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if (cinfo->input_scan_number == cinfo->output_scan_number) { + /* If input is working on current scan, we ordinarily want it to + * have completed the current row. But if input scan is DC, + * we want it to keep one row ahead so that next block row's DC + * values are up to date. + */ + JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0; + if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta) + break; + } + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) { + block_rows = compptr->v_samp_factor; + access_rows = block_rows * 2; /* this and next iMCU row */ + last_row = FALSE; + } else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + access_rows = block_rows; /* this iMCU row only */ + last_row = TRUE; + } + /* Align the virtual buffer for this component. */ + if (cinfo->output_iMCU_row > 0) { + access_rows += compptr->v_samp_factor; /* prior iMCU row too */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor, + (JDIMENSION) access_rows, FALSE); + buffer += compptr->v_samp_factor; /* point to current iMCU row */ + first_row = FALSE; + } else { + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE); + first_row = TRUE; + } + /* Fetch component-dependent info */ + coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS); + quanttbl = compptr->quant_table; + Q00 = quanttbl->quantval[0]; + Q01 = quanttbl->quantval[1]; + Q10 = quanttbl->quantval[2]; + Q20 = quanttbl->quantval[3]; + Q11 = quanttbl->quantval[4]; + Q02 = quanttbl->quantval[5]; + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + if (first_row && block_row == 0) + prev_block_row = buffer_ptr; + else + prev_block_row = buffer[block_row-1]; + if (last_row && block_row == block_rows-1) + next_block_row = buffer_ptr; + else + next_block_row = buffer[block_row+1]; + /* We fetch the surrounding DC values using a sliding-register approach. + * Initialize all nine here so as to do the right thing on narrow pics. + */ + DC1 = DC2 = DC3 = (int) prev_block_row[0][0]; + DC4 = DC5 = DC6 = (int) buffer_ptr[0][0]; + DC7 = DC8 = DC9 = (int) next_block_row[0][0]; + output_col = 0; + last_block_column = compptr->width_in_blocks - 1; + for (block_num = 0; block_num <= last_block_column; block_num++) { + /* Fetch current DCT block into workspace so we can modify it. */ + jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1); + /* Update DC values */ + if (block_num < last_block_column) { + DC3 = (int) prev_block_row[1][0]; + DC6 = (int) buffer_ptr[1][0]; + DC9 = (int) next_block_row[1][0]; + } + /* Compute coefficient estimates per K.8. + * An estimate is applied only if coefficient is still zero, + * and is not known to be fully accurate. + */ + /* AC01 */ + if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) { + num = 36 * Q00 * (DC4 - DC6); + if (num >= 0) { + pred = (int) (((Q01<<7) + num) / (Q01<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q10<<7) + num) / (Q10<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q20<<7) + num) / (Q20<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q11<<7) + num) / (Q11<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q02<<7) + num) / (Q02<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<DCT_scaled_size; + } + output_ptr += compptr->DCT_scaled_size; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL void +jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_coef_ptr coef; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_d_coef_controller *) coef; + coef->pub.start_input_pass = start_input_pass; + coef->pub.start_output_pass = start_output_pass; +#ifdef BLOCK_SMOOTHING_SUPPORTED + coef->coef_bits_latch = NULL; +#endif + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + /* Note we ask for a pre-zeroed array. */ + int ci, access_rows; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + access_rows = compptr->v_samp_factor; +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* If block smoothing could be used, need a bigger window */ + if (cinfo->progressive_mode) + access_rows *= 3; +#endif + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) access_rows); + } + coef->pub.consume_data = consume_data; + coef->pub.decompress_data = decompress_data; + coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + coef->pub.consume_data = dummy_consume_data; + coef->pub.decompress_data = decompress_onepass; + coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */ + } +} diff --git a/engine/jpeg-6/jdcolor.c b/engine/jpeg-6/jdcolor.c new file mode 100644 index 0000000..b2bdf6e --- /dev/null +++ b/engine/jpeg-6/jdcolor.c @@ -0,0 +1,367 @@ +/* + * jdcolor.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains output colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_deconverter pub; /* public fields */ + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ +} my_color_deconverter; + +typedef my_color_deconverter * my_cconvert_ptr; + + +/**************** YCbCr -> RGB conversion: most common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * R = Y + 1.40200 * Cr + * G = Y - 0.34414 * Cb - 0.71414 * Cr + * B = Y + 1.77200 * Cb + * where Cb and Cr represent the incoming values less CENTERJSAMPLE. + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * Notice that Y, being an integral input, does not contribute any fraction + * so it need not participate in the rounding. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times Cb and Cr for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The Cr=>R and Cb=>B values can be rounded to integers in advance; the + * values for the G calculation are left scaled up, since we must add them + * together before rounding. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. + */ + +LOCAL void +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + int i; + INT32 x; + SHIFT_TEMPS + + cconvert->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.40200 * x */ + cconvert->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + cconvert->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + /* Cr=>G value is scaled-up -0.71414 * x */ + cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Convert some rows of samples to the output colorspace. + * + * Note that we change from noninterleaved, one-plane-per-component format + * to interleaved-pixel format. The output buffer is therefore three times + * as wide as the input buffer. + * A starting row offset is provided only for the input buffer. The caller + * can easily adjust the passed output_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF void +ycc_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; + outptr[RGB_GREEN] = range_limit[y + + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/**************** Cases other than YCbCr -> RGB **************/ + + +/* + * Color conversion for no colorspace change: just copy the data, + * converting from separate-planes to interleaved representation. + */ + +METHODDEF void +null_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION count; + register int num_components = cinfo->num_components; + JDIMENSION num_cols = cinfo->output_width; + int ci; + + while (--num_rows >= 0) { + for (ci = 0; ci < num_components; ci++) { + inptr = input_buf[ci][input_row]; + outptr = output_buf[0] + ci; + for (count = num_cols; count > 0; count--) { + *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */ + outptr += num_components; + } + } + input_row++; + output_buf++; + } +} + + +/* + * Color conversion for grayscale: just copy the data. + * This also works for YCbCr -> grayscale conversion, in which + * we just copy the Y (luminance) component and ignore chrominance. + */ + +METHODDEF void +grayscale_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0, + num_rows, cinfo->output_width); +} + + +/* + * Adobe-style YCCK->CMYK conversion. + * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same + * conversion as above, while passing K (black) unchanged. + * We assume build_ycc_rgb_table has been called. + */ + +METHODDEF void +ycck_cmyk_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2, inptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + inptr3 = input_buf[3][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ + outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)))]; + outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ + /* K passes through unchanged */ + outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */ + outptr += 4; + } + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF void +start_pass_dcolor (j_decompress_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Module initialization routine for output colorspace conversion. + */ + +GLOBAL void +jinit_color_deconverter (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + int ci; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_deconverter)); + cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert; + cconvert->pub.start_pass = start_pass_dcolor; + + /* Make sure num_components agrees with jpeg_color_space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_RGB: + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->num_components < 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + } + + /* Set out_color_components and conversion method based on requested space. + * Also clear the component_needed flags for any unused components, + * so that earlier pipeline stages can avoid useless computation. + */ + + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + if (cinfo->jpeg_color_space == JCS_GRAYSCALE || + cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = grayscale_convert; + /* For color->grayscale conversion, only the Y (0) component is needed */ + for (ci = 1; ci < cinfo->num_components; ci++) + cinfo->comp_info[ci].component_needed = FALSE; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + cinfo->out_color_components = RGB_PIXELSIZE; + if (cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = ycc_rgb_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) { + cconvert->pub.color_convert = null_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + cinfo->out_color_components = 4; + if (cinfo->jpeg_color_space == JCS_YCCK) { + cconvert->pub.color_convert = ycck_cmyk_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_CMYK) { + cconvert->pub.color_convert = null_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: + /* Permit null conversion to same output space */ + if (cinfo->out_color_space == cinfo->jpeg_color_space) { + cinfo->out_color_components = cinfo->num_components; + cconvert->pub.color_convert = null_convert; + } else /* unsupported non-null conversion */ + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + } + + if (cinfo->quantize_colors) + cinfo->output_components = 1; /* single colormapped output component */ + else + cinfo->output_components = cinfo->out_color_components; +} diff --git a/engine/jpeg-6/jdct.h b/engine/jpeg-6/jdct.h new file mode 100644 index 0000000..3ce790b --- /dev/null +++ b/engine/jpeg-6/jdct.h @@ -0,0 +1,176 @@ +/* + * jdct.h + * + * Copyright (C) 1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the forward and + * inverse DCT modules. These declarations are private to the DCT managers + * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. + * The individual DCT algorithms are kept in separate files to ease + * machine-dependent tuning (e.g., assembly coding). + */ + + +/* + * A forward DCT routine is given a pointer to a work area of type DCTELEM[]; + * the DCT is to be performed in-place in that buffer. Type DCTELEM is int + * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT + * implementations use an array of type FAST_FLOAT, instead.) + * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). + * The DCT outputs are returned scaled up by a factor of 8; they therefore + * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This + * convention improves accuracy in integer implementations and saves some + * work in floating-point ones. + * Quantization of the output coefficients is done by jcdctmgr.c. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef int DCTELEM; /* 16 or 32 bits is fine */ +#else +typedef INT32 DCTELEM; /* must have 32 bits */ +#endif + +typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data)); +typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data)); + + +/* + * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer + * to an output sample array. The routine must dequantize the input data as + * well as perform the IDCT; for dequantization, it uses the multiplier table + * pointed to by compptr->dct_table. The output data is to be placed into the + * sample array starting at a specified column. (Any row offset needed will + * be applied to the array pointer before it is passed to the IDCT code.) + * Note that the number of samples emitted by the IDCT routine is + * DCT_scaled_size * DCT_scaled_size. + */ + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + +/* + * Each IDCT routine has its own ideas about the best dct_table element type. + */ + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ +#if BITS_IN_JSAMPLE == 8 +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ +#else +typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ +#endif +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + +/* + * Each IDCT routine is responsible for range-limiting its results and + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + * be quite far out of range if the input data is corrupt, so a bulletproof + * range-limiting step is required. We use a mask-and-table-lookup method + * to do the combined operations quickly. See the comments with + * prepare_range_limit_table (in jdmaster.c) for more info. + */ + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) + +#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_fdct_islow jFDislow +#define jpeg_fdct_ifast jFDifast +#define jpeg_fdct_float jFDfloat +#define jpeg_idct_islow jRDislow +#define jpeg_idct_ifast jRDifast +#define jpeg_idct_float jRDfloat +#define jpeg_idct_4x4 jRD4x4 +#define jpeg_idct_2x2 jRD2x2 +#define jpeg_idct_1x1 jRD1x1 +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Extern declarations for the forward and inverse DCT routines. */ + +EXTERN void jpeg_fdct_islow JPP((DCTELEM * data)); +EXTERN void jpeg_fdct_ifast JPP((DCTELEM * data)); +EXTERN void jpeg_fdct_float JPP((FAST_FLOAT * data)); + +EXTERN void jpeg_idct_islow + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN void jpeg_idct_ifast + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN void jpeg_idct_float + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN void jpeg_idct_4x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN void jpeg_idct_2x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN void jpeg_idct_1x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + +/* + * Macros for handling fixed-point arithmetic; these are used by many + * but not all of the DCT/IDCT modules. + * + * All values are expected to be of type INT32. + * Fractional constants are scaled left by CONST_BITS bits. + * CONST_BITS is defined within each module using these macros, + * and may differ from one module to the next. + */ + +#define ONE ((INT32) 1) +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + * thus causing a lot of useless floating-point operations at run time. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * This macro is used only when the two inputs will actually be no more than + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + * full 32x32 multiply. This provides a useful speedup on many machines. + * Unfortunately there is no way to specify a 16x16->32 multiply portably + * in C, but some C compilers will do the right thing if you provide the + * correct combination of casts. + */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif + +#ifndef MULTIPLY16C16 /* default definition */ +#define MULTIPLY16C16(var,const) ((var) * (const)) +#endif + +/* Same except both inputs are variables. */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) +#endif + +#ifndef MULTIPLY16V16 /* default definition */ +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) +#endif diff --git a/engine/jpeg-6/jddctmgr.c b/engine/jpeg-6/jddctmgr.c new file mode 100644 index 0000000..71215f1 --- /dev/null +++ b/engine/jpeg-6/jddctmgr.c @@ -0,0 +1,270 @@ +/* + * jddctmgr.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the inverse-DCT management logic. + * This code selects a particular IDCT implementation to be used, + * and it performs related housekeeping chores. No code in this file + * is executed per IDCT step, only during output pass setup. + * + * Note that the IDCT routines are responsible for performing coefficient + * dequantization as well as the IDCT proper. This module sets up the + * dequantization multiplier table needed by the IDCT routine. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* + * The decompressor input side (jdinput.c) saves away the appropriate + * quantization table for each component at the start of the first scan + * involving that component. (This is necessary in order to correctly + * decode files that reuse Q-table slots.) + * When we are ready to make an output pass, the saved Q-table is converted + * to a multiplier table that will actually be used by the IDCT routine. + * The multiplier table contents are IDCT-method-dependent. To support + * application changes in IDCT method between scans, we can remake the + * multiplier tables if necessary. + * In buffered-image mode, the first output pass may occur before any data + * has been seen for some components, and thus before their Q-tables have + * been saved away. To handle this case, multiplier tables are preset + * to zeroes; the result of the IDCT will be a neutral gray level. + */ + + +/* Private subobject for this module */ + +typedef struct { + struct jpeg_inverse_dct pub; /* public fields */ + + /* This array contains the IDCT method code that each multiplier table + * is currently set up for, or -1 if it's not yet set up. + * The actual multiplier tables are pointed to by dct_table in the + * per-component comp_info structures. + */ + int cur_method[MAX_COMPONENTS]; +} my_idct_controller; + +typedef my_idct_controller * my_idct_ptr; + + +/* Allocated multiplier tables: big enough for any supported variant */ + +typedef union { + ISLOW_MULT_TYPE islow_array[DCTSIZE2]; +#ifdef DCT_IFAST_SUPPORTED + IFAST_MULT_TYPE ifast_array[DCTSIZE2]; +#endif +#ifdef DCT_FLOAT_SUPPORTED + FLOAT_MULT_TYPE float_array[DCTSIZE2]; +#endif +} multiplier_table; + + +/* The current scaled-IDCT routines require ISLOW-style multiplier tables, + * so be sure to compile that code if either ISLOW or SCALING is requested. + */ +#ifdef DCT_ISLOW_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#else +#ifdef IDCT_SCALING_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#endif +#endif + + +/* + * Prepare for an output pass. + * Here we select the proper IDCT routine for each component and build + * a matching multiplier table. + */ + +METHODDEF void +start_pass (j_decompress_ptr cinfo) +{ + my_idct_ptr idct = (my_idct_ptr) cinfo->idct; + int ci, i; + jpeg_component_info *compptr; + int method = 0; + inverse_DCT_method_ptr method_ptr = NULL; + JQUANT_TBL * qtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Select the proper IDCT routine for this component's scaling */ + switch (compptr->DCT_scaled_size) { +#ifdef IDCT_SCALING_SUPPORTED + case 1: + method_ptr = jpeg_idct_1x1; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; + case 2: + method_ptr = jpeg_idct_2x2; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; + case 4: + method_ptr = jpeg_idct_4x4; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; +#endif + case DCTSIZE: + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + method_ptr = jpeg_idct_islow; + method = JDCT_ISLOW; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + method_ptr = jpeg_idct_ifast; + method = JDCT_IFAST; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + method_ptr = jpeg_idct_float; + method = JDCT_FLOAT; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + break; + default: + ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->DCT_scaled_size); + break; + } + idct->pub.inverse_DCT[ci] = method_ptr; + /* Create multiplier table from quant table. + * However, we can skip this if the component is uninteresting + * or if we already built the table. Also, if no quant table + * has yet been saved for the component, we leave the + * multiplier table all-zero; we'll be reading zeroes from the + * coefficient controller's buffer anyway. + */ + if (! compptr->component_needed || idct->cur_method[ci] == method) + continue; + qtbl = compptr->quant_table; + if (qtbl == NULL) /* happens if no data yet for component */ + continue; + idct->cur_method[ci] = method; + switch (method) { +#ifdef PROVIDE_ISLOW_TABLES + case JDCT_ISLOW: + { + /* For LL&M IDCT method, multipliers are equal to raw quantization + * coefficients, but are stored in natural order as ints. + */ + ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table; + for (i = 0; i < DCTSIZE2; i++) { + ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[jpeg_zigzag_order[i]]; + } + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * For integer operation, the multiplier table is to be scaled by + * IFAST_SCALE_BITS. The multipliers are stored in natural order. + */ + IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table; +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + for (i = 0; i < DCTSIZE2; i++) { + ifmtbl[i] = (IFAST_MULT_TYPE) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[jpeg_zigzag_order[i]], + (INT32) aanscales[i]), + CONST_BITS-IFAST_SCALE_BITS); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * The multipliers are stored in natural order. + */ + FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fmtbl[i] = (FLOAT_MULT_TYPE) + ((double) qtbl->quantval[jpeg_zigzag_order[i]] * + aanscalefactor[row] * aanscalefactor[col]); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Initialize IDCT manager. + */ + +GLOBAL void +jinit_inverse_dct (j_decompress_ptr cinfo) +{ + my_idct_ptr idct; + int ci; + jpeg_component_info *compptr; + + idct = (my_idct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_idct_controller)); + cinfo->idct = (struct jpeg_inverse_dct *) idct; + idct->pub.start_pass = start_pass; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate and pre-zero a multiplier table for each component */ + compptr->dct_table = + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(multiplier_table)); + MEMZERO(compptr->dct_table, SIZEOF(multiplier_table)); + /* Mark multiplier table not yet set up for any method */ + idct->cur_method[ci] = -1; + } +} diff --git a/engine/jpeg-6/jdhuff.c b/engine/jpeg-6/jdhuff.c new file mode 100644 index 0000000..95174b1 --- /dev/null +++ b/engine/jpeg-6/jdhuff.c @@ -0,0 +1,574 @@ +/* + * jdhuff.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdhuff.h" /* Declarations shared with jdphuff.c */ + + +/* + * Expanded entropy decoder object for Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_decoder pub; /* public fields */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + bitread_perm_state bitstate; /* Bit buffer at start of MCU */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; +} huff_entropy_decoder; + +typedef huff_entropy_decoder * huff_entropy_ptr; + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF void +start_pass_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + + /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. + * This ought to be an error condition, but we make it a warning because + * there are some baseline files out there with all zeroes in these bytes. + */ + if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 || + cinfo->Ah != 0 || cinfo->Al != 0) + WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + /* Make sure requested tables are present */ + if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS || + cinfo->dc_huff_tbl_ptrs[dctbl] == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); + if (actbl < 0 || actbl >= NUM_HUFF_TBLS || + cinfo->ac_huff_tbl_ptrs[actbl] == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl); + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_d_derived_tbl(cinfo, cinfo->dc_huff_tbl_ptrs[dctbl], + & entropy->dc_derived_tbls[dctbl]); + jpeg_make_d_derived_tbl(cinfo, cinfo->ac_huff_tbl_ptrs[actbl], + & entropy->ac_derived_tbls[actbl]); + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->bitstate.printed_eod = FALSE; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Compute the derived values for a Huffman table. + * Note this is also used by jdphuff.c. + */ + +GLOBAL void +jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, JHUFF_TBL * htbl, + d_derived_tbl ** pdtbl) +{ + d_derived_tbl *dtbl; + int p, i, l, si; + int lookbits, ctr; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (d_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(d_derived_tbl)); + dtbl = *pdtbl; + dtbl->pub = htbl; /* fill in back link */ + + /* Figure C.1: make table of Huffman code length for each symbol */ + /* Note that this is in code-length order. */ + + p = 0; + for (l = 1; l <= 16; l++) { + for (i = 1; i <= (int) htbl->bits[l]; i++) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + + /* Figure C.2: generate the codes themselves */ + /* Note that this is in code-length order. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + code <<= 1; + si++; + } + + /* Figure F.15: generate decoding tables for bit-sequential decoding */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + dtbl->valptr[l] = p; /* huffval[] index of 1st symbol of code length l */ + dtbl->mincode[l] = huffcode[p]; /* minimum code of length l */ + p += htbl->bits[l]; + dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ + } + } + dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */ + + /* Compute lookahead tables to speed up decoding. + * First we set all the table entries to 0, indicating "too long"; + * then we iterate through the Huffman codes that are short enough and + * fill in all the entries that correspond to bit sequences starting + * with that code. + */ + + MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits)); + + p = 0; + for (l = 1; l <= HUFF_LOOKAHEAD; l++) { + for (i = 1; i <= (int) htbl->bits[l]; i++, p++) { + /* l = current code's length, p = its index in huffcode[] & huffval[]. */ + /* Generate left-justified code followed by all possible bit sequences */ + lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); + for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) { + dtbl->look_nbits[lookbits] = l; + dtbl->look_sym[lookbits] = htbl->huffval[p]; + lookbits++; + } + } + } +} + + +/* + * Out-of-line code for bit fetching (shared with jdphuff.c). + * See jdhuff.h for info about usage. + * Note: current values of get_buffer and bits_left are passed as parameters, + * but are returned in the corresponding fields of the state struct. + * + * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width + * of get_buffer to be used. (On machines with wider words, an even larger + * buffer could be used.) However, on some machines 32-bit shifts are + * quite slow and take time proportional to the number of places shifted. + * (This is true with most PC compilers, for instance.) In this case it may + * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the + * average shift distance at the cost of more calls to jpeg_fill_bit_buffer. + */ + +#ifdef SLOW_SHIFT_32 +#define MIN_GET_BITS 15 /* minimum allowable value */ +#else +#define MIN_GET_BITS (BIT_BUF_SIZE-7) +#endif + + +GLOBAL boolean +jpeg_fill_bit_buffer (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + int nbits) +/* Load up the bit buffer to a depth of at least nbits */ +{ + /* Copy heavily used state fields into locals (hopefully registers) */ + register const JOCTET * next_input_byte = state->next_input_byte; + register size_t bytes_in_buffer = state->bytes_in_buffer; + register int c; + + /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */ + /* (It is assumed that no request will be for more than that many bits.) */ + + while (bits_left < MIN_GET_BITS) { + /* Attempt to read a byte */ + if (state->unread_marker != 0) + goto no_more_data; /* can't advance past a marker */ + + if (bytes_in_buffer == 0) { + if (! (*state->cinfo->src->fill_input_buffer) (state->cinfo)) + return FALSE; + next_input_byte = state->cinfo->src->next_input_byte; + bytes_in_buffer = state->cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + + /* If it's 0xFF, check and discard stuffed zero byte */ + if (c == 0xFF) { + do { + if (bytes_in_buffer == 0) { + if (! (*state->cinfo->src->fill_input_buffer) (state->cinfo)) + return FALSE; + next_input_byte = state->cinfo->src->next_input_byte; + bytes_in_buffer = state->cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + } while (c == 0xFF); + + if (c == 0) { + /* Found FF/00, which represents an FF data byte */ + c = 0xFF; + } else { + /* Oops, it's actually a marker indicating end of compressed data. */ + /* Better put it back for use later */ + state->unread_marker = c; + + no_more_data: + /* There should be enough bits still left in the data segment; */ + /* if so, just break out of the outer while loop. */ + if (bits_left >= nbits) + break; + /* Uh-oh. Report corrupted data to user and stuff zeroes into + * the data stream, so that we can produce some kind of image. + * Note that this code will be repeated for each byte demanded + * for the rest of the segment. We use a nonvolatile flag to ensure + * that only one warning message appears. + */ + if (! *(state->printed_eod_ptr)) { + WARNMS(state->cinfo, JWRN_HIT_MARKER); + *(state->printed_eod_ptr) = TRUE; + } + c = 0; /* insert a zero byte into bit buffer */ + } + } + + /* OK, load c into get_buffer */ + get_buffer = (get_buffer << 8) | c; + bits_left += 8; + } + + /* Unload the local registers */ + state->next_input_byte = next_input_byte; + state->bytes_in_buffer = bytes_in_buffer; + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + return TRUE; +} + + +/* + * Out-of-line code for Huffman code decoding. + * See jdhuff.h for info about usage. + */ + +GLOBAL int +jpeg_huff_decode (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + d_derived_tbl * htbl, int min_bits) +{ + register int l = min_bits; + register INT32 code; + + /* HUFF_DECODE has determined that the code is at least min_bits */ + /* bits long, so fetch that many bits in one swoop. */ + + CHECK_BIT_BUFFER(*state, l, return -1); + code = GET_BITS(l); + + /* Collect the rest of the Huffman code one bit at a time. */ + /* This is per Figure F.16 in the JPEG spec. */ + + while (code > htbl->maxcode[l]) { + code <<= 1; + CHECK_BIT_BUFFER(*state, 1, return -1); + code |= GET_BITS(1); + l++; + } + + /* Unload the local registers */ + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + /* With garbage input we may reach the sentinel value l = 17. */ + + if (l > 16) { + WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE); + return 0; /* fake a zero as the safest result */ + } + + return htbl->pub->huffval[ htbl->valptr[l] + + ((int) (code - htbl->mincode[l])) ]; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL boolean +process_restart (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Next segment can get another out-of-data warning */ + entropy->bitstate.printed_eod = FALSE; + + return TRUE; +} + + +/* + * Decode and return one MCU's worth of Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER. + * (Wholesale zeroing is usually a little faster than retail...) + * + * Returns FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * this module, since we'll just re-assign them on the next call.) + */ + +METHODDEF boolean +decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + register int s, k, r; + int blkn, ci; + JBLOCKROW block; + BITREAD_STATE_VARS; + savable_state state; + d_derived_tbl * dctbl; + d_derived_tbl * actbl; + jpeg_component_info * compptr; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + dctbl = entropy->dc_derived_tbls[compptr->dc_tbl_no]; + actbl = entropy->ac_derived_tbls[compptr->ac_tbl_no]; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, dctbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + /* Shortcut if component's values are not interesting */ + if (! compptr->component_needed) + goto skip_ACs; + + /* Convert DC difference to actual value, update last_dc_val */ + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */ + (*block)[0] = (JCOEF) s; + + /* Do we need to decode the AC coefficients for this component? */ + if (compptr->DCT_scaled_size > 1) { + + /* Section F.2.2.2: decode the AC coefficients */ + /* Since zeroes are skipped, output area must be cleared beforehand */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label2); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Output coefficient in natural (dezigzagged) order. + * Note: the extra entries in jpeg_natural_order[] will save us + * if k >= DCTSIZE2, which could happen if the data is corrupted. + */ + (*block)[jpeg_natural_order[k]] = (JCOEF) s; + } else { + if (r != 15) + break; + k += 15; + } + } + + } else { +skip_ACs: + + /* Section F.2.2.2: decode the AC coefficients */ + /* In this path we just discard the values */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + + } + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * Module initialization routine for Huffman entropy decoding. + */ + +GLOBAL void +jinit_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(huff_entropy_decoder)); + cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; + entropy->pub.start_pass = start_pass_huff_decoder; + entropy->pub.decode_mcu = decode_mcu; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + } +} diff --git a/engine/jpeg-6/jdhuff.h b/engine/jpeg-6/jdhuff.h new file mode 100644 index 0000000..d375c78 --- /dev/null +++ b/engine/jpeg-6/jdhuff.h @@ -0,0 +1,202 @@ +/* + * jdhuff.h + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy decoding routines + * that are shared between the sequential decoder (jdhuff.c) and the + * progressive decoder (jdphuff.c). No other modules need to see these. + */ + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_d_derived_tbl jMkDDerived +#define jpeg_fill_bit_buffer jFilBitBuf +#define jpeg_huff_decode jHufDecode +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + INT32 mincode[17]; /* smallest code of length k */ + INT32 maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + int valptr[17]; /* huffval[] index of 1st symbol of length k */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from these tables. + */ + int look_nbits[1< 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't do this with + * something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + boolean printed_eod; /* flag to suppress multiple warning msgs */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* current data source state */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + int unread_marker; /* nonzero if we have hit a marker */ + /* bit input buffer --- note these values are kept in register variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* pointers needed by jpeg_fill_bit_buffer */ + j_decompress_ptr cinfo; /* back link to decompress master record */ + boolean * printed_eod_ptr; /* => flag in permanent state */ +} bitread_working_state; + +/* Macros to declare and load/save bitread local variables. */ +#define BITREAD_STATE_VARS \ + register bit_buf_type get_buffer; \ + register int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + br_state.unread_marker = cinfop->unread_marker; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; \ + br_state.printed_eod_ptr = & permstate.printed_eod + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + cinfop->unread_marker = br_state.unread_marker; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + +/* Load up the bit buffer to a depth of at least nbits */ +EXTERN boolean jpeg_fill_bit_buffer JPP((bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + int nbits)); + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ register int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = htbl->look_nbits[look]) != 0) { \ + DROP_BITS(nb); \ + result = htbl->look_sym[look]; \ + } else { \ + nb = HUFF_LOOKAHEAD+1; \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + +/* Out-of-line case for Huffman code fetching */ +EXTERN int jpeg_huff_decode JPP((bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + d_derived_tbl * htbl, int min_bits)); diff --git a/engine/jpeg-6/jdinput.c b/engine/jpeg-6/jdinput.c new file mode 100644 index 0000000..3061a17 --- /dev/null +++ b/engine/jpeg-6/jdinput.c @@ -0,0 +1,381 @@ +/* + * jdinput.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input control logic for the JPEG decompressor. + * These routines are concerned with controlling the decompressor's input + * processing (marker reading and coefficient decoding). The actual input + * reading is done in jdmarker.c, jdhuff.c, and jdphuff.c. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_input_controller pub; /* public fields */ + + boolean inheaders; /* TRUE until first SOS is reached */ +} my_input_controller; + +typedef my_input_controller * my_inputctl_ptr; + + +/* Forward declarations */ +METHODDEF int consume_markers JPP((j_decompress_ptr cinfo)); + + +/* + * Routines to calculate various quantities related to the size of the image. + */ + +LOCAL void +initial_setup (j_decompress_ptr cinfo) +/* Called once, when first SOS marker is reached */ +{ + int ci; + jpeg_component_info *compptr; + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE. + * In the full decompressor, this will be overridden by jdmaster.c; + * but in the transcoder, jdmaster.c is not used, so we must do it here. + */ + cinfo->min_DCT_scaled_size = DCTSIZE; + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->DCT_scaled_size = DCTSIZE; + /* Size in DCT blocks */ + compptr->width_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->height_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + /* downsampled_width and downsampled_height will also be overridden by + * jdmaster.c if we are doing full decompression. The transcoder library + * doesn't use these values, but the calling application might. + */ + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed, until color conversion says otherwise */ + compptr->component_needed = TRUE; + /* Mark no quantization table yet saved for component */ + compptr->quant_table = NULL; + } + + /* Compute number of fully interleaved MCU rows. */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); + + /* Decide whether file contains multiple scans */ + if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode) + cinfo->inputctl->has_multiple_scans = TRUE; + else + cinfo->inputctl->has_multiple_scans = FALSE; +} + + +LOCAL void +per_scan_setup (j_decompress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_blocks; + cinfo->MCU_rows_in_scan = compptr->height_in_blocks; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + compptr->MCU_sample_width = compptr->DCT_scaled_size; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor*DCTSIZE)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_scaled_size; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + } +} + + +/* + * Save away a copy of the Q-table referenced by each component present + * in the current scan, unless already saved during a prior scan. + * + * In a multiple-scan JPEG file, the encoder could assign different components + * the same Q-table slot number, but change table definitions between scans + * so that each component uses a different Q-table. (The IJG encoder is not + * currently capable of doing this, but other encoders might.) Since we want + * to be able to dequantize all the components at the end of the file, this + * means that we have to save away the table actually used for each component. + * We do this by copying the table at the start of the first scan containing + * the component. + * The JPEG spec prohibits the encoder from changing the contents of a Q-table + * slot between scans of a component using that slot. If the encoder does so + * anyway, this decoder will simply use the Q-table values that were current + * at the start of the first scan for the component. + * + * The decompressor output side looks only at the saved quant tables, + * not at the current Q-table slots. + */ + +LOCAL void +latch_quant_tables (j_decompress_ptr cinfo) +{ + int ci, qtblno; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* No work if we already saved Q-table for this component */ + if (compptr->quant_table != NULL) + continue; + /* Make sure specified quantization table is present */ + qtblno = compptr->quant_tbl_no; + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + /* OK, save away the quantization table */ + qtbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(JQUANT_TBL)); + MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL)); + compptr->quant_table = qtbl; + } +} + + +/* + * Initialize the input modules to read a scan of compressed data. + * The first call to this is done by jdmaster.c after initializing + * the entire decompressor (during jpeg_start_decompress). + * Subsequent calls come from consume_markers, below. + */ + +METHODDEF void +start_input_pass (j_decompress_ptr cinfo) +{ + per_scan_setup(cinfo); + latch_quant_tables(cinfo); + (*cinfo->entropy->start_pass) (cinfo); + (*cinfo->coef->start_input_pass) (cinfo); + cinfo->inputctl->consume_input = cinfo->coef->consume_data; +} + + +/* + * Finish up after inputting a compressed-data scan. + * This is called by the coefficient controller after it's read all + * the expected data of the scan. + */ + +METHODDEF void +finish_input_pass (j_decompress_ptr cinfo) +{ + cinfo->inputctl->consume_input = consume_markers; +} + + +/* + * Read JPEG markers before, between, or after compressed-data scans. + * Change state as necessary when a new scan is reached. + * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + * + * The consume_input method pointer points either here or to the + * coefficient controller's consume_data routine, depending on whether + * we are reading a compressed data segment or inter-segment markers. + */ + +METHODDEF int +consume_markers (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + int val; + + if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */ + return JPEG_REACHED_EOI; + + val = (*cinfo->marker->read_markers) (cinfo); + + switch (val) { + case JPEG_REACHED_SOS: /* Found SOS */ + if (inputctl->inheaders) { /* 1st SOS */ + initial_setup(cinfo); + inputctl->inheaders = FALSE; + /* Note: start_input_pass must be called by jdmaster.c + * before any more input can be consumed. jdapi.c is + * responsible for enforcing this sequencing. + */ + } else { /* 2nd or later SOS marker */ + if (! inputctl->pub.has_multiple_scans) + ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */ + start_input_pass(cinfo); + } + break; + case JPEG_REACHED_EOI: /* Found EOI */ + inputctl->pub.eoi_reached = TRUE; + if (inputctl->inheaders) { /* Tables-only datastream, apparently */ + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_NO_SOS); + } else { + /* Prevent infinite loop in coef ctlr's decompress_data routine + * if user set output_scan_number larger than number of scans. + */ + if (cinfo->output_scan_number > cinfo->input_scan_number) + cinfo->output_scan_number = cinfo->input_scan_number; + } + break; + case JPEG_SUSPENDED: + break; + } + + return val; +} + + +/* + * Reset state to begin a fresh datastream. + */ + +METHODDEF void +reset_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + + inputctl->pub.consume_input = consume_markers; + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = TRUE; + /* Reset other modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->marker->reset_marker_reader) (cinfo); + /* Reset progression state -- would be cleaner if entropy decoder did this */ + cinfo->coef_bits = NULL; +} + + +/* + * Initialize the input controller module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL void +jinit_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl; + + /* Create subobject in permanent pool */ + inputctl = (my_inputctl_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_input_controller)); + cinfo->inputctl = (struct jpeg_input_controller *) inputctl; + /* Initialize method pointers */ + inputctl->pub.consume_input = consume_markers; + inputctl->pub.reset_input_controller = reset_input_controller; + inputctl->pub.start_input_pass = start_input_pass; + inputctl->pub.finish_input_pass = finish_input_pass; + /* Initialize state: can't use reset_input_controller since we don't + * want to try to reset other modules yet. + */ + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = TRUE; +} diff --git a/engine/jpeg-6/jdmainct.c b/engine/jpeg-6/jdmainct.c new file mode 100644 index 0000000..6cb0b7a --- /dev/null +++ b/engine/jpeg-6/jdmainct.c @@ -0,0 +1,520 @@ +/* + * jdmainct.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for decompression. + * The main buffer lies between the JPEG decompressor proper and the + * post-processor; it holds downsampled data in the JPEG colorspace. + * + * Note that this code is bypassed in raw-data mode, since the application + * supplies the equivalent of the main buffer in that case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * In the current system design, the main buffer need never be a full-image + * buffer; any full-height buffers will be found inside the coefficient or + * postprocessing controllers. Nonetheless, the main controller is not + * trivial. Its responsibility is to provide context rows for upsampling/ + * rescaling, and doing this in an efficient fashion is a bit tricky. + * + * Postprocessor input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) + * sample rows of each component. (We require DCT_scaled_size values to be + * chosen such that these numbers are integers. In practice DCT_scaled_size + * values will likely be powers of two, so we actually have the stronger + * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.) + * Upsampling will typically produce max_v_samp_factor pixel rows from each + * row group (times any additional scale factor that the upsampler is + * applying). + * + * The coefficient controller will deliver data to us one iMCU row at a time; + * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or + * exactly min_DCT_scaled_size row groups. (This amount of data corresponds + * to one row of MCUs when the image is fully interleaved.) Note that the + * number of sample rows varies across components, but the number of row + * groups does not. Some garbage sample rows may be included in the last iMCU + * row at the bottom of the image. + * + * Depending on the vertical scaling algorithm used, the upsampler may need + * access to the sample row(s) above and below its current input row group. + * The upsampler is required to set need_context_rows TRUE at global selection + * time if so. When need_context_rows is FALSE, this controller can simply + * obtain one iMCU row at a time from the coefficient controller and dole it + * out as row groups to the postprocessor. + * + * When need_context_rows is TRUE, this controller guarantees that the buffer + * passed to postprocessing contains at least one row group's worth of samples + * above and below the row group(s) being processed. Note that the context + * rows "above" the first passed row group appear at negative row offsets in + * the passed buffer. At the top and bottom of the image, the required + * context rows are manufactured by duplicating the first or last real sample + * row; this avoids having special cases in the upsampling inner loops. + * + * The amount of context is fixed at one row group just because that's a + * convenient number for this controller to work with. The existing + * upsamplers really only need one sample row of context. An upsampler + * supporting arbitrary output rescaling might wish for more than one row + * group of context when shrinking the image; tough, we don't handle that. + * (This is justified by the assumption that downsizing will be handled mostly + * by adjusting the DCT_scaled_size values, so that the actual scale factor at + * the upsample step needn't be much less than one.) + * + * To provide the desired context, we have to retain the last two row groups + * of one iMCU row while reading in the next iMCU row. (The last row group + * can't be processed until we have another row group for its below-context, + * and so we have to save the next-to-last group too for its above-context.) + * We could do this most simply by copying data around in our buffer, but + * that'd be very slow. We can avoid copying any data by creating a rather + * strange pointer structure. Here's how it works. We allocate a workspace + * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number + * of row groups per iMCU row). We create two sets of redundant pointers to + * the workspace. Labeling the physical row groups 0 to M+1, the synthesized + * pointer lists look like this: + * M+1 M-1 + * master pointer --> 0 master pointer --> 0 + * 1 1 + * ... ... + * M-3 M-3 + * M-2 M + * M-1 M+1 + * M M-2 + * M+1 M-1 + * 0 0 + * We read alternate iMCU rows using each master pointer; thus the last two + * row groups of the previous iMCU row remain un-overwritten in the workspace. + * The pointer lists are set up so that the required context rows appear to + * be adjacent to the proper places when we pass the pointer lists to the + * upsampler. + * + * The above pictures describe the normal state of the pointer lists. + * At top and bottom of the image, we diddle the pointer lists to duplicate + * the first or last sample row as necessary (this is cheaper than copying + * sample rows around). + * + * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that + * situation each iMCU row provides only one row group so the buffering logic + * must be different (eg, we must read two iMCU rows before we can emit the + * first row group). For now, we simply do not support providing context + * rows when min_DCT_scaled_size is 1. That combination seems unlikely to + * be worth providing --- if someone wants a 1/8th-size preview, they probably + * want it quick and dirty, so a context-free upsampler is sufficient. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_main_controller pub; /* public fields */ + + /* Pointer to allocated workspace (M or M+2 row groups). */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + + boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ + JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ + + /* Remaining fields are only used in the context case. */ + + /* These are the master pointers to the funny-order pointer lists. */ + JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ + + int whichptr; /* indicates which pointer set is now in use */ + int context_state; /* process_data state machine status */ + JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ + JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + +/* context_state values: */ +#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ +#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ +#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ + + +/* Forward declarations */ +METHODDEF void process_data_simple_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +METHODDEF void process_data_context_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF void process_data_crank_post + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#endif + + +LOCAL void +alloc_funny_pointers (j_decompress_ptr cinfo) +/* Allocate space for the funny pointer lists. + * This is done only once, not once per pass. + */ +{ + // bk001204 - no use main + my_main_ptr jmain = (my_main_ptr) cinfo->main; + int ci, rgroup; + int M = cinfo->min_DCT_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + /* Get top-level space for component array pointers. + * We alloc both arrays with one call to save a few cycles. + */ + jmain->xbuffer[0] = (JSAMPIMAGE) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * 2 * SIZEOF(JSAMPARRAY)); + jmain->xbuffer[1] = jmain->xbuffer[0] + cinfo->num_components; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + /* Get space for pointer lists --- M+4 row groups in each list. + * We alloc both pointer lists with one call to save a few cycles. + */ + xbuf = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)); + xbuf += rgroup; /* want one row group at negative offsets */ + jmain->xbuffer[0][ci] = xbuf; + xbuf += rgroup * (M + 4); + jmain->xbuffer[1][ci] = xbuf; + } +} + + +LOCAL void +make_funny_pointers (j_decompress_ptr cinfo) +/* Create the funny pointer lists discussed in the comments above. + * The actual workspace is already allocated (in main->buffer), + * and the space for the pointer lists is allocated too. + * This routine just fills in the curiously ordered lists. + * This will be repeated at the beginning of each pass. + */ +{ + // bk001204 - no use main + my_main_ptr jmain = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_DCT_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY buf, xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + xbuf0 = jmain->xbuffer[0][ci]; + xbuf1 = jmain->xbuffer[1][ci]; + /* First copy the workspace pointers as-is */ + buf = jmain->buffer[ci]; + for (i = 0; i < rgroup * (M + 2); i++) { + xbuf0[i] = xbuf1[i] = buf[i]; + } + /* In the second list, put the last four row groups in swapped order */ + for (i = 0; i < rgroup * 2; i++) { + xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i]; + xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i]; + } + /* The wraparound pointers at top and bottom will be filled later + * (see set_wraparound_pointers, below). Initially we want the "above" + * pointers to duplicate the first actual data line. This only needs + * to happen in xbuffer[0]. + */ + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[0]; + } + } +} + + +LOCAL void +set_wraparound_pointers (j_decompress_ptr cinfo) +/* Set up the "wraparound" pointers at top and bottom of the pointer lists. + * This changes the pointer list state from top-of-image to the normal state. + */ +{ + // bk001204 - no use main + my_main_ptr jmain = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_DCT_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + xbuf0 = jmain->xbuffer[0][ci]; + xbuf1 = jmain->xbuffer[1][ci]; + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; + xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; + xbuf0[rgroup*(M+2) + i] = xbuf0[i]; + xbuf1[rgroup*(M+2) + i] = xbuf1[i]; + } + } +} + + +LOCAL void +set_bottom_pointers (j_decompress_ptr cinfo) +/* Change the pointer lists to duplicate the last sample row at the bottom + * of the image. whichptr indicates which xbuffer holds the final iMCU row. + * Also sets rowgroups_avail to indicate number of nondummy row groups in row. + */ +{ + // bk001204 - no use main + my_main_ptr jmain = (my_main_ptr) cinfo->main; + int ci, i, rgroup, iMCUheight, rows_left; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Count sample rows in one iMCU row and in one row group */ + iMCUheight = compptr->v_samp_factor * compptr->DCT_scaled_size; + rgroup = iMCUheight / cinfo->min_DCT_scaled_size; + /* Count nondummy sample rows remaining for this component */ + rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); + if (rows_left == 0) rows_left = iMCUheight; + /* Count nondummy row groups. Should get same answer for each component, + * so we need only do it once. + */ + if (ci == 0) { + jmain->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1); + } + /* Duplicate the last real sample row rgroup*2 times; this pads out the + * last partial rowgroup and ensures at least one full rowgroup of context. + */ + xbuf = jmain->xbuffer[jmain->whichptr][ci]; + for (i = 0; i < rgroup * 2; i++) { + xbuf[rows_left + i] = xbuf[rows_left-1]; + } + } +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF void +start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + // bk001204 - no use main + my_main_ptr jmain = (my_main_ptr) cinfo->main; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->upsample->need_context_rows) { + jmain->pub.process_data = process_data_context_main; + make_funny_pointers(cinfo); /* Create the xbuffer[] lists */ + jmain->whichptr = 0; /* Read first iMCU row into xbuffer[0] */ + jmain->context_state = CTX_PREPARE_FOR_IMCU; + jmain->iMCU_row_ctr = 0; + } else { + /* Simple case with no context needed */ + jmain->pub.process_data = process_data_simple_main; + } + jmain->buffer_full = FALSE; /* Mark buffer empty */ + jmain->rowgroup_ctr = 0; + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_CRANK_DEST: + /* For last pass of 2-pass quantization, just crank the postprocessor */ + jmain->pub.process_data = process_data_crank_post; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This handles the simple case where no context is required. + */ + +METHODDEF void +process_data_simple_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + // bk001204 - no use main + my_main_ptr jmain = (my_main_ptr) cinfo->main; + JDIMENSION rowgroups_avail; + + /* Read input data if we haven't filled the main buffer yet */ + if (! jmain->buffer_full) { + if (! (*cinfo->coef->decompress_data) (cinfo, jmain->buffer)) + return; /* suspension forced, can do nothing more */ + jmain->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + } + + /* There are always min_DCT_scaled_size row groups in an iMCU row. */ + rowgroups_avail = (JDIMENSION) cinfo->min_DCT_scaled_size; + /* Note: at the bottom of the image, we may pass extra garbage row groups + * to the postprocessor. The postprocessor has to check for bottom + * of image anyway (at row resolution), so no point in us doing it too. + */ + + /* Feed the postprocessor */ + (*cinfo->post->post_process_data) (cinfo, jmain->buffer, + &jmain->rowgroup_ctr, rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + + /* Has postprocessor consumed all the data yet? If so, mark buffer empty */ + if (jmain->rowgroup_ctr >= rowgroups_avail) { + jmain->buffer_full = FALSE; + jmain->rowgroup_ctr = 0; + } +} + + +/* + * Process some data. + * This handles the case where context rows must be provided. + */ + +METHODDEF void +process_data_context_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + // bk001204 - no use main + my_main_ptr jmain = (my_main_ptr) cinfo->main; + + /* Read input data if we haven't filled the main buffer yet */ + if (! jmain->buffer_full) { + if (! (*cinfo->coef->decompress_data) (cinfo, + jmain->xbuffer[jmain->whichptr])) + return; /* suspension forced, can do nothing more */ + jmain->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + jmain->iMCU_row_ctr++; /* count rows received */ + } + + /* Postprocessor typically will not swallow all the input data it is handed + * in one call (due to filling the output buffer first). Must be prepared + * to exit and restart. This switch lets us keep track of how far we got. + * Note that each case falls through to the next on successful completion. + */ + switch (jmain->context_state) { + case CTX_POSTPONED_ROW: + /* Call postprocessor using previously set pointers for postponed row */ + (*cinfo->post->post_process_data) (cinfo, jmain->xbuffer[jmain->whichptr], + &jmain->rowgroup_ctr, jmain->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (jmain->rowgroup_ctr < jmain->rowgroups_avail) + return; /* Need to suspend */ + jmain->context_state = CTX_PREPARE_FOR_IMCU; + if (*out_row_ctr >= out_rows_avail) + return; /* Postprocessor exactly filled output buf */ + /*FALLTHROUGH*/ + case CTX_PREPARE_FOR_IMCU: + /* Prepare to process first M-1 row groups of this iMCU row */ + jmain->rowgroup_ctr = 0; + jmain->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1); + /* Check for bottom of image: if so, tweak pointers to "duplicate" + * the last sample row, and adjust rowgroups_avail to ignore padding rows. + */ + if (jmain->iMCU_row_ctr == cinfo->total_iMCU_rows) + set_bottom_pointers(cinfo); + jmain->context_state = CTX_PROCESS_IMCU; + /*FALLTHROUGH*/ + case CTX_PROCESS_IMCU: + /* Call postprocessor using previously set pointers */ + (*cinfo->post->post_process_data) (cinfo, jmain->xbuffer[jmain->whichptr], + &jmain->rowgroup_ctr, jmain->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (jmain->rowgroup_ctr < jmain->rowgroups_avail) + return; /* Need to suspend */ + /* After the first iMCU, change wraparound pointers to normal state */ + if (jmain->iMCU_row_ctr == 1) + set_wraparound_pointers(cinfo); + /* Prepare to load new iMCU row using other xbuffer list */ + jmain->whichptr ^= 1; /* 0=>1 or 1=>0 */ + jmain->buffer_full = FALSE; + /* Still need to process last row group of this iMCU row, */ + /* which is saved at index M+1 of the other xbuffer */ + jmain->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1); + jmain->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2); + jmain->context_state = CTX_POSTPONED_ROW; + } +} + + +/* + * Process some data. + * Final pass of two-pass quantization: just call the postprocessor. + * Source data will be the postprocessor controller's internal buffer. + */ + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF void +process_data_crank_post (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL, + (JDIMENSION *) NULL, (JDIMENSION) 0, + output_buf, out_row_ctr, out_rows_avail); +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL void +jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + // bk001204 - no use main + my_main_ptr jmain; + int ci, rgroup, ngroups; + jpeg_component_info *compptr; + + jmain = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_d_main_controller *) jmain; + jmain->pub.start_pass = start_pass_main; + + if (need_full_buffer) /* shouldn't happen */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Allocate the workspace. + * ngroups is the number of row groups we need. + */ + if (cinfo->upsample->need_context_rows) { + if (cinfo->min_DCT_scaled_size < 2) /* unsupported, see comments above */ + ERREXIT(cinfo, JERR_NOTIMPL); + alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ + ngroups = cinfo->min_DCT_scaled_size + 2; + } else { + ngroups = cinfo->min_DCT_scaled_size; + } + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + jmain->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_blocks * compptr->DCT_scaled_size, + (JDIMENSION) (rgroup * ngroups)); + } +} diff --git a/engine/jpeg-6/jdmarker.c b/engine/jpeg-6/jdmarker.c new file mode 100644 index 0000000..80e5f78 --- /dev/null +++ b/engine/jpeg-6/jdmarker.c @@ -0,0 +1,1052 @@ +/* + * jdmarker.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to decode JPEG datastream markers. + * Most of the complexity arises from our desire to support input + * suspension: if not all of the data for a marker is available, + * we must exit back to the application. On resumption, we reprocess + * the marker. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* + * Macros for fetching data from the data source module. + * + * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect + * the current restart point; we update them only when we have reached a + * suitable place to restart if a suspension occurs. + */ + +/* Declare and initialize local copies of input pointer/count */ +#define INPUT_VARS(cinfo) \ + struct jpeg_source_mgr * datasrc = (cinfo)->src; \ + const JOCTET * next_input_byte = datasrc->next_input_byte; \ + size_t bytes_in_buffer = datasrc->bytes_in_buffer + +/* Unload the local copies --- do this only at a restart boundary */ +#define INPUT_SYNC(cinfo) \ + ( datasrc->next_input_byte = next_input_byte, \ + datasrc->bytes_in_buffer = bytes_in_buffer ) + +/* Reload the local copies --- seldom used except in MAKE_BYTE_AVAIL */ +#define INPUT_RELOAD(cinfo) \ + ( next_input_byte = datasrc->next_input_byte, \ + bytes_in_buffer = datasrc->bytes_in_buffer ) + +/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. + * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, + * but we must reload the local copies after a successful fill. + */ +#define MAKE_BYTE_AVAIL(cinfo,action) \ + if (bytes_in_buffer == 0) { \ + if (! (*datasrc->fill_input_buffer) (cinfo)) \ + { action; } \ + INPUT_RELOAD(cinfo); \ + } \ + bytes_in_buffer-- + +/* Read a byte into variable V. + * If must suspend, take the specified action (typically "return FALSE"). + */ +#define INPUT_BYTE(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + V = GETJOCTET(*next_input_byte++); ) + +/* As above, but read two bytes interpreted as an unsigned 16-bit integer. + * V should be declared unsigned int or perhaps INT32. + */ +#define INPUT_2BYTES(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ + MAKE_BYTE_AVAIL(cinfo,action); \ + V += GETJOCTET(*next_input_byte++); ) + + +/* + * Routines to process JPEG markers. + * + * Entry condition: JPEG marker itself has been read and its code saved + * in cinfo->unread_marker; input restart point is just after the marker. + * + * Exit: if return TRUE, have read and processed any parameters, and have + * updated the restart point to point after the parameters. + * If return FALSE, was forced to suspend before reaching end of + * marker parameters; restart point has not been moved. Same routine + * will be called again after application supplies more input data. + * + * This approach to suspension assumes that all of a marker's parameters can + * fit into a single input bufferload. This should hold for "normal" + * markers. Some COM/APPn markers might have large parameter segments, + * but we use skip_input_data to get past those, and thereby put the problem + * on the source manager's shoulders. + * + * Note that we don't bother to avoid duplicate trace messages if a + * suspension occurs within marker parameters. Other side effects + * require more care. + */ + + +LOCAL boolean +get_soi (j_decompress_ptr cinfo) +/* Process an SOI marker */ +{ + int i; + + TRACEMS(cinfo, 1, JTRC_SOI); + + if (cinfo->marker->saw_SOI) + ERREXIT(cinfo, JERR_SOI_DUPLICATE); + + /* Reset all parameters that are defined to be reset by SOI */ + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + cinfo->restart_interval = 0; + + /* Set initial assumptions for colorspace etc */ + + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */ + + cinfo->saw_JFIF_marker = FALSE; + cinfo->density_unit = 0; /* set default JFIF APP0 values */ + cinfo->X_density = 1; + cinfo->Y_density = 1; + cinfo->saw_Adobe_marker = FALSE; + cinfo->Adobe_transform = 0; + + cinfo->marker->saw_SOI = TRUE; + + return TRUE; +} + + +LOCAL boolean +get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_arith) +/* Process a SOFn marker */ +{ + INT32 length; + int c, ci; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + cinfo->progressive_mode = is_prog; + cinfo->arith_code = is_arith; + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE); + INPUT_BYTE(cinfo, cinfo->num_components, return FALSE); + + length -= 8; + + TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker, + (int) cinfo->image_width, (int) cinfo->image_height, + cinfo->num_components); + + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_DUPLICATE); + + /* We don't support files in which the image height is initially specified */ + /* as 0 and is later redefined by DNL. As long as we have to check that, */ + /* might as well have a general sanity check. */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + if (length != (cinfo->num_components * 3)) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + if (cinfo->comp_info == NULL) /* do only once, even if suspend */ + cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * SIZEOF(jpeg_component_info)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->component_index = ci; + INPUT_BYTE(cinfo, compptr->component_id, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + compptr->h_samp_factor = (c >> 4) & 15; + compptr->v_samp_factor = (c ) & 15; + INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE); + + TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT, + compptr->component_id, compptr->h_samp_factor, + compptr->v_samp_factor, compptr->quant_tbl_no); + } + + cinfo->marker->saw_SOF = TRUE; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_sos (j_decompress_ptr cinfo) +/* Process a SOS marker */ +{ + INT32 length; + int i, ci, n, c, cc; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + if (! cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOS_NO_SOF); + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */ + + if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + TRACEMS1(cinfo, 1, JTRC_SOS, n); + + cinfo->comps_in_scan = n; + + /* Collect the component-spec parameters */ + + for (i = 0; i < n; i++) { + INPUT_BYTE(cinfo, cc, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (cc == compptr->component_id) + goto id_found; + } + + ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc); + + id_found: + + cinfo->cur_comp_info[i] = compptr; + compptr->dc_tbl_no = (c >> 4) & 15; + compptr->ac_tbl_no = (c ) & 15; + + TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc, + compptr->dc_tbl_no, compptr->ac_tbl_no); + } + + /* Collect the additional scan parameters Ss, Se, Ah/Al. */ + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ss = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Se = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ah = (c >> 4) & 15; + cinfo->Al = (c ) & 15; + + TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se, + cinfo->Ah, cinfo->Al); + + /* Prepare to scan data & restart markers */ + cinfo->marker->next_restart_num = 0; + + /* Count another SOS marker */ + cinfo->input_scan_number++; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +METHODDEF boolean +get_app0 (j_decompress_ptr cinfo) +/* Process an APP0 marker */ +{ +#define JFIF_LEN 14 + INT32 length; + UINT8 b[JFIF_LEN]; + int buffp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* See if a JFIF APP0 marker is present */ + + if (length >= JFIF_LEN) { + for (buffp = 0; buffp < JFIF_LEN; buffp++) + INPUT_BYTE(cinfo, b[buffp], return FALSE); + length -= JFIF_LEN; + + if (b[0]==0x4A && b[1]==0x46 && b[2]==0x49 && b[3]==0x46 && b[4]==0) { + /* Found JFIF APP0 marker: check version */ + /* Major version must be 1, anything else signals an incompatible change. + * We used to treat this as an error, but now it's a nonfatal warning, + * because some bozo at Hijaak couldn't read the spec. + * Minor version should be 0..2, but process anyway if newer. + */ + if (b[5] != 1) + WARNMS2(cinfo, JWRN_JFIF_MAJOR, b[5], b[6]); + else if (b[6] > 2) + TRACEMS2(cinfo, 1, JTRC_JFIF_MINOR, b[5], b[6]); + /* Save info */ + cinfo->saw_JFIF_marker = TRUE; + cinfo->density_unit = b[7]; + cinfo->X_density = (b[8] << 8) + b[9]; + cinfo->Y_density = (b[10] << 8) + b[11]; + TRACEMS3(cinfo, 1, JTRC_JFIF, + cinfo->X_density, cinfo->Y_density, cinfo->density_unit); + if (b[12] | b[13]) + TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, b[12], b[13]); + if (length != ((INT32) b[12] * (INT32) b[13] * (INT32) 3)) + TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) length); + } else { + /* Start of APP0 does not match "JFIF" */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) length + JFIF_LEN); + } + } else { + /* Too short to be JFIF marker */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) length); + } + + INPUT_SYNC(cinfo); + if (length > 0) /* skip any remaining data -- could be lots */ + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +METHODDEF boolean +get_app14 (j_decompress_ptr cinfo) +/* Process an APP14 marker */ +{ +#define ADOBE_LEN 12 + INT32 length; + UINT8 b[ADOBE_LEN]; + int buffp; + unsigned int version, flags0, flags1, transform; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* See if an Adobe APP14 marker is present */ + + if (length >= ADOBE_LEN) { + for (buffp = 0; buffp < ADOBE_LEN; buffp++) + INPUT_BYTE(cinfo, b[buffp], return FALSE); + length -= ADOBE_LEN; + + if (b[0]==0x41 && b[1]==0x64 && b[2]==0x6F && b[3]==0x62 && b[4]==0x65) { + /* Found Adobe APP14 marker */ + version = (b[5] << 8) + b[6]; + flags0 = (b[7] << 8) + b[8]; + flags1 = (b[9] << 8) + b[10]; + transform = b[11]; + TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform); + cinfo->saw_Adobe_marker = TRUE; + cinfo->Adobe_transform = (UINT8) transform; + } else { + /* Start of APP14 does not match "Adobe" */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) length + ADOBE_LEN); + } + } else { + /* Too short to be Adobe marker */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) length); + } + + INPUT_SYNC(cinfo); + if (length > 0) /* skip any remaining data -- could be lots */ + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +LOCAL boolean +get_dac (j_decompress_ptr cinfo) +/* Process a DAC marker */ +{ + INT32 length; + int index, val; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + INPUT_BYTE(cinfo, val, return FALSE); + + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_DAC, index, val); + + if (index < 0 || index >= (2*NUM_ARITH_TBLS)) + ERREXIT1(cinfo, JERR_DAC_INDEX, index); + + if (index >= NUM_ARITH_TBLS) { /* define AC table */ + cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val; + } else { /* define DC table */ + cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F); + cinfo->arith_dc_U[index] = (UINT8) (val >> 4); + if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) + ERREXIT1(cinfo, JERR_DAC_VALUE, val); + } + } + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_dht (j_decompress_ptr cinfo) +/* Process a DHT marker */ +{ + INT32 length; + UINT8 bits[17]; + UINT8 huffval[256]; + int i, index, count; + JHUFF_TBL **htblptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DHT, index); + + bits[0] = 0; + count = 0; + for (i = 1; i <= 16; i++) { + INPUT_BYTE(cinfo, bits[i], return FALSE); + count += bits[i]; + } + + length -= 1 + 16; + + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[1], bits[2], bits[3], bits[4], + bits[5], bits[6], bits[7], bits[8]); + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[9], bits[10], bits[11], bits[12], + bits[13], bits[14], bits[15], bits[16]); + + if (count > 256 || ((INT32) count) > length) + ERREXIT(cinfo, JERR_DHT_COUNTS); + + for (i = 0; i < count; i++) + INPUT_BYTE(cinfo, huffval[i], return FALSE); + + length -= count; + + if (index & 0x10) { /* AC table definition */ + index -= 0x10; + htblptr = &cinfo->ac_huff_tbl_ptrs[index]; + } else { /* DC table definition */ + htblptr = &cinfo->dc_huff_tbl_ptrs[index]; + } + + if (index < 0 || index >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_DHT_INDEX, index); + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval)); + } + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_dqt (j_decompress_ptr cinfo) +/* Process a DQT marker */ +{ + INT32 length; + int n, i, prec; + unsigned int tmp; + JQUANT_TBL *quant_ptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, n, return FALSE); + prec = n >> 4; + n &= 0x0F; + + TRACEMS2(cinfo, 1, JTRC_DQT, n, prec); + + if (n >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, n); + + if (cinfo->quant_tbl_ptrs[n] == NULL) + cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo); + quant_ptr = cinfo->quant_tbl_ptrs[n]; + + for (i = 0; i < DCTSIZE2; i++) { + if (prec) + INPUT_2BYTES(cinfo, tmp, return FALSE); + else + INPUT_BYTE(cinfo, tmp, return FALSE); + quant_ptr->quantval[i] = (UINT16) tmp; + } + + for (i = 0; i < DCTSIZE2; i += 8) { + TRACEMS8(cinfo, 2, JTRC_QUANTVALS, + quant_ptr->quantval[i ], quant_ptr->quantval[i+1], + quant_ptr->quantval[i+2], quant_ptr->quantval[i+3], + quant_ptr->quantval[i+4], quant_ptr->quantval[i+5], + quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]); + } + + length -= DCTSIZE2+1; + if (prec) length -= DCTSIZE2; + } + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_dri (j_decompress_ptr cinfo) +/* Process a DRI marker */ +{ + INT32 length; + unsigned int tmp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + if (length != 4) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_2BYTES(cinfo, tmp, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DRI, tmp); + + cinfo->restart_interval = tmp; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +METHODDEF boolean +skip_variable (j_decompress_ptr cinfo) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + INT32 length; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length); + + INPUT_SYNC(cinfo); /* do before skip_input_data */ + (*cinfo->src->skip_input_data) (cinfo, (long) length - 2L); + + return TRUE; +} + + +/* + * Find the next JPEG marker, save it in cinfo->unread_marker. + * Returns FALSE if had to suspend before reaching a marker; + * in that case cinfo->unread_marker is unchanged. + * + * Note that the result might not be a valid marker code, + * but it will never be 0 or FF. + */ + +LOCAL boolean +next_marker (j_decompress_ptr cinfo) +{ + int c; + INPUT_VARS(cinfo); + + for (;;) { + INPUT_BYTE(cinfo, c, return FALSE); + /* Skip any non-FF bytes. + * This may look a bit inefficient, but it will not occur in a valid file. + * We sync after each discarded byte so that a suspending data source + * can discard the byte from its buffer. + */ + while (c != 0xFF) { + cinfo->marker->discarded_bytes++; + INPUT_SYNC(cinfo); + INPUT_BYTE(cinfo, c, return FALSE); + } + /* This loop swallows any duplicate FF bytes. Extra FFs are legal as + * pad bytes, so don't count them in discarded_bytes. We assume there + * will not be so many consecutive FF bytes as to overflow a suspending + * data source's input buffer. + */ + do { + INPUT_BYTE(cinfo, c, return FALSE); + } while (c == 0xFF); + if (c != 0) + break; /* found a valid marker, exit loop */ + /* Reach here if we found a stuffed-zero data sequence (FF/00). + * Discard it and loop back to try again. + */ + cinfo->marker->discarded_bytes += 2; + INPUT_SYNC(cinfo); + } + + if (cinfo->marker->discarded_bytes != 0) { + WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c); + cinfo->marker->discarded_bytes = 0; + } + + cinfo->unread_marker = c; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +first_marker (j_decompress_ptr cinfo) +/* Like next_marker, but used to obtain the initial SOI marker. */ +/* For this marker, we do not allow preceding garbage or fill; otherwise, + * we might well scan an entire input file before realizing it ain't JPEG. + * If an application wants to process non-JFIF files, it must seek to the + * SOI before calling the JPEG library. + */ +{ + int c, c2; + INPUT_VARS(cinfo); + + INPUT_BYTE(cinfo, c, return FALSE); + INPUT_BYTE(cinfo, c2, return FALSE); + if (c != 0xFF || c2 != (int) M_SOI) + ERREXIT2(cinfo, JERR_NO_SOI, c, c2); + + cinfo->unread_marker = c2; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Read markers until SOS or EOI. + * + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + +METHODDEF int +read_markers (j_decompress_ptr cinfo) +{ + /* Outer loop repeats once for each marker. */ + for (;;) { + /* Collect the marker proper, unless we already did. */ + /* NB: first_marker() enforces the requirement that SOI appear first. */ + if (cinfo->unread_marker == 0) { + if (! cinfo->marker->saw_SOI) { + if (! first_marker(cinfo)) + return JPEG_SUSPENDED; + } else { + if (! next_marker(cinfo)) + return JPEG_SUSPENDED; + } + } + /* At this point cinfo->unread_marker contains the marker code and the + * input point is just past the marker proper, but before any parameters. + * A suspension will cause us to return with this state still true. + */ + switch (cinfo->unread_marker) { + case M_SOI: + if (! get_soi(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + if (! get_sof(cinfo, FALSE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF2: /* Progressive, Huffman */ + if (! get_sof(cinfo, TRUE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF9: /* Extended sequential, arithmetic */ + if (! get_sof(cinfo, FALSE, TRUE)) + return JPEG_SUSPENDED; + break; + + case M_SOF10: /* Progressive, arithmetic */ + if (! get_sof(cinfo, TRUE, TRUE)) + return JPEG_SUSPENDED; + break; + + /* Currently unsupported SOFn types */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_JPG: /* Reserved for JPEG extensions */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); + break; + + case M_SOS: + if (! get_sos(cinfo)) + return JPEG_SUSPENDED; + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_SOS; + + case M_EOI: + TRACEMS(cinfo, 1, JTRC_EOI); + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_EOI; + + case M_DAC: + if (! get_dac(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DHT: + if (! get_dht(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DQT: + if (! get_dqt(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DRI: + if (! get_dri(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_APP0: + case M_APP1: + case M_APP2: + case M_APP3: + case M_APP4: + case M_APP5: + case M_APP6: + case M_APP7: + case M_APP8: + case M_APP9: + case M_APP10: + case M_APP11: + case M_APP12: + case M_APP13: + case M_APP14: + case M_APP15: + if (! (*cinfo->marker->process_APPn[cinfo->unread_marker - (int) M_APP0]) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_COM: + if (! (*cinfo->marker->process_COM) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_RST0: /* these are all parameterless */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); + break; + + case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ + if (! skip_variable(cinfo)) + return JPEG_SUSPENDED; + break; + + default: /* must be DHP, EXP, JPGn, or RESn */ + /* For now, we treat the reserved markers as fatal errors since they are + * likely to be used to signal incompatible JPEG Part 3 extensions. + * Once the JPEG 3 version-number marker is well defined, this code + * ought to change! + */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + /* Successfully processed marker, so reset state variable */ + cinfo->unread_marker = 0; + } /* end loop */ +} + + +/* + * Read a restart marker, which is expected to appear next in the datastream; + * if the marker is not there, take appropriate recovery action. + * Returns FALSE if suspension is required. + * + * This is called by the entropy decoder after it has read an appropriate + * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder + * has already read a marker from the data source. Under normal conditions + * cinfo->unread_marker will be reset to 0 before returning; if not reset, + * it holds a marker which the decoder will be unable to read past. + */ + +METHODDEF boolean +read_restart_marker (j_decompress_ptr cinfo) +{ + /* Obtain a marker unless we already did. */ + /* Note that next_marker will complain if it skips any data. */ + if (cinfo->unread_marker == 0) { + if (! next_marker(cinfo)) + return FALSE; + } + + if (cinfo->unread_marker == + ((int) M_RST0 + cinfo->marker->next_restart_num)) { + /* Normal case --- swallow the marker and let entropy decoder continue */ + TRACEMS1(cinfo, 2, JTRC_RST, cinfo->marker->next_restart_num); + cinfo->unread_marker = 0; + } else { + /* Uh-oh, the restart markers have been messed up. */ + /* Let the data source manager determine how to resync. */ + if (! (*cinfo->src->resync_to_restart) (cinfo, + cinfo->marker->next_restart_num)) + return FALSE; + } + + /* Update next-restart state */ + cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7; + + return TRUE; +} + + +/* + * This is the default resync_to_restart method for data source managers + * to use if they don't have any better approach. Some data source managers + * may be able to back up, or may have additional knowledge about the data + * which permits a more intelligent recovery strategy; such managers would + * presumably supply their own resync method. + * + * read_restart_marker calls resync_to_restart if it finds a marker other than + * the restart marker it was expecting. (This code is *not* used unless + * a nonzero restart interval has been declared.) cinfo->unread_marker is + * the marker code actually found (might be anything, except 0 or FF). + * The desired restart marker number (0..7) is passed as a parameter. + * This routine is supposed to apply whatever error recovery strategy seems + * appropriate in order to position the input stream to the next data segment. + * Note that cinfo->unread_marker is treated as a marker appearing before + * the current data-source input point; usually it should be reset to zero + * before returning. + * Returns FALSE if suspension is required. + * + * This implementation is substantially constrained by wanting to treat the + * input as a data stream; this means we can't back up. Therefore, we have + * only the following actions to work with: + * 1. Simply discard the marker and let the entropy decoder resume at next + * byte of file. + * 2. Read forward until we find another marker, discarding intervening + * data. (In theory we could look ahead within the current bufferload, + * without having to discard data if we don't find the desired marker. + * This idea is not implemented here, in part because it makes behavior + * dependent on buffer size and chance buffer-boundary positions.) + * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). + * This will cause the entropy decoder to process an empty data segment, + * inserting dummy zeroes, and then we will reprocess the marker. + * + * #2 is appropriate if we think the desired marker lies ahead, while #3 is + * appropriate if the found marker is a future restart marker (indicating + * that we have missed the desired restart marker, probably because it got + * corrupted). + * We apply #2 or #3 if the found marker is a restart marker no more than + * two counts behind or ahead of the expected one. We also apply #2 if the + * found marker is not a legal JPEG marker code (it's certainly bogus data). + * If the found marker is a restart marker more than 2 counts away, we do #1 + * (too much risk that the marker is erroneous; with luck we will be able to + * resync at some future point). + * For any valid non-restart JPEG marker, we apply #3. This keeps us from + * overrunning the end of a scan. An implementation limited to single-scan + * files might find it better to apply #2 for markers other than EOI, since + * any other marker would have to be bogus data in that case. + */ + +GLOBAL boolean +jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) +{ + int marker = cinfo->unread_marker; + int action = 1; + + /* Always put up a warning. */ + WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired); + + /* Outer loop handles repeated decision after scanning forward. */ + for (;;) { + if (marker < (int) M_SOF0) + action = 2; /* invalid marker */ + else if (marker < (int) M_RST0 || marker > (int) M_RST7) + action = 3; /* valid non-restart marker */ + else { + if (marker == ((int) M_RST0 + ((desired+1) & 7)) || + marker == ((int) M_RST0 + ((desired+2) & 7))) + action = 3; /* one of the next two expected restarts */ + else if (marker == ((int) M_RST0 + ((desired-1) & 7)) || + marker == ((int) M_RST0 + ((desired-2) & 7))) + action = 2; /* a prior restart, so advance */ + else + action = 1; /* desired restart or too far away */ + } + TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action); + switch (action) { + case 1: + /* Discard marker and let entropy decoder resume processing. */ + cinfo->unread_marker = 0; + return TRUE; + case 2: + /* Scan to the next marker, and repeat the decision loop. */ + if (! next_marker(cinfo)) + return FALSE; + marker = cinfo->unread_marker; + break; + case 3: + /* Return without advancing past this marker. */ + /* Entropy decoder will be forced to process an empty segment. */ + return TRUE; + } + } /* end loop */ +} + + +/* + * Reset marker processing state to begin a fresh datastream. + */ + +METHODDEF void +reset_marker_reader (j_decompress_ptr cinfo) +{ + cinfo->comp_info = NULL; /* until allocated by get_sof */ + cinfo->input_scan_number = 0; /* no SOS seen yet */ + cinfo->unread_marker = 0; /* no pending marker */ + cinfo->marker->saw_SOI = FALSE; /* set internal state too */ + cinfo->marker->saw_SOF = FALSE; + cinfo->marker->discarded_bytes = 0; +} + + +/* + * Initialize the marker reader module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL void +jinit_marker_reader (j_decompress_ptr cinfo) +{ + int i; + + /* Create subobject in permanent pool */ + cinfo->marker = (struct jpeg_marker_reader *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(struct jpeg_marker_reader)); + /* Initialize method pointers */ + cinfo->marker->reset_marker_reader = reset_marker_reader; + cinfo->marker->read_markers = read_markers; + cinfo->marker->read_restart_marker = read_restart_marker; + cinfo->marker->process_COM = skip_variable; + for (i = 0; i < 16; i++) + cinfo->marker->process_APPn[i] = skip_variable; + cinfo->marker->process_APPn[0] = get_app0; + cinfo->marker->process_APPn[14] = get_app14; + /* Reset marker processing state */ + reset_marker_reader(cinfo); +} diff --git a/engine/jpeg-6/jdmaster.c b/engine/jpeg-6/jdmaster.c new file mode 100644 index 0000000..18e0880 --- /dev/null +++ b/engine/jpeg-6/jdmaster.c @@ -0,0 +1,557 @@ +/* + * jdmaster.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG decompressor. + * These routines are concerned with selecting the modules to be executed + * and with determining the number of passes and the work to be done in each + * pass. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_decomp_master pub; /* public fields */ + + int pass_number; /* # of passes completed */ + + boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */ + + /* Saved references to initialized quantizer modules, + * in case we need to switch modes. + */ + struct jpeg_color_quantizer * quantizer_1pass; + struct jpeg_color_quantizer * quantizer_2pass; +} my_decomp_master; + +typedef my_decomp_master * my_master_ptr; + + +/* + * Determine whether merged upsample/color conversion should be used. + * CRUCIAL: this must match the actual capabilities of jdmerge.c! + */ + +LOCAL boolean +use_merged_upsample (j_decompress_ptr cinfo) +{ +#ifdef UPSAMPLE_MERGING_SUPPORTED + /* Merging is the equivalent of plain box-filter upsampling */ + if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling) + return FALSE; + /* jdmerge.c only supports YCC=>RGB color conversion */ + if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 || + cinfo->out_color_space != JCS_RGB || + cinfo->out_color_components != RGB_PIXELSIZE) + return FALSE; + /* and it only handles 2h1v or 2h2v sampling ratios */ + if (cinfo->comp_info[0].h_samp_factor != 2 || + cinfo->comp_info[1].h_samp_factor != 1 || + cinfo->comp_info[2].h_samp_factor != 1 || + cinfo->comp_info[0].v_samp_factor > 2 || + cinfo->comp_info[1].v_samp_factor != 1 || + cinfo->comp_info[2].v_samp_factor != 1) + return FALSE; + /* furthermore, it doesn't work if we've scaled the IDCTs differently */ + if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size || + cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size || + cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size) + return FALSE; + /* ??? also need to test for upsample-time rescaling, when & if supported */ + return TRUE; /* by golly, it'll work... */ +#else + return FALSE; +#endif +} + + +/* + * Compute output image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + * Also note that it may be called before the master module is initialized! + */ + +GLOBAL void +jpeg_calc_output_dimensions (j_decompress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ +#if 0 // JDC: commented out to remove warning + int ci; + jpeg_component_info *compptr; +#endif + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_READY) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + +#ifdef IDCT_SCALING_SUPPORTED + + /* Compute actual output image dimensions and DCT scaling choices. */ + if (cinfo->scale_num * 8 <= cinfo->scale_denom) { + /* Provide 1/8 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 8L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 8L); + cinfo->min_DCT_scaled_size = 1; + } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) { + /* Provide 1/4 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 4L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 4L); + cinfo->min_DCT_scaled_size = 2; + } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) { + /* Provide 1/2 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 2L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 2L); + cinfo->min_DCT_scaled_size = 4; + } else { + /* Provide 1/1 scaling */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + cinfo->min_DCT_scaled_size = DCTSIZE; + } + /* In selecting the actual DCT scaling for each component, we try to + * scale up the chroma components via IDCT scaling rather than upsampling. + * This saves time if the upsampler gets to use 1:1 scaling. + * Note this code assumes that the supported DCT scalings are powers of 2. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + int ssize = cinfo->min_DCT_scaled_size; + while (ssize < DCTSIZE && + (compptr->h_samp_factor * ssize * 2 <= + cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) && + (compptr->v_samp_factor * ssize * 2 <= + cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) { + ssize = ssize * 2; + } + compptr->DCT_scaled_size = ssize; + } + + /* Recompute downsampled dimensions of components; + * application needs to know these if using raw downsampled data. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Size in samples, after IDCT scaling */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * + (long) (compptr->h_samp_factor * compptr->DCT_scaled_size), + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * + (long) (compptr->v_samp_factor * compptr->DCT_scaled_size), + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + } + +#else /* !IDCT_SCALING_SUPPORTED */ + + /* Hardwire it to "no scaling" */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE, + * and has computed unscaled downsampled_width and downsampled_height. + */ + +#endif /* IDCT_SCALING_SUPPORTED */ + + /* Report number of components in selected colorspace. */ + /* Probably this should be in the color conversion module... */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + break; + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + cinfo->out_color_components = RGB_PIXELSIZE; + break; +#endif /* else share code with YCbCr */ + case JCS_YCbCr: + cinfo->out_color_components = 3; + break; + case JCS_CMYK: + case JCS_YCCK: + cinfo->out_color_components = 4; + break; + default: /* else must be same colorspace as in file */ + cinfo->out_color_components = cinfo->num_components; + break; + } + cinfo->output_components = (cinfo->quantize_colors ? 1 : + cinfo->out_color_components); + + /* See if upsampler will want to emit more than one row at a time */ + if (use_merged_upsample(cinfo)) + cinfo->rec_outbuf_height = cinfo->max_v_samp_factor; + else + cinfo->rec_outbuf_height = 1; +} + + +/* + * Several decompression processes need to range-limit values to the range + * 0..MAXJSAMPLE; the input value may fall somewhat outside this range + * due to noise introduced by quantization, roundoff error, etc. These + * processes are inner loops and need to be as fast as possible. On most + * machines, particularly CPUs with pipelines or instruction prefetch, + * a (subscript-check-less) C table lookup + * x = sample_range_limit[x]; + * is faster than explicit tests + * if (x < 0) x = 0; + * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; + * These processes all use a common table prepared by the routine below. + * + * For most steps we can mathematically guarantee that the initial value + * of x is within MAXJSAMPLE+1 of the legal range, so a table running from + * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial + * limiting step (just after the IDCT), a wildly out-of-range value is + * possible if the input data is corrupt. To avoid any chance of indexing + * off the end of memory and getting a bad-pointer trap, we perform the + * post-IDCT limiting thus: + * x = range_limit[x & MASK]; + * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit + * samples. Under normal circumstances this is more than enough range and + * a correct output will be generated; with bogus input data the mask will + * cause wraparound, and we will safely generate a bogus-but-in-range output. + * For the post-IDCT step, we want to convert the data from signed to unsigned + * representation by adding CENTERJSAMPLE at the same time that we limit it. + * So the post-IDCT limiting table ends up looking like this: + * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE, + * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0,1,...,CENTERJSAMPLE-1 + * Negative inputs select values from the upper half of the table after + * masking. + * + * We can save some space by overlapping the start of the post-IDCT table + * with the simpler range limiting table. The post-IDCT table begins at + * sample_range_limit + CENTERJSAMPLE. + * + * Note that the table is allocated in near data space on PCs; it's small + * enough and used often enough to justify this. + */ + +LOCAL void +prepare_range_limit_table (j_decompress_ptr cinfo) +/* Allocate and fill in the sample_range_limit table */ +{ + JSAMPLE * table; + int i; + + table = (JSAMPLE *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ + cinfo->sample_range_limit = table; + /* First segment of "simple" table: limit[x] = 0 for x < 0 */ + MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE)); + /* Main part of "simple" table: limit[x] = x */ + for (i = 0; i <= MAXJSAMPLE; i++) + table[i] = (JSAMPLE) i; + table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ + /* End of simple table, rest of first half of post-IDCT table */ + for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) + table[i] = MAXJSAMPLE; + /* Second half of post-IDCT table */ + MEMZERO(table + (2 * (MAXJSAMPLE+1)), + (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), + cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE)); +} + + +/* + * Master selection of decompression modules. + * This is done once at jpeg_start_decompress time. We determine + * which modules will be used and give them appropriate initialization calls. + * We also initialize the decompressor input side to begin consuming data. + * + * Since jpeg_read_header has finished, we know what is in the SOF + * and (first) SOS markers. We also have all the application parameter + * settings. + */ + +LOCAL void +master_selection (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + boolean use_c_buffer; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* Initialize dimensions and other stuff */ + jpeg_calc_output_dimensions(cinfo); + prepare_range_limit_table(cinfo); + + /* Width of an output scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* Initialize my private state */ + master->pass_number = 0; + master->using_merged_upsample = use_merged_upsample(cinfo); + + /* Color quantizer selection */ + master->quantizer_1pass = NULL; + master->quantizer_2pass = NULL; + /* No mode changes if not using buffered-image mode. */ + if (! cinfo->quantize_colors || ! cinfo->buffered_image) { + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + } + if (cinfo->quantize_colors) { + if (cinfo->raw_data_out) + ERREXIT(cinfo, JERR_NOTIMPL); + /* 2-pass quantizer only works in 3-component color space. */ + if (cinfo->out_color_components != 3) { + cinfo->enable_1pass_quant = TRUE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + cinfo->colormap = NULL; + } else if (cinfo->colormap != NULL) { + cinfo->enable_external_quant = TRUE; + } else if (cinfo->two_pass_quantize) { + cinfo->enable_2pass_quant = TRUE; + } else { + cinfo->enable_1pass_quant = TRUE; + } + + if (cinfo->enable_1pass_quant) { +#ifdef QUANT_1PASS_SUPPORTED + jinit_1pass_quantizer(cinfo); + master->quantizer_1pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + /* We use the 2-pass code to map to external colormaps. */ + if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) { +#ifdef QUANT_2PASS_SUPPORTED + jinit_2pass_quantizer(cinfo); + master->quantizer_2pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + /* If both quantizers are initialized, the 2-pass one is left active; + * this is necessary for starting with quantization to an external map. + */ + } + + /* Post-processing: in particular, color conversion first */ + if (! cinfo->raw_data_out) { + if (master->using_merged_upsample) { +#ifdef UPSAMPLE_MERGING_SUPPORTED + jinit_merged_upsampler(cinfo); /* does color conversion too */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + jinit_color_deconverter(cinfo); + jinit_upsampler(cinfo); + } + jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); + } + /* Inverse DCT */ + jinit_inverse_dct(cinfo); + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef D_PROGRESSIVE_SUPPORTED + jinit_phuff_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_decoder(cinfo); + } + + /* Initialize principal buffer controllers. */ + use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; + jinit_d_coef_controller(cinfo, use_c_buffer); + + if (! cinfo->raw_data_out) + jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* If jpeg_start_decompress will read the whole file, initialize + * progress monitoring appropriately. The input step is counted + * as one pass. + */ + if (cinfo->progress != NULL && ! cinfo->buffered_image && + cinfo->inputctl->has_multiple_scans) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2); + /* Count the input pass as done */ + master->pass_number++; + } +#endif /* D_MULTISCAN_FILES_SUPPORTED */ +} + + +/* + * Per-pass setup. + * This is called at the beginning of each output pass. We determine which + * modules will be active during this pass and give them appropriate + * start_pass calls. We also set is_dummy_pass to indicate whether this + * is a "real" output pass or a dummy pass for color quantization. + * (In the latter case, jdapi.c will crank the pass to completion.) + */ + +METHODDEF void +prepare_for_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (master->pub.is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Final pass of 2-pass quantization */ + master->pub.is_dummy_pass = FALSE; + (*cinfo->cquantize->start_pass) (cinfo, FALSE); + (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST); + (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + if (cinfo->quantize_colors && cinfo->colormap == NULL) { + /* Select new quantization method */ + if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) { + cinfo->cquantize = master->quantizer_2pass; + master->pub.is_dummy_pass = TRUE; + } else if (cinfo->enable_1pass_quant) { + cinfo->cquantize = master->quantizer_1pass; + } else { + ERREXIT(cinfo, JERR_MODE_CHANGE); + } + } + (*cinfo->idct->start_pass) (cinfo); + (*cinfo->coef->start_output_pass) (cinfo); + if (! cinfo->raw_data_out) { + if (! master->using_merged_upsample) + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->upsample->start_pass) (cinfo); + if (cinfo->quantize_colors) + (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass); + (*cinfo->post->start_pass) (cinfo, + (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + } + } + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->pass_number + + (master->pub.is_dummy_pass ? 2 : 1); + /* In buffered-image mode, we assume one more output pass if EOI not + * yet reached, but no more passes if EOI has been reached. + */ + if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) { + cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1); + } + } +} + + +/* + * Finish up at end of an output pass. + */ + +METHODDEF void +finish_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (cinfo->quantize_colors) + (*cinfo->cquantize->finish_pass) (cinfo); + master->pass_number++; +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Switch to a new external colormap between output passes. + */ + +GLOBAL void +jpeg_new_colormap (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_BUFIMAGE) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (cinfo->quantize_colors && cinfo->enable_external_quant && + cinfo->colormap != NULL) { + /* Select 2-pass quantizer for external colormap use */ + cinfo->cquantize = master->quantizer_2pass; + /* Notify quantizer of colormap change */ + (*cinfo->cquantize->new_color_map) (cinfo); + master->pub.is_dummy_pass = FALSE; /* just in case */ + } else + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +/* + * Initialize master decompression control and select active modules. + * This is performed at the start of jpeg_start_decompress. + */ + +GLOBAL void +jinit_master_decompress (j_decompress_ptr cinfo) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_decomp_master)); + cinfo->master = (struct jpeg_decomp_master *) master; + master->pub.prepare_for_output_pass = prepare_for_output_pass; + master->pub.finish_output_pass = finish_output_pass; + + master->pub.is_dummy_pass = FALSE; + + master_selection(cinfo); +} diff --git a/engine/jpeg-6/jdmerge.c b/engine/jpeg-6/jdmerge.c new file mode 100644 index 0000000..95585fb --- /dev/null +++ b/engine/jpeg-6/jdmerge.c @@ -0,0 +1,400 @@ +/* + * jdmerge.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains code for merged upsampling/color conversion. + * + * This file combines functions from jdsample.c and jdcolor.c; + * read those files first to understand what's going on. + * + * When the chroma components are to be upsampled by simple replication + * (ie, box filtering), we can save some work in color conversion by + * calculating all the output pixels corresponding to a pair of chroma + * samples at one time. In the conversion equations + * R = Y + K1 * Cr + * G = Y + K2 * Cb + K3 * Cr + * B = Y + K4 * Cb + * only the Y term varies among the group of pixels corresponding to a pair + * of chroma samples, so the rest of the terms can be calculated just once. + * At typical sampling ratios, this eliminates half or three-quarters of the + * multiplications needed for color conversion. + * + * This file currently provides implementations for the following cases: + * YCbCr => RGB color conversion only. + * Sampling ratios of 2h1v or 2h2v. + * No scaling needed at upsample time. + * Corner-aligned (non-CCIR601) sampling alignment. + * Other special cases could be added, but in most applications these are + * the only common cases. (For uncommon cases we fall back on the more + * general code in jdsample.c and jdcolor.c.) + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef UPSAMPLE_MERGING_SUPPORTED + + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Pointer to routine to do actual upsampling/conversion of one row group */ + JMETHOD(void, upmethod, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf)); + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ + + /* For 2:1 vertical sampling, we produce two output rows at a time. + * We need a "spare" row buffer to hold the second output row if the + * application provides just a one-row buffer; we also use the spare + * to discard the dummy last row if the image height is odd. + */ + JSAMPROW spare_row; + boolean spare_full; /* T if spare buffer is occupied */ + + JDIMENSION out_row_width; /* samples per output row */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. + * This is taken directly from jdcolor.c; see that file for more info. + */ + +LOCAL void +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int i; + INT32 x; + SHIFT_TEMPS + + upsample->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + upsample->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.40200 * x */ + upsample->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + upsample->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + /* Cr=>G value is scaled-up -0.71414 * x */ + upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF void +start_pass_merged_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the spare buffer empty */ + upsample->spare_full = FALSE; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * The control routine just handles the row buffering considerations. + */ + +METHODDEF void +merged_2v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 2:1 vertical sampling case: may need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW work_ptrs[2]; + JDIMENSION num_rows; /* number of rows returned to caller */ + + if (upsample->spare_full) { + /* If we have a spare row saved from a previous cycle, just return it. */ + jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, + 1, upsample->out_row_width); + num_rows = 1; + upsample->spare_full = FALSE; + } else { + /* Figure number of rows to return to caller. */ + num_rows = 2; + /* Not more than the distance to the end of the image. */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + /* Create output pointer array for upsampler. */ + work_ptrs[0] = output_buf[*out_row_ctr]; + if (num_rows > 1) { + work_ptrs[1] = output_buf[*out_row_ctr + 1]; + } else { + work_ptrs[1] = upsample->spare_row; + upsample->spare_full = TRUE; + } + /* Now do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); + } + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (! upsample->spare_full) + (*in_row_group_ctr)++; +} + + +METHODDEF void +merged_1v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 1:1 vertical sampling case: much easier, never need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Just do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, + output_buf + *out_row_ctr); + /* Adjust counts */ + (*out_row_ctr)++; + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by the control routines to do + * the actual upsampling/conversion. One row group is processed per call. + * + * Note: since we may be writing directly into application-supplied buffers, + * we have to be honest about the output width; we can't assume the buffer + * has been rounded up to an even width. + */ + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. + */ + +METHODDEF void +h2v1_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr; + JSAMPROW inptr0, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr0 = input_buf[0][in_row_group_ctr]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr = output_buf[0]; + /* Loop for each pair of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 2 Y values and emit 2 pixels */ + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr0); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. + */ + +METHODDEF void +h2v2_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr0, outptr1; + JSAMPROW inptr00, inptr01, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr00 = input_buf[0][in_row_group_ctr*2]; + inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr0 = output_buf[0]; + outptr1 = output_buf[1]; + /* Loop for each group of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 4 Y values and emit 4 pixels */ + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr00); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + y = GETJSAMPLE(*inptr01); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Module initialization routine for merged upsampling/color conversion. + * + * NB: this is called under the conditions determined by use_merged_upsample() + * in jdmaster.c. That routine MUST correspond to the actual capabilities + * of this module; no safety checks are made here. + */ + +GLOBAL void +jinit_merged_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_merged_upsample; + upsample->pub.need_context_rows = FALSE; + + upsample->out_row_width = cinfo->output_width * cinfo->out_color_components; + + if (cinfo->max_v_samp_factor == 2) { + upsample->pub.upsample = merged_2v_upsample; + upsample->upmethod = h2v2_merged_upsample; + /* Allocate a spare row buffer */ + upsample->spare_row = (JSAMPROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE))); + } else { + upsample->pub.upsample = merged_1v_upsample; + upsample->upmethod = h2v1_merged_upsample; + /* No spare row needed */ + upsample->spare_row = NULL; + } + + build_ycc_rgb_table(cinfo); +} + +#endif /* UPSAMPLE_MERGING_SUPPORTED */ diff --git a/engine/jpeg-6/jdphuff.c b/engine/jpeg-6/jdphuff.c new file mode 100644 index 0000000..025bfd8 --- /dev/null +++ b/engine/jpeg-6/jdphuff.c @@ -0,0 +1,642 @@ +/* + * jdphuff.c + * + * Copyright (C) 1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines for progressive JPEG. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdhuff.h" /* Declarations shared with jdhuff.c */ + + +#ifdef D_PROGRESSIVE_SUPPORTED + +/* + * Expanded entropy decoder object for progressive Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + unsigned int EOBRUN; /* remaining EOBs in EOBRUN */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).EOBRUN = (src).EOBRUN, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_decoder pub; /* public fields */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + bitread_perm_state bitstate; /* Bit buffer at start of MCU */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */ +} phuff_entropy_decoder; + +typedef phuff_entropy_decoder * phuff_entropy_ptr; + +/* Forward declarations */ +METHODDEF boolean decode_mcu_DC_first JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF boolean decode_mcu_AC_first JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF boolean decode_mcu_DC_refine JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF boolean decode_mcu_AC_refine JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF void +start_pass_phuff_decoder (j_decompress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + boolean is_DC_band, bad; + int ci, coefi, tbl; + int *coef_bit_ptr; + jpeg_component_info * compptr; + + is_DC_band = (cinfo->Ss == 0); + + /* Validate scan parameters */ + bad = FALSE; + if (is_DC_band) { + if (cinfo->Se != 0) + bad = TRUE; + } else { + /* need not check Ss/Se < 0 since they came from unsigned bytes */ + if (cinfo->Ss > cinfo->Se || cinfo->Se >= DCTSIZE2) + bad = TRUE; + /* AC scans may have only one component */ + if (cinfo->comps_in_scan != 1) + bad = TRUE; + } + if (cinfo->Ah != 0) { + /* Successive approximation refinement scan: must have Al = Ah-1. */ + if (cinfo->Al != cinfo->Ah-1) + bad = TRUE; + } + if (cinfo->Al > 13) /* need not check for < 0 */ + bad = TRUE; + if (bad) + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + /* Update progression status, and verify that scan order is legal. + * Note that inter-scan inconsistencies are treated as warnings + * not fatal errors ... not clear if this is right way to behave. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + int cindex = cinfo->cur_comp_info[ci]->component_index; + coef_bit_ptr = & cinfo->coef_bits[cindex][0]; + if (!is_DC_band && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); + for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { + int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; + if (cinfo->Ah != expected) + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); + coef_bit_ptr[coefi] = cinfo->Al; + } + } + + /* Select MCU decoding routine */ + if (cinfo->Ah == 0) { + if (is_DC_band) + entropy->pub.decode_mcu = decode_mcu_DC_first; + else + entropy->pub.decode_mcu = decode_mcu_AC_first; + } else { + if (is_DC_band) + entropy->pub.decode_mcu = decode_mcu_DC_refine; + else + entropy->pub.decode_mcu = decode_mcu_AC_refine; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Make sure requested tables are present, and compute derived tables. + * We may build same derived table more than once, but it's not expensive. + */ + if (is_DC_band) { + if (cinfo->Ah == 0) { /* DC refinement needs no table */ + tbl = compptr->dc_tbl_no; + if (tbl < 0 || tbl >= NUM_HUFF_TBLS || + cinfo->dc_huff_tbl_ptrs[tbl] == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl); + jpeg_make_d_derived_tbl(cinfo, cinfo->dc_huff_tbl_ptrs[tbl], + & entropy->derived_tbls[tbl]); + } + } else { + tbl = compptr->ac_tbl_no; + if (tbl < 0 || tbl >= NUM_HUFF_TBLS || + cinfo->ac_huff_tbl_ptrs[tbl] == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl); + jpeg_make_d_derived_tbl(cinfo, cinfo->ac_huff_tbl_ptrs[tbl], + & entropy->derived_tbls[tbl]); + /* remember the single active table */ + entropy->ac_derived_tbl = entropy->derived_tbls[tbl]; + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->bitstate.printed_eod = FALSE; + + /* Initialize private state variables */ + entropy->saved.EOBRUN = 0; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL boolean +process_restart (j_decompress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Re-init EOB run count, too */ + entropy->saved.EOBRUN = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Next segment can get another out-of-data warning */ + entropy->bitstate.printed_eod = FALSE; + + return TRUE; +} + + +/* + * Huffman MCU decoding. + * Each of these routines decodes and returns one MCU's worth of + * Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. + * + * We return FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * spectral selection, since we'll just re-assign them on the next call. + * Successive approximation AC refinement has to be more careful, however.) + */ + +/* + * MCU decoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF boolean +decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int Al = cinfo->Al; + register int s, r; + int blkn, ci; + JBLOCKROW block; + BITREAD_STATE_VARS; + savable_state state; + d_derived_tbl * tbl; + jpeg_component_info * compptr; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + tbl = entropy->derived_tbls[compptr->dc_tbl_no]; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, tbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + /* Convert DC difference to actual value, update last_dc_val */ + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */ + (*block)[0] = (JCOEF) (s << Al); + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF boolean +decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int Se = cinfo->Se; + int Al = cinfo->Al; + register int s, k, r; + unsigned int EOBRUN; + JBLOCKROW block; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Load up working state. + * We can avoid loading/saving bitread state if in an EOB run. + */ + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we care about */ + + /* There is always only one block per MCU */ + + if (EOBRUN > 0) /* if it's a band of zeroes... */ + EOBRUN--; /* ...process it now (we do nothing) */ + else { + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + for (k = cinfo->Ss; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, return FALSE, label2); + r = s >> 4; + s &= 15; + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Scale and output coefficient in natural (dezigzagged) order */ + (*block)[jpeg_natural_order[k]] = (JCOEF) (s << Al); + } else { + if (r == 15) { /* ZRL */ + k += 15; /* skip 15 zeroes in band */ + } else { /* EOBr, run length is 2^r + appended bits */ + EOBRUN = 1 << r; + if (r) { /* EOBr, r > 0 */ + CHECK_BIT_BUFFER(br_state, r, return FALSE); + r = GET_BITS(r); + EOBRUN += r; + } + EOBRUN--; /* this band is processed at this moment */ + break; /* force end-of-band */ + } + } + } + + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + } + + /* Completed MCU, so update state */ + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we care about */ + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF boolean +decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int blkn; + JBLOCKROW block; + BITREAD_STATE_VARS; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* Encoded data is simply the next bit of the two's-complement DC value */ + CHECK_BIT_BUFFER(br_state, 1, return FALSE); + if (GET_BITS(1)) + (*block)[0] |= p1; + /* Note: since we use |=, repeating the assignment later is safe */ + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC successive approximation refinement scan. + */ + +METHODDEF boolean +decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int Se = cinfo->Se; + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ + register int s, k, r; + unsigned int EOBRUN; + JBLOCKROW block; + JCOEFPTR thiscoef; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + int num_newnz; + int newnz_pos[DCTSIZE2]; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we care about */ + + /* There is always only one block per MCU */ + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + /* If we are forced to suspend, we must undo the assignments to any newly + * nonzero coefficients in the block, because otherwise we'd get confused + * next time about which coefficients were already nonzero. + * But we need not undo addition of bits to already-nonzero coefficients; + * instead, we can test the current bit position to see if we already did it. + */ + num_newnz = 0; + + /* initialize coefficient loop counter to start of band */ + k = cinfo->Ss; + + if (EOBRUN == 0) { + for (; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, goto undoit, label3); + r = s >> 4; + s &= 15; + if (s) { + if (s != 1) /* size of new coef should always be 1 */ + WARNMS(cinfo, JWRN_HUFF_BAD_CODE); + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) + s = p1; /* newly nonzero coef is positive */ + else + s = m1; /* newly nonzero coef is negative */ + } else { + if (r != 15) { + EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */ + if (r) { + CHECK_BIT_BUFFER(br_state, r, goto undoit); + r = GET_BITS(r); + EOBRUN += r; + } + break; /* rest of block is handled by EOB logic */ + } + /* note s = 0 for processing ZRL */ + } + /* Advance over already-nonzero coefs and r still-zero coefs, + * appending correction bits to the nonzeroes. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + do { + thiscoef = *block + jpeg_natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } else { + if (--r < 0) + break; /* reached target zero coefficient */ + } + k++; + } while (k <= Se); + if (s) { + int pos = jpeg_natural_order[k]; + /* Output newly nonzero coefficient */ + (*block)[pos] = (JCOEF) s; + /* Remember its position in case we have to suspend */ + newnz_pos[num_newnz++] = pos; + } + } + } + + if (EOBRUN > 0) { + /* Scan any remaining coefficient positions after the end-of-band + * (the last newly nonzero coefficient, if any). Append a correction + * bit to each already-nonzero coefficient. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + for (; k <= Se; k++) { + thiscoef = *block + jpeg_natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } + } + /* Count one block completed in EOB run */ + EOBRUN--; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we care about */ + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; + +undoit: + /* Re-zero any output coefficients that we made newly nonzero */ + while (num_newnz > 0) + (*block)[newnz_pos[--num_newnz]] = 0; + + return FALSE; +} + + +/* + * Module initialization routine for progressive Huffman entropy decoding. + */ + +GLOBAL void +jinit_phuff_decoder (j_decompress_ptr cinfo) +{ + phuff_entropy_ptr entropy; + int *coef_bit_ptr; + int ci, i; + + entropy = (phuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(phuff_entropy_decoder)); + cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; + entropy->pub.start_pass = start_pass_phuff_decoder; + + /* Mark derived tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + } + + /* Create progression status table */ + cinfo->coef_bits = (int (*)[DCTSIZE2]) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components*DCTSIZE2*SIZEOF(int)); + coef_bit_ptr = & cinfo->coef_bits[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (i = 0; i < DCTSIZE2; i++) + *coef_bit_ptr++ = -1; +} + +#endif /* D_PROGRESSIVE_SUPPORTED */ diff --git a/engine/jpeg-6/jdpostct.c b/engine/jpeg-6/jdpostct.c new file mode 100644 index 0000000..f612002 --- /dev/null +++ b/engine/jpeg-6/jdpostct.c @@ -0,0 +1,290 @@ +/* + * jdpostct.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the decompression postprocessing controller. + * This controller manages the upsampling, color conversion, and color + * quantization/reduction steps; specifically, it controls the buffering + * between upsample/color conversion and color quantization/reduction. + * + * If no color quantization/reduction is required, then this module has no + * work to do, and it just hands off to the upsample/color conversion code. + * An integrated upsample/convert/quantize process would replace this module + * entirely. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_post_controller pub; /* public fields */ + + /* Color quantization source buffer: this holds output data from + * the upsample/color conversion step to be passed to the quantizer. + * For two-pass color quantization, we need a full-image buffer; + * for one-pass operation, a strip buffer is sufficient. + */ + jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ + JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ + JDIMENSION strip_height; /* buffer size in rows */ + /* for two-pass mode only: */ + JDIMENSION starting_row; /* row # of first row in current strip */ + JDIMENSION next_row; /* index of next row to fill/empty in strip */ +} my_post_controller; + +typedef my_post_controller * my_post_ptr; + + +/* Forward declarations */ +METHODDEF void post_process_1pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF void post_process_prepass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +METHODDEF void post_process_2pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF void +start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->quantize_colors) { + /* Single-pass processing with color quantization. */ + post->pub.post_process_data = post_process_1pass; + /* We could be doing buffered-image output before starting a 2-pass + * color quantization; in that case, jinit_d_post_controller did not + * allocate a strip buffer. Use the virtual-array buffer as workspace. + */ + if (post->buffer == NULL) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + (JDIMENSION) 0, post->strip_height, TRUE); + } + } else { + /* For single-pass processing without color quantization, + * I have no work to do; just call the upsampler directly. + */ + post->pub.post_process_data = cinfo->upsample->upsample; + } + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_SAVE_AND_PASS: + /* First pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_prepass; + break; + case JBUF_CRANK_DEST: + /* Second pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_2pass; + break; +#endif /* QUANT_2PASS_SUPPORTED */ + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } + post->starting_row = post->next_row = 0; +} + + +/* + * Process some data in the one-pass (strip buffer) case. + * This is used for color precision reduction as well as one-pass quantization. + */ + +METHODDEF void +post_process_1pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Fill the buffer, but not more than what we can dump out in one go. */ + /* Note we rely on the upsampler to detect bottom of image. */ + max_rows = out_rows_avail - *out_row_ctr; + if (max_rows > post->strip_height) + max_rows = post->strip_height; + num_rows = 0; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &num_rows, max_rows); + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer, output_buf + *out_row_ctr, (int) num_rows); + *out_row_ctr += num_rows; +} + + +#ifdef QUANT_2PASS_SUPPORTED + +/* + * Process some data in the first pass of 2-pass quantization. + */ + +METHODDEF void +post_process_prepass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION old_next_row, num_rows; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, TRUE); + } + + /* Upsample some data (up to a strip height's worth). */ + old_next_row = post->next_row; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &post->next_row, post->strip_height); + + /* Allow quantizer to scan new data. No data is emitted, */ + /* but we advance out_row_ctr so outer loop can tell when we're done. */ + if (post->next_row > old_next_row) { + num_rows = post->next_row - old_next_row; + (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row, + (JSAMPARRAY) NULL, (int) num_rows); + *out_row_ctr += num_rows; + } + + /* Advance if we filled the strip. */ + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + + +/* + * Process some data in the second pass of 2-pass quantization. + */ + +METHODDEF void +post_process_2pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, FALSE); + } + + /* Determine number of rows to emit. */ + num_rows = post->strip_height - post->next_row; /* available in strip */ + max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ + if (num_rows > max_rows) + num_rows = max_rows; + /* We have to check bottom of image here, can't depend on upsampler. */ + max_rows = cinfo->output_height - post->starting_row; + if (num_rows > max_rows) + num_rows = max_rows; + + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer + post->next_row, output_buf + *out_row_ctr, + (int) num_rows); + *out_row_ctr += num_rows; + + /* Advance if we filled the strip. */ + post->next_row += num_rows; + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize postprocessing controller. + */ + +GLOBAL void +jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_post_ptr post; + + post = (my_post_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_post_controller)); + cinfo->post = (struct jpeg_d_post_controller *) post; + post->pub.start_pass = start_pass_dpost; + post->whole_image = NULL; /* flag for no virtual arrays */ + post->buffer = NULL; /* flag for no strip buffer */ + + /* Create the quantization buffer, if needed */ + if (cinfo->quantize_colors) { + /* The buffer strip height is max_v_samp_factor, which is typically + * an efficient number of rows for upsampling to return. + * (In the presence of output rescaling, we might want to be smarter?) + */ + post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor; + if (need_full_buffer) { + /* Two-pass color quantization: need full-image storage. */ + /* We round up the number of rows to a multiple of the strip height. */ +#ifdef QUANT_2PASS_SUPPORTED + post->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + cinfo->output_width * cinfo->out_color_components, + (JDIMENSION) jround_up((long) cinfo->output_height, + (long) post->strip_height), + post->strip_height); +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + /* One-pass color quantization: just make a strip buffer. */ + post->buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width * cinfo->out_color_components, + post->strip_height); + } + } +} diff --git a/engine/jpeg-6/jdsample.c b/engine/jpeg-6/jdsample.c new file mode 100644 index 0000000..661e198 --- /dev/null +++ b/engine/jpeg-6/jdsample.c @@ -0,0 +1,478 @@ +/* + * jdsample.c + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains upsampling routines. + * + * Upsampling input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) + * sample rows of each component. Upsampling will normally produce + * max_v_samp_factor pixel rows from each row group (but this could vary + * if the upsampler is applying a scale factor of its own). + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to upsample a single component */ +typedef JMETHOD(void, upsample1_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Color conversion buffer. When using separate upsampling and color + * conversion steps, this buffer holds one upsampled row group until it + * has been color converted and output. + * Note: we do not allocate any storage for component(s) which are full-size, + * ie do not need rescaling. The corresponding entry of color_buf[] is + * simply set to point to the input data array, thereby avoiding copying. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + /* Per-component upsampling method pointers */ + upsample1_ptr methods[MAX_COMPONENTS]; + + int next_row_out; /* counts rows emitted from color_buf */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ + + /* Height of an input row group for each component. */ + int rowgroup_height[MAX_COMPONENTS]; + + /* These arrays save pixel expansion factors so that int_expand need not + * recompute them each time. They are unused for other upsampling methods. + */ + UINT8 h_expand[MAX_COMPONENTS]; + UINT8 v_expand[MAX_COMPONENTS]; +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF void +start_pass_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the conversion buffer empty */ + upsample->next_row_out = cinfo->max_v_samp_factor; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * In this version we upsample each component independently. + * We upsample one row group into the conversion buffer, then apply + * color conversion a row at a time. + */ + +METHODDEF void +sep_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int ci; + jpeg_component_info * compptr; + JDIMENSION num_rows; + + /* Fill the conversion buffer, if it's empty */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Invoke per-component upsample method. Notice we pass a POINTER + * to color_buf[ci], so that fullsize_upsample can change it. + */ + (*upsample->methods[ci]) (cinfo, compptr, + input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]), + upsample->color_buf + ci); + } + upsample->next_row_out = 0; + } + + /* Color-convert and emit rows */ + + /* How many we have in the buffer: */ + num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out); + /* Not more than the distance to the end of the image. Need this test + * in case the image height is not a multiple of max_v_samp_factor: + */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + + (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf, + (JDIMENSION) upsample->next_row_out, + output_buf + *out_row_ctr, + (int) num_rows); + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + upsample->next_row_out += num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by sep_upsample to upsample pixel values + * of a single component. One row group is processed per call. + */ + + +/* + * For full-size components, we just make color_buf[ci] point at the + * input buffer, and thus avoid copying any data. Note that this is + * safe only because sep_upsample doesn't declare the input row group + * "consumed" until we are done color converting and emitting it. + */ + +METHODDEF void +fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + *output_data_ptr = input_data; +} + + +/* + * This is a no-op version used for "uninteresting" components. + * These components will not be referenced by color conversion. + */ + +METHODDEF void +noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + *output_data_ptr = NULL; /* safety check */ +} + + +/* + * This version handles any integral sampling ratios. + * This is not used for typical JPEG files, so it need not be fast. + * Nor, for that matter, is it particularly accurate: the algorithm is + * simple replication of the input pixel onto the corresponding output + * pixels. The hi-falutin sampling literature refers to this as a + * "box filter". A box filter tends to introduce visible artifacts, + * so if you are actually going to use 3:1 or 4:1 sampling ratios + * you would be well advised to improve this code. + */ + +METHODDEF void +int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + register int h; + JSAMPROW outend; + int h_expand, v_expand; + int inrow, outrow; + + h_expand = upsample->h_expand[compptr->component_index]; + v_expand = upsample->v_expand[compptr->component_index]; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + /* Generate one output row with proper horizontal expansion */ + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + for (h = h_expand; h > 0; h--) { + *outptr++ = invalue; + } + } + /* Generate any additional output rows by duplicating the first one */ + if (v_expand > 1) { + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + v_expand-1, cinfo->output_width); + } + inrow++; + outrow += v_expand; + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 1:1 vertical. + * It's still a box filter. + */ + +METHODDEF void +h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int inrow; + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + inptr = input_data[inrow]; + outptr = output_data[inrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 2:1 vertical. + * It's still a box filter. + */ + +METHODDEF void +h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int inrow, outrow; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + 1, cinfo->output_width); + inrow++; + outrow += 2; + } +} + + +/* + * Fancy processing for the common case of 2:1 horizontal and 1:1 vertical. + * + * The upsampling algorithm is linear interpolation between pixel centers, + * also known as a "triangle filter". This is a good compromise between + * speed and visual quality. The centers of the output pixels are 1/4 and 3/4 + * of the way between input pixel centers. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF void +h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register int invalue; + register JDIMENSION colctr; + int inrow; + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + inptr = input_data[inrow]; + outptr = output_data[inrow]; + /* Special case for first column */ + invalue = GETJSAMPLE(*inptr++); + *outptr++ = (JSAMPLE) invalue; + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2); + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + /* General case: 3/4 * nearer pixel + 1/4 * further pixel */ + invalue = GETJSAMPLE(*inptr++) * 3; + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2); + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(*inptr) + 2) >> 2); + } + + /* Special case for last column */ + invalue = GETJSAMPLE(*inptr); + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2); + *outptr++ = (JSAMPLE) invalue; + } +} + + +/* + * Fancy processing for the common case of 2:1 horizontal and 2:1 vertical. + * Again a triangle filter; see comments for h2v1 case, above. + * + * It is OK for us to reference the adjacent input rows because we demanded + * context from the main buffer controller (see initialization code). + */ + +METHODDEF void +h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr0, inptr1, outptr; +#if BITS_IN_JSAMPLE == 8 + register int thiscolsum, lastcolsum, nextcolsum; +#else + register INT32 thiscolsum, lastcolsum, nextcolsum; +#endif + register JDIMENSION colctr; + int inrow, outrow, v; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + for (v = 0; v < 2; v++) { + /* inptr0 points to nearest input row, inptr1 points to next nearest */ + inptr0 = input_data[inrow]; + if (v == 0) /* next nearest is row above */ + inptr1 = input_data[inrow-1]; + else /* next nearest is row below */ + inptr1 = input_data[inrow+1]; + outptr = output_data[outrow++]; + + /* Special case for first column */ + thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */ + /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */ + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + } + + /* Special case for last column */ + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 7) >> 4); + } + inrow++; + } +} + + +/* + * Module initialization routine for upsampling. + */ + +GLOBAL void +jinit_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + int ci; + jpeg_component_info * compptr; + boolean need_buffer, do_fancy; + int h_in_group, v_in_group, h_out_group, v_out_group; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_upsample; + upsample->pub.upsample = sep_upsample; + upsample->pub.need_context_rows = FALSE; /* until we find out differently */ + + if (cinfo->CCIR601_sampling) /* this isn't supported */ + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1, + * so don't ask for it. + */ + do_fancy = cinfo->do_fancy_upsampling && cinfo->min_DCT_scaled_size > 1; + + /* Verify we can handle the sampling factors, select per-component methods, + * and create storage as needed. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Compute size of an "input group" after IDCT scaling. This many samples + * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. + */ + h_in_group = (compptr->h_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; + v_in_group = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; + h_out_group = cinfo->max_h_samp_factor; + v_out_group = cinfo->max_v_samp_factor; + upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ + need_buffer = TRUE; + if (! compptr->component_needed) { + /* Don't bother to upsample an uninteresting component. */ + upsample->methods[ci] = noop_upsample; + need_buffer = FALSE; + } else if (h_in_group == h_out_group && v_in_group == v_out_group) { + /* Fullsize components can be processed without any work. */ + upsample->methods[ci] = fullsize_upsample; + need_buffer = FALSE; + } else if (h_in_group * 2 == h_out_group && + v_in_group == v_out_group) { + /* Special cases for 2h1v upsampling */ + if (do_fancy && compptr->downsampled_width > 2) + upsample->methods[ci] = h2v1_fancy_upsample; + else + upsample->methods[ci] = h2v1_upsample; + } else if (h_in_group * 2 == h_out_group && + v_in_group * 2 == v_out_group) { + /* Special cases for 2h2v upsampling */ + if (do_fancy && compptr->downsampled_width > 2) { + upsample->methods[ci] = h2v2_fancy_upsample; + upsample->pub.need_context_rows = TRUE; + } else + upsample->methods[ci] = h2v2_upsample; + } else if ((h_out_group % h_in_group) == 0 && + (v_out_group % v_in_group) == 0) { + /* Generic integral-factors upsampling method */ + upsample->methods[ci] = int_upsample; + upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group); + upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group); + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + if (need_buffer) { + upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) cinfo->output_width, + (long) cinfo->max_h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/engine/jpeg-6/jdtrans.c b/engine/jpeg-6/jdtrans.c new file mode 100644 index 0000000..5c14adc --- /dev/null +++ b/engine/jpeg-6/jdtrans.c @@ -0,0 +1,122 @@ +/* + * jdtrans.c + * + * Copyright (C) 1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding decompression, + * that is, reading raw DCT coefficient arrays from an input JPEG file. + * The routines in jdapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL void transdecode_master_selection JPP((j_decompress_ptr cinfo)); + + +/* + * Read the coefficient arrays from a JPEG file. + * jpeg_read_header must be completed before calling this. + * + * The entire image is read into a set of virtual coefficient-block arrays, + * one per component. The return value is a pointer to the array of + * virtual-array descriptors. These can be manipulated directly via the + * JPEG memory manager, or handed off to jpeg_write_coefficients(). + * To release the memory occupied by the virtual arrays, call + * jpeg_finish_decompress() when done with the data. + * + * Returns NULL if suspended. This case need be checked only if + * a suspending data source is used. + */ + +GLOBAL jvirt_barray_ptr * +jpeg_read_coefficients (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize active modules */ + transdecode_master_selection(cinfo); + cinfo->global_state = DSTATE_RDCOEFS; + } else if (cinfo->global_state != DSTATE_RDCOEFS) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Absorb whole file into the coef buffer */ + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return NULL; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* startup underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } + /* Set state so that jpeg_finish_decompress does the right thing */ + cinfo->global_state = DSTATE_STOPPING; + return cinfo->coef->coef_arrays; +} + + +/* + * Master selection of decompression modules for transcoding. + * This substitutes for jdmaster.c's initialization of the full decompressor. + */ + +LOCAL void +transdecode_master_selection (j_decompress_ptr cinfo) +{ + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef D_PROGRESSIVE_SUPPORTED + jinit_phuff_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_decoder(cinfo); + } + + /* Always get a full-image coefficient buffer. */ + jinit_d_coef_controller(cinfo, TRUE); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + + /* Initialize progress monitoring. */ + if (cinfo->progress != NULL) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else if (cinfo->inputctl->has_multiple_scans) { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } else { + nscans = 1; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = 1; + } +} diff --git a/engine/jpeg-6/jerror.c b/engine/jpeg-6/jerror.c new file mode 100644 index 0000000..1324d5e --- /dev/null +++ b/engine/jpeg-6/jerror.c @@ -0,0 +1,232 @@ +/* + * jerror.c + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains simple error-reporting and trace-message routines. + * These are suitable for Unix-like systems and others where writing to + * stderr is the right thing to do. Many applications will want to replace + * some or all of these routines. + * + * These routines are used by both the compression and decompression code. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jversion.h" +#include "jerror.h" + +//#include "../renderer/tr_local.h" + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif + + +/* + * Create the message string table. + * We do this from the master message list in jerror.h by re-reading + * jerror.h with a suitable definition for macro JMESSAGE. + * The message table is made an external symbol just in case any applications + * want to refer to it directly. + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_message_table jMsgTable +#endif + +#define JMESSAGE(code,string) string , + +const char * const jpeg_std_message_table[] = { +#include "jerror.h" + NULL +}; + + +/* + * Error exit handler: must not return to caller. + * + * Applications may override this if they want to get control back after + * an error. Typically one would longjmp somewhere instead of exiting. + * The setjmp buffer can be made a private field within an expanded error + * handler object. Note that the info needed to generate an error message + * is stored in the error object, so you can generate the message now or + * later, at your convenience. + * You should make sure that the JPEG object is cleaned up (with jpeg_abort + * or jpeg_destroy) at some point. + */ + +METHODDEF void +error_exit (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + Sys_Error( "%s\n", buffer ); +} + + +/* + * Actual output of an error or trace message. + * Applications may override this method to send JPEG messages somewhere + * other than stderr. + */ + +METHODDEF void +output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + + /* Send it to stderr, adding a newline */ + Con_Printf("%s\n", buffer); +} + + +/* + * Decide whether to emit a trace or warning message. + * msg_level is one of: + * -1: recoverable corrupt-data warning, may want to abort. + * 0: important advisory messages (always display to user). + * 1: first level of tracing detail. + * 2,3,...: successively more detailed tracing messages. + * An application might override this method if it wanted to abort on warnings + * or change the policy about which messages to display. + */ + +METHODDEF void +emit_message (j_common_ptr cinfo, int msg_level) +{ + struct jpeg_error_mgr * err = cinfo->err; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + + +/* + * Format a message string for the most recent JPEG error or message. + * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX + * characters. Note that no '\n' character is added to the string. + * Few applications should need to override this method. + */ + +METHODDEF void +format_message (j_common_ptr cinfo, char * buffer) +{ + struct jpeg_error_mgr * err = cinfo->err; + int msg_code = err->msg_code; + const char * msgtext = NULL; + const char * msgptr; + char ch; + boolean isstring; + + /* Look up message string in proper table */ + if (msg_code > 0 && msg_code <= err->last_jpeg_message) { + msgtext = err->jpeg_message_table[msg_code]; + } else if (err->addon_message_table != NULL && + msg_code >= err->first_addon_message && + msg_code <= err->last_addon_message) { + msgtext = err->addon_message_table[msg_code - err->first_addon_message]; + } + + /* Defend against bogus message number */ + if (msgtext == NULL) { + err->msg_parm.i[0] = msg_code; + msgtext = err->jpeg_message_table[0]; + } + + /* Check for string parameter, as indicated by %s in the message text */ + isstring = FALSE; + msgptr = msgtext; + while ((ch = *msgptr++) != '\0') { + if (ch == '%') { + if (*msgptr == 's') isstring = TRUE; + break; + } + } + + /* Format the message into the passed buffer */ + if (isstring) + sprintf(buffer, msgtext, err->msg_parm.s); + else + sprintf(buffer, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); +} + + +/* + * Reset error state variables at start of a new image. + * This is called during compression startup to reset trace/error + * processing to default state, without losing any application-specific + * method pointers. An application might possibly want to override + * this method if it has additional error processing state. + */ + +METHODDEF void +reset_error_mgr (j_common_ptr cinfo) +{ + cinfo->err->num_warnings = 0; + /* trace_level is not reset since it is an application-supplied parameter */ + cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ +} + + +/* + * Fill in the standard error-handling methods in a jpeg_error_mgr object. + * Typical call is: + * struct jpeg_compress_struct cinfo; + * struct jpeg_error_mgr err; + * + * cinfo.err = jpeg_std_error(&err); + * after which the application may override some of the methods. + */ + +GLOBAL struct jpeg_error_mgr * +jpeg_std_error (struct jpeg_error_mgr * err) +{ + err->error_exit = error_exit; + err->emit_message = emit_message; + err->output_message = output_message; + err->format_message = format_message; + err->reset_error_mgr = reset_error_mgr; + + err->trace_level = 0; /* default = no tracing */ + err->num_warnings = 0; /* no warnings emitted yet */ + err->msg_code = 0; /* may be useful as a flag for "no error" */ + + /* Initialize message table pointers */ + err->jpeg_message_table = jpeg_std_message_table; + err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; + + err->addon_message_table = NULL; + err->first_addon_message = 0; /* for safety */ + err->last_addon_message = 0; + + return err; +} diff --git a/engine/jpeg-6/jerror.h b/engine/jpeg-6/jerror.h new file mode 100644 index 0000000..bf60e7e --- /dev/null +++ b/engine/jpeg-6/jerror.h @@ -0,0 +1,273 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, there are legal restrictions on arithmetic coding") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_COUNTS, "Bogus DHT counts") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_MINOR, "Unknown JFIF minor revision number %d.%02d") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Skipping marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/engine/jpeg-6/jfdctflt.c b/engine/jpeg-6/jfdctflt.c new file mode 100644 index 0000000..21371eb --- /dev/null +++ b/engine/jpeg-6/jfdctflt.c @@ -0,0 +1,168 @@ +/* + * jfdctflt.c + * + * Copyright (C) 1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * forward DCT (Discrete Cosine Transform). + * + * This implementation should be more accurate than either of the integer + * DCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL void +jpeg_fdct_float (FAST_FLOAT * data) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z1, z2, z3, z4, z5, z11, z13; + FAST_FLOAT *dataptr; + int ctr; + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/engine/jpeg-6/jfdctfst.c b/engine/jpeg-6/jfdctfst.c new file mode 100644 index 0000000..a52d7b7 --- /dev/null +++ b/engine/jpeg-6/jfdctfst.c @@ -0,0 +1,224 @@ +/* + * jfdctfst.c + * + * Copyright (C) 1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jfdctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * Again to save a few shifts, the intermediate results between pass 1 and + * pass 2 are not upscaled, but are represented only to integral precision. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#define CONST_BITS 8 + + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */ +#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */ +#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */ +#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */ +#else +#define FIX_0_382683433 FIX(0.382683433) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_707106781 FIX(0.707106781) +#define FIX_1_306562965 FIX(1.306562965) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL void +jpeg_fdct_ifast (DCTELEM * data) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z1, z2, z3, z4, z5, z11, z13; + DCTELEM *dataptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/engine/jpeg-6/jfdctint.c b/engine/jpeg-6/jfdctint.c new file mode 100644 index 0000000..7df0433 --- /dev/null +++ b/engine/jpeg-6/jfdctint.c @@ -0,0 +1,283 @@ +/* + * jfdctint.c + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D DCT step produces outputs which are a factor of sqrt(N) + * larger than the true DCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D DCT, + * because the y0 and y4 outputs need not be divided by sqrt(N). + * In the IJG code, this factor of 8 is removed by the quantization step + * (in jcdctmgr.c), NOT in this module. + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (For 12-bit sample data, the intermediate + * array is INT32 anyway.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL void +jpeg_fdct_islow (DCTELEM * data) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + DCTELEM *dataptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = (DCTELEM) ((tmp10 + tmp11) << PASS1_BITS); + dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), + CONST_BITS-PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents cos(K*pi/16). + * i0..i3 in the paper are tmp4..tmp7 here. + */ + + z1 = tmp4 + tmp7; + z2 = tmp5 + tmp6; + z3 = tmp4 + tmp6; + z4 = tmp5 + tmp7; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + dataptr[7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, CONST_BITS-PASS1_BITS); + dataptr[1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), + CONST_BITS+PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents cos(K*pi/16). + * i0..i3 in the paper are tmp4..tmp7 here. + */ + + z1 = tmp4 + tmp7; + z2 = tmp5 + tmp6; + z3 = tmp4 + tmp6; + z4 = tmp5 + tmp7; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/engine/jpeg-6/jidctflt.c b/engine/jpeg-6/jidctflt.c new file mode 100644 index 0000000..847919e --- /dev/null +++ b/engine/jpeg-6/jidctflt.c @@ -0,0 +1,241 @@ +/* + * jidctflt.c + * + * Copyright (C) 1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * This implementation should be more accurate than either of the integer + * IDCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a float result. + */ + +#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL void +jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z5, z10, z11, z12, z13; + JCOEFPTR inptr; + FLOAT_MULT_TYPE * quantptr; + FAST_FLOAT * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*2] | inptr[DCTSIZE*3] | + inptr[DCTSIZE*4] | inptr[DCTSIZE*5] | inptr[DCTSIZE*6] | + inptr[DCTSIZE*7]) == 0) { + /* AC terms all zero */ + FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + wsptr[DCTSIZE*0] = tmp0 + tmp7; + wsptr[DCTSIZE*7] = tmp0 - tmp7; + wsptr[DCTSIZE*1] = tmp1 + tmp6; + wsptr[DCTSIZE*6] = tmp1 - tmp6; + wsptr[DCTSIZE*2] = tmp2 + tmp5; + wsptr[DCTSIZE*5] = tmp2 - tmp5; + wsptr[DCTSIZE*4] = tmp3 + tmp4; + wsptr[DCTSIZE*3] = tmp3 - tmp4; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * And testing floats for zero is relatively expensive, so we don't bother. + */ + + /* Even part */ + + tmp10 = wsptr[0] + wsptr[4]; + tmp11 = wsptr[0] - wsptr[4]; + + tmp13 = wsptr[2] + wsptr[6]; + tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = wsptr[5] + wsptr[3]; + z10 = wsptr[5] - wsptr[3]; + z11 = wsptr[1] + wsptr[7]; + z12 = wsptr[1] - wsptr[7]; + + tmp7 = z11 + z13; + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[(int) DESCALE((INT32) (tmp0 + tmp7), 3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) DESCALE((INT32) (tmp0 - tmp7), 3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE((INT32) (tmp1 + tmp6), 3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) DESCALE((INT32) (tmp1 - tmp6), 3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE((INT32) (tmp2 + tmp5), 3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) DESCALE((INT32) (tmp2 - tmp5), 3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) DESCALE((INT32) (tmp3 + tmp4), 3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE((INT32) (tmp3 - tmp4), 3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/engine/jpeg-6/jidctfst.c b/engine/jpeg-6/jidctfst.c new file mode 100644 index 0000000..5736817 --- /dev/null +++ b/engine/jpeg-6/jidctfst.c @@ -0,0 +1,367 @@ +/* + * jidctfst.c + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jidctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * The dequantized coefficients are not integers because the AA&N scaling + * factors have been incorporated. We represent them scaled up by PASS1_BITS, + * so that the first and second IDCT rounds have the same input scaling. + * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to + * avoid a descaling shift; this compromises accuracy rather drastically + * for small quantization table entries, but it saves a lot of shifts. + * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway, + * so we use a much larger scaling factor to preserve accuracy. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 8 +#define PASS1_BITS 2 +#else +#define CONST_BITS 8 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */ +#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */ +#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */ +#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */ +#else +#define FIX_1_082392200 FIX(1.082392200) +#define FIX_1_414213562 FIX(1.414213562) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_613125930 FIX(2.613125930) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a DCTELEM result. For 8-bit data a 16x16->16 + * multiplication will do. For 12-bit data, the multiplier table is + * declared INT32, so a 32-bit multiply will be used. + */ + +#if BITS_IN_JSAMPLE == 8 +#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval)) +#else +#define DEQUANTIZE(coef,quantval) \ + DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS) +#endif + + +/* Like DESCALE, but applies to a DCTELEM and produces an int. + * We assume that int right shift is unsigned if INT32 right shift is. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS DCTELEM ishift_temp; +#if BITS_IN_JSAMPLE == 8 +#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */ +#else +#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */ +#endif +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +#ifdef USE_ACCURATE_ROUNDING +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n)) +#else +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT(x, n)) +#endif + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL void +jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z5, z10, z11, z12, z13; + JCOEFPTR inptr; + IFAST_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS /* for DESCALE */ + ISHIFT_TEMPS /* for IDESCALE */ + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (IFAST_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*2] | inptr[DCTSIZE*3] | + inptr[DCTSIZE*4] | inptr[DCTSIZE*5] | inptr[DCTSIZE*6] | + inptr[DCTSIZE*7]) == 0) { + /* AC terms all zero */ + int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7); + wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7); + wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6); + wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6); + wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5); + wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5); + wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4); + wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if ((wsptr[1] | wsptr[2] | wsptr[3] | wsptr[4] | wsptr[5] | wsptr[6] | + wsptr[7]) == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]); + tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]); + + tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]); + tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562) + - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3]; + z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3]; + z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7]; + z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7]; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/engine/jpeg-6/jidctint.c b/engine/jpeg-6/jidctint.c new file mode 100644 index 0000000..f25b08d --- /dev/null +++ b/engine/jpeg-6/jidctint.c @@ -0,0 +1,388 @@ +/* + * jidctint.c + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) + * larger than the true IDCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D IDCT, + * because the y0 and y4 inputs need not be divided by sqrt(N). + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (To scale up 12-bit sample data further, an + * intermediate INT32 array would be needed.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL void +jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*2] | inptr[DCTSIZE*3] | + inptr[DCTSIZE*4] | inptr[DCTSIZE*5] | inptr[DCTSIZE*6] | + inptr[DCTSIZE*7]) == 0) { + /* AC terms all zero */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + + tmp0 = (z2 + z3) << CONST_BITS; + tmp1 = (z2 - z3) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*7] = (int) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*6] = (int) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*5] = (int) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*3] = (int) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*4] = (int) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if ((wsptr[1] | wsptr[2] | wsptr[3] | wsptr[4] | wsptr[5] | wsptr[6] | + wsptr[7]) == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + tmp0 = ((INT32) wsptr[0] + (INT32) wsptr[4]) << CONST_BITS; + tmp1 = ((INT32) wsptr[0] - (INT32) wsptr[4]) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) wsptr[7]; + tmp1 = (INT32) wsptr[5]; + tmp2 = (INT32) wsptr[3]; + tmp3 = (INT32) wsptr[1]; + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/engine/jpeg-6/jidctred.c b/engine/jpeg-6/jidctred.c new file mode 100644 index 0000000..019c339 --- /dev/null +++ b/engine/jpeg-6/jidctred.c @@ -0,0 +1,397 @@ +/* + * jidctred.c + * + * Copyright (C) 1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains inverse-DCT routines that produce reduced-size output: + * either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block. + * + * The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M) + * algorithm used in jidctint.c. We simply replace each 8-to-8 1-D IDCT step + * with an 8-to-4 step that produces the four averages of two adjacent outputs + * (or an 8-to-2 step producing two averages of four outputs, for 2x2 output). + * These steps were derived by computing the corresponding values at the end + * of the normal LL&M code, then simplifying as much as possible. + * + * 1x1 is trivial: just take the DC coefficient divided by 8. + * + * See jidctint.c for additional comments. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef IDCT_SCALING_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling is the same as in jidctint.c. */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_211164243 ((INT32) 1730) /* FIX(0.211164243) */ +#define FIX_0_509795579 ((INT32) 4176) /* FIX(0.509795579) */ +#define FIX_0_601344887 ((INT32) 4926) /* FIX(0.601344887) */ +#define FIX_0_720959822 ((INT32) 5906) /* FIX(0.720959822) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_850430095 ((INT32) 6967) /* FIX(0.850430095) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_061594337 ((INT32) 8697) /* FIX(1.061594337) */ +#define FIX_1_272758580 ((INT32) 10426) /* FIX(1.272758580) */ +#define FIX_1_451774981 ((INT32) 11893) /* FIX(1.451774981) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_2_172734803 ((INT32) 17799) /* FIX(2.172734803) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_624509785 ((INT32) 29692) /* FIX(3.624509785) */ +#else +#define FIX_0_211164243 FIX(0.211164243) +#define FIX_0_509795579 FIX(0.509795579) +#define FIX_0_601344887 FIX(0.601344887) +#define FIX_0_720959822 FIX(0.720959822) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_850430095 FIX(0.850430095) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_061594337 FIX(1.061594337) +#define FIX_1_272758580 FIX(1.272758580) +#define FIX_1_451774981 FIX(1.451774981) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_172734803 FIX(2.172734803) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_624509785 FIX(3.624509785) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 4x4 output block. + */ + +GLOBAL void +jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE*4]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { + /* Don't bother to process column 4, because second pass won't use it */ + if (ctr == DCTSIZE-4) + continue; + if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*2] | inptr[DCTSIZE*3] | + inptr[DCTSIZE*5] | inptr[DCTSIZE*6] | inptr[DCTSIZE*7]) == 0) { + /* AC terms all zero; we need not examine term 4 for 4x4 output */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= (CONST_BITS+1); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp2 = MULTIPLY(z2, FIX_1_847759065) + MULTIPLY(z3, - FIX_0_765366865); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + z2 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ + + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ + + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ + + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ + + tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ + + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ + + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ + + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ + + /* Final output stage */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp2, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*3] = (int) DESCALE(tmp10 - tmp2, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp12 + tmp0, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 - tmp0, CONST_BITS-PASS1_BITS+1); + } + + /* Pass 2: process 4 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++) { + outptr = output_buf[ctr] + output_col; + /* It's not clear whether a zero row test is worthwhile here ... */ + +#ifndef NO_ZERO_ROW_TEST + if ((wsptr[1] | wsptr[2] | wsptr[3] | wsptr[5] | wsptr[6] | + wsptr[7]) == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp0 = ((INT32) wsptr[0]) << (CONST_BITS+1); + + tmp2 = MULTIPLY((INT32) wsptr[2], FIX_1_847759065) + + MULTIPLY((INT32) wsptr[6], - FIX_0_765366865); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + /* Odd part */ + + z1 = (INT32) wsptr[7]; + z2 = (INT32) wsptr[5]; + z3 = (INT32) wsptr[3]; + z4 = (INT32) wsptr[1]; + + tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ + + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ + + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ + + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ + + tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ + + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ + + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ + + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp2, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE(tmp10 - tmp2, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp12 + tmp0, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE(tmp12 - tmp0, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 2x2 output block. + */ + +GLOBAL void +jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp10, z1; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE*2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { + /* Don't bother to process columns 2,4,6 */ + if (ctr == DCTSIZE-2 || ctr == DCTSIZE-4 || ctr == DCTSIZE-6) + continue; + if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*3] | + inptr[DCTSIZE*5] | inptr[DCTSIZE*7]) == 0) { + /* AC terms all zero; we need not examine terms 2,4,6 for 2x2 output */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + + continue; + } + + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp10 = z1 << (CONST_BITS+2); + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp0 = MULTIPLY(z1, - FIX_0_720959822); /* sqrt(2) * (c7-c5+c3-c1) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp0 += MULTIPLY(z1, FIX_0_850430095); /* sqrt(2) * (-c1+c3+c5+c7) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp0 += MULTIPLY(z1, - FIX_1_272758580); /* sqrt(2) * (-c1+c3-c5-c7) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp0 += MULTIPLY(z1, FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ + + /* Final output stage */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp0, CONST_BITS-PASS1_BITS+2); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp10 - tmp0, CONST_BITS-PASS1_BITS+2); + } + + /* Pass 2: process 2 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 2; ctr++) { + outptr = output_buf[ctr] + output_col; + /* It's not clear whether a zero row test is worthwhile here ... */ + +#ifndef NO_ZERO_ROW_TEST + if ((wsptr[1] | wsptr[3] | wsptr[5] | wsptr[7]) == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = ((INT32) wsptr[0]) << (CONST_BITS+2); + + /* Odd part */ + + tmp0 = MULTIPLY((INT32) wsptr[7], - FIX_0_720959822) /* sqrt(2) * (c7-c5+c3-c1) */ + + MULTIPLY((INT32) wsptr[5], FIX_0_850430095) /* sqrt(2) * (-c1+c3+c5+c7) */ + + MULTIPLY((INT32) wsptr[3], - FIX_1_272758580) /* sqrt(2) * (-c1+c3-c5-c7) */ + + MULTIPLY((INT32) wsptr[1], FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3+2) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3+2) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 1x1 output block. + */ + +GLOBAL void +jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + int dcval; + ISLOW_MULT_TYPE * quantptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + SHIFT_TEMPS + + /* We hardly need an inverse DCT routine for this: just take the + * average pixel value, which is one-eighth of the DC coefficient. + */ + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + dcval = DEQUANTIZE(coef_block[0], quantptr[0]); + dcval = (int) DESCALE((INT32) dcval, 3); + + output_buf[0][output_col] = range_limit[dcval & RANGE_MASK]; +} + +#endif /* IDCT_SCALING_SUPPORTED */ diff --git a/engine/jpeg-6/jinclude.h b/engine/jpeg-6/jinclude.h new file mode 100644 index 0000000..eadcd19 --- /dev/null +++ b/engine/jpeg-6/jinclude.h @@ -0,0 +1,116 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +#ifdef _WIN32 + +#pragma warning(disable : 4018) // signed/unsigned mismatch +#pragma warning(disable : 4032) +#pragma warning(disable : 4051) +#pragma warning(disable : 4057) // slightly different base types +#pragma warning(disable : 4100) // unreferenced formal parameter +#pragma warning(disable : 4115) +#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4136) +#pragma warning(disable : 4152) // nonstandard extension, function/data pointer conversion in expression +#pragma warning(disable : 4201) +#pragma warning(disable : 4214) +#pragma warning(disable : 4244) +#pragma warning(disable : 4305) // truncation from const double to float +#pragma warning(disable : 4310) // cast truncates constant value +#pragma warning(disable: 4505) // unreferenced local function has been removed +#pragma warning(disable : 4514) +#pragma warning(disable : 4702) // unreachable code +#pragma warning(disable : 4711) // selected for automatic inline expansion +#pragma warning(disable : 4220) // varargs matches remaining parameters +#pragma warning(disable : 4761) // integral size mismatch +#endif + +/* Include auto-config file to find out which system include files we need. */ + +#include "../jpeg-6/jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/engine/jpeg-6/jload.c b/engine/jpeg-6/jload.c new file mode 100644 index 0000000..dc82555 --- /dev/null +++ b/engine/jpeg-6/jload.c @@ -0,0 +1,145 @@ + +#include "../game/q_shared.h" +#include "../qcommon/qcommon.h" + +/* + * Include file for users of JPEG library. + * You will need to have included system headers that define at least + * the typedefs FILE and size_t before you can include jpeglib.h. + * (stdio.h is sufficient on ANSI-conforming systems.) + * You may also wish to include "jerror.h". + */ + +#include "jpeglib.h" + + +int LoadJPG( const char *filename, unsigned char **pic, int *width, int *height ) { + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + fileHandle_t infile; /* source file */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + unsigned char *out; + + /* In this example we want to open the input file before doing anything else, + * so that the setjmp() error recovery below can assume the file is open. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to read binary files. + */ + + FS_FOpenFileRead( filename, &infile, qfalse ); + if (infile == 0) { + return 0; + } + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, infile); + + /* Step 3: read file parameters with jpeg_read_header() */ + + (void) jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + + out = Z_Malloc(cinfo.output_width*cinfo.output_height*cinfo.output_components); + + *pic = out; + *width = cinfo.output_width; + *height = cinfo.output_height; + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + buffer = (JSAMPARRAY)out+(row_stride*cinfo.output_scanline); + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + FS_FCloseFile(infile); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ + return 1; +} + diff --git a/engine/jpeg-6/jmemansi.c b/engine/jpeg-6/jmemansi.c new file mode 100644 index 0000000..70010f9 --- /dev/null +++ b/engine/jpeg-6/jmemansi.c @@ -0,0 +1,167 @@ +/* + * jmemansi.c + * + * Copyright (C) 1992-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a simple generic implementation of the system- + * dependent portion of the JPEG memory manager. This implementation + * assumes that you have the ANSI-standard library routine tmpfile(). + * Also, the problem of determining the amount of memory available + * is shoved onto the user. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + +#ifndef SEEK_SET /* pre-ANSI systems may not define this; */ +#define SEEK_SET 0 /* if not, assume 0 is correct */ +#endif + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL void * +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL void +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL void FAR * +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL void +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * It's impossible to do this in a portable way; our current solution is + * to make the user tell us (with a default value set at compile time). + * If you can actually get the available space, it's a good idea to subtract + * a slop factor of 5% or so. + */ + +#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ +#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */ +#endif + +GLOBAL long +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return cinfo->mem->max_memory_to_use - already_allocated; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + + +METHODDEF void +read_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFREAD(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF void +write_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFWRITE(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF void +close_backing_store (j_common_ptr cinfo, backing_store_ptr info) +{ + fclose(info->temp_file); + /* Since this implementation uses tmpfile() to create the file, + * no explicit file deletion is needed. + */ +} + + +/* + * Initial opening of a backing-store object. + * + * This version uses tmpfile(), which constructs a suitable file name + * behind the scenes. We don't have to use info->temp_name[] at all; + * indeed, we can't even find out the actual name of the temp file. + */ + +GLOBAL void +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + if ((info->temp_file = tmpfile()) == NULL) + ERREXITS(cinfo, JERR_TFILE_CREATE, ""); + info->read_backing_store = read_backing_store; + info->write_backing_store = write_backing_store; + info->close_backing_store = close_backing_store; +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL long +jpeg_mem_init (j_common_ptr cinfo) +{ + return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ +} + +GLOBAL void +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/engine/jpeg-6/jmemdos.c b/engine/jpeg-6/jmemdos.c new file mode 100644 index 0000000..4db8ec5 --- /dev/null +++ b/engine/jpeg-6/jmemdos.c @@ -0,0 +1,634 @@ +/* + * jmemdos.c + * + * Copyright (C) 1992-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides an MS-DOS-compatible implementation of the system- + * dependent portion of the JPEG memory manager. Temporary data can be + * stored in extended or expanded memory as well as in regular DOS files. + * + * If you use this file, you must be sure that NEED_FAR_POINTERS is defined + * if you compile in a small-data memory model; it should NOT be defined if + * you use a large-data memory model. This file is not recommended if you + * are using a flat-memory-space 386 environment such as DJGCC or Watcom C. + * Also, this code will NOT work if struct fields are aligned on greater than + * 2-byte boundaries. + * + * Based on code contributed by Ge' Weijers. + */ + +/* + * If you have both extended and expanded memory, you may want to change the + * order in which they are tried in jopen_backing_store. On a 286 machine + * expanded memory is usually faster, since extended memory access involves + * an expensive protected-mode-and-back switch. On 386 and better, extended + * memory is usually faster. As distributed, the code tries extended memory + * first (what? not everyone has a 386? :-). + * + * You can disable use of extended/expanded memory entirely by altering these + * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0). + */ + +#ifndef XMS_SUPPORTED +#define XMS_SUPPORTED 1 +#endif +#ifndef EMS_SUPPORTED +#define EMS_SUPPORTED 1 +#endif + + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare these */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +extern char * getenv JPP((const char * name)); +#endif + +#ifdef NEED_FAR_POINTERS + +#ifdef __TURBOC__ +/* These definitions work for Borland C (Turbo C) */ +#include /* need farmalloc(), farfree() */ +#define far_malloc(x) farmalloc(x) +#define far_free(x) farfree(x) +#else +/* These definitions work for Microsoft C and compatible compilers */ +#include /* need _fmalloc(), _ffree() */ +#define far_malloc(x) _fmalloc(x) +#define far_free(x) _ffree(x) +#endif + +#else /* not NEED_FAR_POINTERS */ + +#define far_malloc(x) malloc(x) +#define far_free(x) free(x) + +#endif /* NEED_FAR_POINTERS */ + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#else +#define READ_BINARY "rb" +#endif + +#if MAX_ALLOC_CHUNK >= 65535L /* make sure jconfig.h got this right */ + MAX_ALLOC_CHUNK should be less than 64K. /* deliberate syntax error */ +#endif + + +/* + * Declarations for assembly-language support routines (see jmemdosa.asm). + * + * The functions are declared "far" as are all pointer arguments; + * this ensures the assembly source code will work regardless of the + * compiler memory model. We assume "short" is 16 bits, "long" is 32. + */ + +typedef void far * XMSDRIVER; /* actually a pointer to code */ +typedef struct { /* registers for calling XMS driver */ + unsigned short ax, dx, bx; + void far * ds_si; + } XMScontext; +typedef struct { /* registers for calling EMS driver */ + unsigned short ax, dx, bx; + void far * ds_si; + } EMScontext; + +EXTERN short far jdos_open JPP((short far * handle, char far * filename)); +EXTERN short far jdos_close JPP((short handle)); +EXTERN short far jdos_seek JPP((short handle, long offset)); +EXTERN short far jdos_read JPP((short handle, void far * buffer, + unsigned short count)); +EXTERN short far jdos_write JPP((short handle, void far * buffer, + unsigned short count)); +EXTERN void far jxms_getdriver JPP((XMSDRIVER far *)); +EXTERN void far jxms_calldriver JPP((XMSDRIVER, XMScontext far *)); +EXTERN short far jems_available JPP((void)); +EXTERN void far jems_calldriver JPP((EMScontext far *)); + + +/* + * Selection of a file name for a temporary file. + * This is highly system-dependent, and you may want to customize it. + */ + +static int next_file_num; /* to distinguish among several temp files */ + +LOCAL void +select_file_name (char * fname) +{ + const char * env; + char * ptr; + FILE * tfile; + + /* Keep generating file names till we find one that's not in use */ + for (;;) { + /* Get temp directory name from environment TMP or TEMP variable; + * if none, use "." + */ + if ((env = (const char *) getenv("TMP")) == NULL) + if ((env = (const char *) getenv("TEMP")) == NULL) + env = "."; + if (*env == '\0') /* null string means "." */ + env = "."; + ptr = fname; /* copy name to fname */ + while (*env != '\0') + *ptr++ = *env++; + if (ptr[-1] != '\\' && ptr[-1] != '/') + *ptr++ = '\\'; /* append backslash if not in env variable */ + /* Append a suitable file name */ + next_file_num++; /* advance counter */ + sprintf(ptr, "JPG%03d.TMP", next_file_num); + /* Probe to see if file name is already in use */ + if ((tfile = fopen(fname, READ_BINARY)) == NULL) + break; + fclose(tfile); /* oops, it's there; close tfile & try again */ + } +} + + +/* + * Near-memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL void * +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL void +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are allocated in far memory, if possible + */ + +GLOBAL void FAR * +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) far_malloc(sizeofobject); +} + +GLOBAL void +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + far_free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * It's impossible to do this in a portable way; our current solution is + * to make the user tell us (with a default value set at compile time). + * If you can actually get the available space, it's a good idea to subtract + * a slop factor of 5% or so. + */ + +#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ +#define DEFAULT_MAX_MEM 300000L /* for total usage about 450K */ +#endif + +GLOBAL long +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return cinfo->mem->max_memory_to_use - already_allocated; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + +/* + * For MS-DOS we support three types of backing storage: + * 1. Conventional DOS files. We access these by direct DOS calls rather + * than via the stdio package. This provides a bit better performance, + * but the real reason is that the buffers to be read or written are FAR. + * The stdio library for small-data memory models can't cope with that. + * 2. Extended memory, accessed per the XMS V2.0 specification. + * 3. Expanded memory, accessed per the LIM/EMS 4.0 specification. + * You'll need copies of those specs to make sense of the related code. + * The specs are available by Internet FTP from the SIMTEL archives + * (oak.oakland.edu and its various mirror sites). See files + * pub/msdos/microsoft/xms20.arc and pub/msdos/info/limems41.zip. + */ + + +/* + * Access methods for a DOS file. + */ + + +METHODDEF void +read_file_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (jdos_seek(info->handle.file_handle, file_offset)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */ + if (byte_count > 65535L) /* safety check */ + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + if (jdos_read(info->handle.file_handle, buffer_address, + (unsigned short) byte_count)) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF void +write_file_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (jdos_seek(info->handle.file_handle, file_offset)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */ + if (byte_count > 65535L) /* safety check */ + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + if (jdos_write(info->handle.file_handle, buffer_address, + (unsigned short) byte_count)) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF void +close_file_store (j_common_ptr cinfo, backing_store_ptr info) +{ + jdos_close(info->handle.file_handle); /* close the file */ + remove(info->temp_name); /* delete the file */ +/* If your system doesn't have remove(), try unlink() instead. + * remove() is the ANSI-standard name for this function, but + * unlink() was more common in pre-ANSI systems. + */ + TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name); +} + + +LOCAL boolean +open_file_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + short handle; + + select_file_name(info->temp_name); + if (jdos_open((short far *) & handle, (char far *) info->temp_name)) { + /* might as well exit since jpeg_open_backing_store will fail anyway */ + ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name); + return FALSE; + } + info->handle.file_handle = handle; + info->read_backing_store = read_file_store; + info->write_backing_store = write_file_store; + info->close_backing_store = close_file_store; + TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name); + return TRUE; /* succeeded */ +} + + +/* + * Access methods for extended memory. + */ + +#if XMS_SUPPORTED + +static XMSDRIVER xms_driver; /* saved address of XMS driver */ + +typedef union { /* either long offset or real-mode pointer */ + long offset; + void far * ptr; + } XMSPTR; + +typedef struct { /* XMS move specification structure */ + long length; + XMSH src_handle; + XMSPTR src; + XMSH dst_handle; + XMSPTR dst; + } XMSspec; + +#define ODD(X) (((X) & 1L) != 0) + + +METHODDEF void +read_xms_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + XMScontext ctx; + XMSspec spec; + char endbuffer[2]; + + /* The XMS driver can't cope with an odd length, so handle the last byte + * specially if byte_count is odd. We don't expect this to be common. + */ + + spec.length = byte_count & (~ 1L); + spec.src_handle = info->handle.xms_handle; + spec.src.offset = file_offset; + spec.dst_handle = 0; + spec.dst.ptr = buffer_address; + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x0b00; /* EMB move */ + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax != 1) + ERREXIT(cinfo, JERR_XMS_READ); + + if (ODD(byte_count)) { + read_xms_store(cinfo, info, (void FAR *) endbuffer, + file_offset + byte_count - 1L, 2L); + ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0]; + } +} + + +METHODDEF void +write_xms_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + XMScontext ctx; + XMSspec spec; + char endbuffer[2]; + + /* The XMS driver can't cope with an odd length, so handle the last byte + * specially if byte_count is odd. We don't expect this to be common. + */ + + spec.length = byte_count & (~ 1L); + spec.src_handle = 0; + spec.src.ptr = buffer_address; + spec.dst_handle = info->handle.xms_handle; + spec.dst.offset = file_offset; + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x0b00; /* EMB move */ + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax != 1) + ERREXIT(cinfo, JERR_XMS_WRITE); + + if (ODD(byte_count)) { + read_xms_store(cinfo, info, (void FAR *) endbuffer, + file_offset + byte_count - 1L, 2L); + endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L]; + write_xms_store(cinfo, info, (void FAR *) endbuffer, + file_offset + byte_count - 1L, 2L); + } +} + + +METHODDEF void +close_xms_store (j_common_ptr cinfo, backing_store_ptr info) +{ + XMScontext ctx; + + ctx.dx = info->handle.xms_handle; + ctx.ax = 0x0a00; + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + TRACEMS1(cinfo, 1, JTRC_XMS_CLOSE, info->handle.xms_handle); + /* we ignore any error return from the driver */ +} + + +LOCAL boolean +open_xms_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + XMScontext ctx; + + /* Get address of XMS driver */ + jxms_getdriver((XMSDRIVER far *) & xms_driver); + if (xms_driver == NULL) + return FALSE; /* no driver to be had */ + + /* Get version number, must be >= 2.00 */ + ctx.ax = 0x0000; + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax < (unsigned short) 0x0200) + return FALSE; + + /* Try to get space (expressed in kilobytes) */ + ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10); + ctx.ax = 0x0900; + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax != 1) + return FALSE; + + /* Succeeded, save the handle and away we go */ + info->handle.xms_handle = ctx.dx; + info->read_backing_store = read_xms_store; + info->write_backing_store = write_xms_store; + info->close_backing_store = close_xms_store; + TRACEMS1(cinfo, 1, JTRC_XMS_OPEN, ctx.dx); + return TRUE; /* succeeded */ +} + +#endif /* XMS_SUPPORTED */ + + +/* + * Access methods for expanded memory. + */ + +#if EMS_SUPPORTED + +/* The EMS move specification structure requires word and long fields aligned + * at odd byte boundaries. Some compilers will align struct fields at even + * byte boundaries. While it's usually possible to force byte alignment, + * that causes an overall performance penalty and may pose problems in merging + * JPEG into a larger application. Instead we accept some rather dirty code + * here. Note this code would fail if the hardware did not allow odd-byte + * word & long accesses, but all 80x86 CPUs do. + */ + +typedef void far * EMSPTR; + +typedef union { /* EMS move specification structure */ + long length; /* It's easy to access first 4 bytes */ + char bytes[18]; /* Misaligned fields in here! */ + } EMSspec; + +/* Macros for accessing misaligned fields */ +#define FIELD_AT(spec,offset,type) (*((type *) &(spec.bytes[offset]))) +#define SRC_TYPE(spec) FIELD_AT(spec,4,char) +#define SRC_HANDLE(spec) FIELD_AT(spec,5,EMSH) +#define SRC_OFFSET(spec) FIELD_AT(spec,7,unsigned short) +#define SRC_PAGE(spec) FIELD_AT(spec,9,unsigned short) +#define SRC_PTR(spec) FIELD_AT(spec,7,EMSPTR) +#define DST_TYPE(spec) FIELD_AT(spec,11,char) +#define DST_HANDLE(spec) FIELD_AT(spec,12,EMSH) +#define DST_OFFSET(spec) FIELD_AT(spec,14,unsigned short) +#define DST_PAGE(spec) FIELD_AT(spec,16,unsigned short) +#define DST_PTR(spec) FIELD_AT(spec,14,EMSPTR) + +#define EMSPAGESIZE 16384L /* gospel, see the EMS specs */ + +#define HIBYTE(W) (((W) >> 8) & 0xFF) +#define LOBYTE(W) ((W) & 0xFF) + + +METHODDEF void +read_ems_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + EMScontext ctx; + EMSspec spec; + + spec.length = byte_count; + SRC_TYPE(spec) = 1; + SRC_HANDLE(spec) = info->handle.ems_handle; + SRC_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE); + SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE); + DST_TYPE(spec) = 0; + DST_HANDLE(spec) = 0; + DST_PTR(spec) = buffer_address; + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x5700; /* move memory region */ + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + ERREXIT(cinfo, JERR_EMS_READ); +} + + +METHODDEF void +write_ems_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + EMScontext ctx; + EMSspec spec; + + spec.length = byte_count; + SRC_TYPE(spec) = 0; + SRC_HANDLE(spec) = 0; + SRC_PTR(spec) = buffer_address; + DST_TYPE(spec) = 1; + DST_HANDLE(spec) = info->handle.ems_handle; + DST_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE); + DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE); + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x5700; /* move memory region */ + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + ERREXIT(cinfo, JERR_EMS_WRITE); +} + + +METHODDEF void +close_ems_store (j_common_ptr cinfo, backing_store_ptr info) +{ + EMScontext ctx; + + ctx.ax = 0x4500; + ctx.dx = info->handle.ems_handle; + jems_calldriver((EMScontext far *) & ctx); + TRACEMS1(cinfo, 1, JTRC_EMS_CLOSE, info->handle.ems_handle); + /* we ignore any error return from the driver */ +} + + +LOCAL boolean +open_ems_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + EMScontext ctx; + + /* Is EMS driver there? */ + if (! jems_available()) + return FALSE; + + /* Get status, make sure EMS is OK */ + ctx.ax = 0x4000; + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + return FALSE; + + /* Get version, must be >= 4.0 */ + ctx.ax = 0x4600; + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40) + return FALSE; + + /* Try to allocate requested space */ + ctx.ax = 0x4300; + ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE); + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + return FALSE; + + /* Succeeded, save the handle and away we go */ + info->handle.ems_handle = ctx.dx; + info->read_backing_store = read_ems_store; + info->write_backing_store = write_ems_store; + info->close_backing_store = close_ems_store; + TRACEMS1(cinfo, 1, JTRC_EMS_OPEN, ctx.dx); + return TRUE; /* succeeded */ +} + +#endif /* EMS_SUPPORTED */ + + +/* + * Initial opening of a backing-store object. + */ + +GLOBAL void +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + /* Try extended memory, then expanded memory, then regular file. */ +#if XMS_SUPPORTED + if (open_xms_store(cinfo, info, total_bytes_needed)) + return; +#endif +#if EMS_SUPPORTED + if (open_ems_store(cinfo, info, total_bytes_needed)) + return; +#endif + if (open_file_store(cinfo, info, total_bytes_needed)) + return; + ERREXITS(cinfo, JERR_TFILE_CREATE, ""); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL long +jpeg_mem_init (j_common_ptr cinfo) +{ + next_file_num = 0; /* initialize temp file name generator */ + return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ +} + +GLOBAL void +jpeg_mem_term (j_common_ptr cinfo) +{ + /* Microsoft C, at least in v6.00A, will not successfully reclaim freed + * blocks of size > 32Kbytes unless we give it a kick in the rear, like so: + */ +#ifdef NEED_FHEAPMIN + _fheapmin(); +#endif +} diff --git a/engine/jpeg-6/jmemmgr.c b/engine/jpeg-6/jmemmgr.c new file mode 100644 index 0000000..dc3e1c7 --- /dev/null +++ b/engine/jpeg-6/jmemmgr.c @@ -0,0 +1,1115 @@ +/* + * jmemmgr.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the JPEG system-independent memory management + * routines. This code is usable across a wide variety of machines; most + * of the system dependencies have been isolated in a separate file. + * The major functions provided here are: + * * pool-based allocation and freeing of memory; + * * policy decisions about how to divide available memory among the + * virtual arrays; + * * control logic for swapping virtual arrays between main memory and + * backing storage. + * The separate system-dependent file provides the actual backing-storage + * access code, and it contains the policy decision about how much total + * main memory to use. + * This file is system-dependent in the sense that some of its functions + * are unnecessary in some systems. For example, if there is enough virtual + * memory so that backing storage will never be used, much of the virtual + * array control logic could be removed. (Of course, if you have that much + * memory then you shouldn't care about a little bit of unused code...) + */ + +#define JPEG_INTERNALS +#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef NO_GETENV +#ifndef HAVE_STDLIB_H /* should declare getenv() */ +extern char * getenv JPP((const char * name)); +#endif +#endif + + +/* + * Some important notes: + * The allocation routines provided here must never return NULL. + * They should exit to error_exit if unsuccessful. + * + * It's not a good idea to try to merge the sarray and barray routines, + * even though they are textually almost the same, because samples are + * usually stored as bytes while coefficients are shorts or ints. Thus, + * in machines where byte pointers have a different representation from + * word pointers, the resulting machine code could not be the same. + */ + + +/* + * Many machines require storage alignment: longs must start on 4-byte + * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() + * always returns pointers that are multiples of the worst-case alignment + * requirement, and we had better do so too. + * There isn't any really portable way to determine the worst-case alignment + * requirement. This module assumes that the alignment requirement is + * multiples of sizeof(ALIGN_TYPE). + * By default, we define ALIGN_TYPE as double. This is necessary on some + * workstations (where doubles really do need 8-byte alignment) and will work + * fine on nearly everything. If your machine has lesser alignment needs, + * you can save a few bytes by making ALIGN_TYPE smaller. + * The only place I know of where this will NOT work is certain Macintosh + * 680x0 compilers that define double as a 10-byte IEEE extended float. + * Doing 10-byte alignment is counterproductive because longwords won't be + * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have + * such a compiler. + */ + +#ifndef ALIGN_TYPE /* so can override from jconfig.h */ +#define ALIGN_TYPE double +#endif + + +/* + * We allocate objects from "pools", where each pool is gotten with a single + * request to jpeg_get_small() or jpeg_get_large(). There is no per-object + * overhead within a pool, except for alignment padding. Each pool has a + * header with a link to the next pool of the same class. + * Small and large pool headers are identical except that the latter's + * link pointer must be FAR on 80x86 machines. + * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE + * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple + * of the alignment requirement of ALIGN_TYPE. + */ + +typedef union small_pool_struct * small_pool_ptr; + +typedef union small_pool_struct { + struct { + small_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} small_pool_hdr; + +typedef union large_pool_struct FAR * large_pool_ptr; + +typedef union large_pool_struct { + struct { + large_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} large_pool_hdr; + + +/* + * Here is the full definition of a memory manager object. + */ + +typedef struct { + struct jpeg_memory_mgr pub; /* public fields */ + + /* Each pool identifier (lifetime class) names a linked list of pools. */ + small_pool_ptr small_list[JPOOL_NUMPOOLS]; + large_pool_ptr large_list[JPOOL_NUMPOOLS]; + + /* Since we only have one lifetime class of virtual arrays, only one + * linked list is necessary (for each datatype). Note that the virtual + * array control blocks being linked together are actually stored somewhere + * in the small-pool list. + */ + jvirt_sarray_ptr virt_sarray_list; + jvirt_barray_ptr virt_barray_list; + + /* This counts total space obtained from jpeg_get_small/large */ + long total_space_allocated; + + /* alloc_sarray and alloc_barray set this value for use by virtual + * array routines. + */ + JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */ +} my_memory_mgr; + +typedef my_memory_mgr * my_mem_ptr; + + +/* + * The control blocks for virtual arrays. + * Note that these blocks are allocated in the "small" pool area. + * System-dependent info for the associated backing store (if any) is hidden + * inside the backing_store_info struct. + */ + +struct jvirt_sarray_control { + JSAMPARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION samplesperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_sarray_ptr next; /* link to next virtual sarray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + +struct jvirt_barray_control { + JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_barray_ptr next; /* link to next virtual barray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + + +#ifdef MEM_STATS /* optional extra stuff for statistics */ + +LOCAL void +print_mem_stats (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + + /* Since this is only a debugging stub, we can cheat a little by using + * fprintf directly rather than going through the trace message code. + * This is helpful because message parm array can't handle longs. + */ + fprintf(stderr, "Freeing pool %d, total space = %ld\n", + pool_id, mem->total_space_allocated); + + for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL; + lhdr_ptr = lhdr_ptr->hdr.next) { + fprintf(stderr, " Large chunk used %ld\n", + (long) lhdr_ptr->hdr.bytes_used); + } + + for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL; + shdr_ptr = shdr_ptr->hdr.next) { + fprintf(stderr, " Small chunk used %ld free %ld\n", + (long) shdr_ptr->hdr.bytes_used, + (long) shdr_ptr->hdr.bytes_left); + } +} + +#endif /* MEM_STATS */ + + +LOCAL void +out_of_memory (j_common_ptr cinfo, int which) +/* Report an out-of-memory error and stop execution */ +/* If we compiled MEM_STATS support, report alloc requests before dying */ +{ +#ifdef MEM_STATS + cinfo->err->trace_level = 2; /* force self_destruct to report stats */ +#endif + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); +} + + +/* + * Allocation of "small" objects. + * + * For these, we use pooled storage. When a new pool must be created, + * we try to get enough space for the current request plus a "slop" factor, + * where the slop will be the amount of leftover space in the new pool. + * The speed vs. space tradeoff is largely determined by the slop values. + * A different slop value is provided for each pool class (lifetime), + * and we also distinguish the first pool of a class from later ones. + * NOTE: the values given work fairly well on both 16- and 32-bit-int + * machines, but may be too small if longs are 64 bits or more. + */ + +static const size_t first_pool_slop[JPOOL_NUMPOOLS] = +{ + 1600, /* first PERMANENT pool */ + 16000 /* first IMAGE pool */ +}; + +static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = +{ + 0, /* additional PERMANENT pools */ + 5000 /* additional IMAGE pools */ +}; + +#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */ + + +METHODDEF void * +alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "small" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr hdr_ptr, prev_hdr_ptr; + char * data_ptr; + size_t odd_bytes, min_request, slop; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) + out_of_memory(cinfo, 1); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* See if space is available in any existing pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + prev_hdr_ptr = NULL; + hdr_ptr = mem->small_list[pool_id]; + while (hdr_ptr != NULL) { + if (hdr_ptr->hdr.bytes_left >= sizeofobject) + break; /* found pool with enough space */ + prev_hdr_ptr = hdr_ptr; + hdr_ptr = hdr_ptr->hdr.next; + } + + /* Time to make a new pool? */ + if (hdr_ptr == NULL) { + /* min_request is what we need now, slop is what will be leftover */ + min_request = sizeofobject + SIZEOF(small_pool_hdr); + if (prev_hdr_ptr == NULL) /* first pool in class? */ + slop = first_pool_slop[pool_id]; + else + slop = extra_pool_slop[pool_id]; + /* Don't ask for more than MAX_ALLOC_CHUNK */ + if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request)) + slop = (size_t) (MAX_ALLOC_CHUNK-min_request); + /* Try to get space, if fail reduce slop and try again */ + for (;;) { + hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop); + if (hdr_ptr != NULL) + break; + slop /= 2; + if (slop < MIN_SLOP) /* give up when it gets real small */ + out_of_memory(cinfo, 2); /* jpeg_get_small failed */ + } + mem->total_space_allocated += min_request + slop; + /* Success, initialize the new pool header and add to end of list */ + hdr_ptr->hdr.next = NULL; + hdr_ptr->hdr.bytes_used = 0; + hdr_ptr->hdr.bytes_left = sizeofobject + slop; + if (prev_hdr_ptr == NULL) /* first pool in class? */ + mem->small_list[pool_id] = hdr_ptr; + else + prev_hdr_ptr->hdr.next = hdr_ptr; + } + + /* OK, allocate the object from the current pool */ + data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */ + data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */ + hdr_ptr->hdr.bytes_used += sizeofobject; + hdr_ptr->hdr.bytes_left -= sizeofobject; + + return (void *) data_ptr; +} + + +/* + * Allocation of "large" objects. + * + * The external semantics of these are the same as "small" objects, + * except that FAR pointers are used on 80x86. However the pool + * management heuristics are quite different. We assume that each + * request is large enough that it may as well be passed directly to + * jpeg_get_large; the pool management just links everything together + * so that we can free it all on demand. + * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY + * structures. The routines that create these structures (see below) + * deliberately bunch rows together to ensure a large request size. + */ + +METHODDEF void FAR * +alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "large" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + large_pool_ptr hdr_ptr; + size_t odd_bytes; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) + out_of_memory(cinfo, 3); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* Always make a new pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject + + SIZEOF(large_pool_hdr)); + if (hdr_ptr == NULL) + out_of_memory(cinfo, 4); /* jpeg_get_large failed */ + mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr); + + /* Success, initialize the new pool header and add to list */ + hdr_ptr->hdr.next = mem->large_list[pool_id]; + /* We maintain space counts in each pool header for statistical purposes, + * even though they are not needed for allocation. + */ + hdr_ptr->hdr.bytes_used = sizeofobject; + hdr_ptr->hdr.bytes_left = 0; + mem->large_list[pool_id] = hdr_ptr; + + return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */ +} + + +/* + * Creation of 2-D sample arrays. + * The pointers are in near heap, the samples themselves in FAR heap. + * + * To minimize allocation overhead and to allow I/O of large contiguous + * blocks, we allocate the sample rows in groups of as many rows as possible + * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. + * NB: the virtual array control routines, later in this file, know about + * this chunking of rows. The rowsperchunk value is left in the mem manager + * object so that it can be saved away if this sarray is the workspace for + * a virtual array. + */ + +METHODDEF JSAMPARRAY +alloc_sarray (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +/* Allocate a 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JSAMPARRAY result; + JSAMPROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) samplesperrow * SIZEOF(JSAMPLE)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JSAMPARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JSAMPROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JSAMPROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow + * SIZEOF(JSAMPLE))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += samplesperrow; + } + } + + return result; +} + + +/* + * Creation of 2-D coefficient-block arrays. + * This is essentially the same as the code for sample arrays, above. + */ + +METHODDEF JBLOCKARRAY +alloc_barray (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, JDIMENSION numrows) +/* Allocate a 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JBLOCKARRAY result; + JBLOCKROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) blocksperrow * SIZEOF(JBLOCK)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JBLOCKARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JBLOCKROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JBLOCKROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow + * SIZEOF(JBLOCK))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += blocksperrow; + } + } + + return result; +} + + +/* + * About virtual array management: + * + * The above "normal" array routines are only used to allocate strip buffers + * (as wide as the image, but just a few rows high). Full-image-sized buffers + * are handled as "virtual" arrays. The array is still accessed a strip at a + * time, but the memory manager must save the whole array for repeated + * accesses. The intended implementation is that there is a strip buffer in + * memory (as high as is possible given the desired memory limit), plus a + * backing file that holds the rest of the array. + * + * The request_virt_array routines are told the total size of the image and + * the maximum number of rows that will be accessed at once. The in-memory + * buffer must be at least as large as the maxaccess value. + * + * The request routines create control blocks but not the in-memory buffers. + * That is postponed until realize_virt_arrays is called. At that time the + * total amount of space needed is known (approximately, anyway), so free + * memory can be divided up fairly. + * + * The access_virt_array routines are responsible for making a specific strip + * area accessible (after reading or writing the backing file, if necessary). + * Note that the access routines are told whether the caller intends to modify + * the accessed strip; during a read-only pass this saves having to rewrite + * data to disk. The access routines are also responsible for pre-zeroing + * any newly accessed rows, if pre-zeroing was requested. + * + * In current usage, the access requests are usually for nonoverlapping + * strips; that is, successive access start_row numbers differ by exactly + * num_rows = maxaccess. This means we can get good performance with simple + * buffer dump/reload logic, by making the in-memory buffer be a multiple + * of the access height; then there will never be accesses across bufferload + * boundaries. The code will still work with overlapping access requests, + * but it doesn't handle bufferload overlaps very efficiently. + */ + + +METHODDEF jvirt_sarray_ptr +request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION samplesperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_sarray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_sarray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->samplesperrow = samplesperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_sarray_list; /* add to list of virtual arrays */ + mem->virt_sarray_list = result; + + return result; +} + + +METHODDEF jvirt_barray_ptr +request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION blocksperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_barray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_barray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->blocksperrow = blocksperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_barray_list; /* add to list of virtual arrays */ + mem->virt_barray_list = result; + + return result; +} + + +METHODDEF void +realize_virt_arrays (j_common_ptr cinfo) +/* Allocate the in-memory buffers for any unrealized virtual arrays */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + long space_per_minheight, maximum_space, avail_mem; + long minheights, max_minheights; + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + /* Compute the minimum space needed (maxaccess rows in each buffer) + * and the maximum space needed (full image height in each buffer). + * These may be of use to the system-dependent jpeg_mem_available routine. + */ + space_per_minheight = 0; + maximum_space = 0; + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) sptr->maxaccess * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + maximum_space += (long) sptr->rows_in_array * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + } + } + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) bptr->maxaccess * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + maximum_space += (long) bptr->rows_in_array * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + } + } + + if (space_per_minheight <= 0) + return; /* no unrealized arrays, no work */ + + /* Determine amount of memory to actually use; this is system-dependent. */ + avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space, + mem->total_space_allocated); + + /* If the maximum space needed is available, make all the buffers full + * height; otherwise parcel it out with the same number of minheights + * in each buffer. + */ + if (avail_mem >= maximum_space) + max_minheights = 1000000000L; + else { + max_minheights = avail_mem / space_per_minheight; + /* If there doesn't seem to be enough space, try to get the minimum + * anyway. This allows a "stub" implementation of jpeg_mem_available(). + */ + if (max_minheights <= 0) + max_minheights = 1; + } + + /* Allocate the in-memory buffers and initialize backing store as needed. */ + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + sptr->rows_in_mem = sptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess); + jpeg_open_backing_store(cinfo, & sptr->b_s_info, + (long) sptr->rows_in_array * + (long) sptr->samplesperrow * + (long) SIZEOF(JSAMPLE)); + sptr->b_s_open = TRUE; + } + sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, + sptr->samplesperrow, sptr->rows_in_mem); + sptr->rowsperchunk = mem->last_rowsperchunk; + sptr->cur_start_row = 0; + sptr->first_undef_row = 0; + sptr->dirty = FALSE; + } + } + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + bptr->rows_in_mem = bptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess); + jpeg_open_backing_store(cinfo, & bptr->b_s_info, + (long) bptr->rows_in_array * + (long) bptr->blocksperrow * + (long) SIZEOF(JBLOCK)); + bptr->b_s_open = TRUE; + } + bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, + bptr->blocksperrow, bptr->rows_in_mem); + bptr->rowsperchunk = mem->last_rowsperchunk; + bptr->cur_start_row = 0; + bptr->first_undef_row = 0; + bptr->dirty = FALSE; + } + } +} + + +LOCAL void +do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual sample array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +LOCAL void +do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual coefficient-block array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +METHODDEF JSAMPARRAY +access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual sample array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_sarray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_sarray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +METHODDEF JBLOCKARRAY +access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual block array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_barray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_barray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +/* + * Release all objects belonging to a specified pool. + */ + +METHODDEF void +free_pool (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + size_t space_freed; + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + +#ifdef MEM_STATS + if (cinfo->err->trace_level > 1) + print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */ +#endif + + /* If freeing IMAGE pool, close any virtual arrays first */ + if (pool_id == JPOOL_IMAGE) { + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->b_s_open) { /* there may be no backing store */ + sptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info); + } + } + mem->virt_sarray_list = NULL; + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->b_s_open) { /* there may be no backing store */ + bptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info); + } + } + mem->virt_barray_list = NULL; + } + + /* Release large objects */ + lhdr_ptr = mem->large_list[pool_id]; + mem->large_list[pool_id] = NULL; + + while (lhdr_ptr != NULL) { + large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next; + space_freed = lhdr_ptr->hdr.bytes_used + + lhdr_ptr->hdr.bytes_left + + SIZEOF(large_pool_hdr); + jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + lhdr_ptr = next_lhdr_ptr; + } + + /* Release small objects */ + shdr_ptr = mem->small_list[pool_id]; + mem->small_list[pool_id] = NULL; + + while (shdr_ptr != NULL) { + small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next; + space_freed = shdr_ptr->hdr.bytes_used + + shdr_ptr->hdr.bytes_left + + SIZEOF(small_pool_hdr); + jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + shdr_ptr = next_shdr_ptr; + } +} + + +/* + * Close up shop entirely. + * Note that this cannot be called unless cinfo->mem is non-NULL. + */ + +METHODDEF void +self_destruct (j_common_ptr cinfo) +{ + int pool; + + /* Close all backing store, release all memory. + * Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + free_pool(cinfo, pool); + } + + /* Release the memory manager control block too. */ + jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr)); + cinfo->mem = NULL; /* ensures I will be called only once */ + + jpeg_mem_term(cinfo); /* system-dependent cleanup */ +} + + +/* + * Memory manager initialization. + * When this is called, only the error manager pointer is valid in cinfo! + */ + +GLOBAL void +jinit_memory_mgr (j_common_ptr cinfo) +{ + my_mem_ptr mem; + long max_to_use; + int pool; + size_t test_mac; + + cinfo->mem = NULL; /* for safety if init fails */ + + /* Check for configuration errors. + * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably + * doesn't reflect any real hardware alignment requirement. + * The test is a little tricky: for X>0, X and X-1 have no one-bits + * in common if and only if X is a power of 2, ie has only one one-bit. + * Some compilers may give an "unreachable code" warning here; ignore it. + */ + if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0) + ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); + /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be + * a multiple of SIZEOF(ALIGN_TYPE). + * Again, an "unreachable code" warning may be ignored here. + * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. + */ + test_mac = (size_t) MAX_ALLOC_CHUNK; + if ((long) test_mac != MAX_ALLOC_CHUNK || + (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0) + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + + max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */ + + /* Attempt to allocate memory manager's control block */ + mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)); + + if (mem == NULL) { + jpeg_mem_term(cinfo); /* system-dependent cleanup */ + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); + } + + /* OK, fill in the method pointers */ + mem->pub.alloc_small = alloc_small; + mem->pub.alloc_large = alloc_large; + mem->pub.alloc_sarray = alloc_sarray; + mem->pub.alloc_barray = alloc_barray; + mem->pub.request_virt_sarray = request_virt_sarray; + mem->pub.request_virt_barray = request_virt_barray; + mem->pub.realize_virt_arrays = realize_virt_arrays; + mem->pub.access_virt_sarray = access_virt_sarray; + mem->pub.access_virt_barray = access_virt_barray; + mem->pub.free_pool = free_pool; + mem->pub.self_destruct = self_destruct; + + /* Initialize working state */ + mem->pub.max_memory_to_use = max_to_use; + + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + mem->small_list[pool] = NULL; + mem->large_list[pool] = NULL; + } + mem->virt_sarray_list = NULL; + mem->virt_barray_list = NULL; + + mem->total_space_allocated = SIZEOF(my_memory_mgr); + + /* Declare ourselves open for business */ + cinfo->mem = & mem->pub; + + /* Check for an environment variable JPEGMEM; if found, override the + * default max_memory setting from jpeg_mem_init. Note that the + * surrounding application may again override this value. + * If your system doesn't support getenv(), define NO_GETENV to disable + * this feature. + */ +#ifndef NO_GETENV + { char * memenv; + + if ((memenv = getenv("JPEGMEM")) != NULL) { + char ch = 'x'; + + if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { + if (ch == 'm' || ch == 'M') + max_to_use *= 1000L; + mem->pub.max_memory_to_use = max_to_use * 1000L; + } + } + } +#endif + +} diff --git a/engine/jpeg-6/jmemname.c b/engine/jpeg-6/jmemname.c new file mode 100644 index 0000000..ba826fb --- /dev/null +++ b/engine/jpeg-6/jmemname.c @@ -0,0 +1,271 @@ +/* + * jmemname.c + * + * Copyright (C) 1992-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a generic implementation of the system-dependent + * portion of the JPEG memory manager. This implementation assumes that + * you must explicitly construct a name for each temp file. + * Also, the problem of determining the amount of memory available + * is shoved onto the user. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + +#ifndef SEEK_SET /* pre-ANSI systems may not define this; */ +#define SEEK_SET 0 /* if not, assume 0 is correct */ +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define RW_BINARY "w+" +#else +#define READ_BINARY "rb" +#define RW_BINARY "w+b" +#endif + + +/* + * Selection of a file name for a temporary file. + * This is system-dependent! + * + * The code as given is suitable for most Unix systems, and it is easily + * modified for most non-Unix systems. Some notes: + * 1. The temp file is created in the directory named by TEMP_DIRECTORY. + * The default value is /usr/tmp, which is the conventional place for + * creating large temp files on Unix. On other systems you'll probably + * want to change the file location. You can do this by editing the + * #define, or (preferred) by defining TEMP_DIRECTORY in jconfig.h. + * + * 2. If you need to change the file name as well as its location, + * you can override the TEMP_FILE_NAME macro. (Note that this is + * actually a printf format string; it must contain %s and %d.) + * Few people should need to do this. + * + * 3. mktemp() is used to ensure that multiple processes running + * simultaneously won't select the same file names. If your system + * doesn't have mktemp(), define NO_MKTEMP to do it the hard way. + * (If you don't have , also define NO_ERRNO_H.) + * + * 4. You probably want to define NEED_SIGNAL_CATCHER so that cjpeg.c/djpeg.c + * will cause the temp files to be removed if you stop the program early. + */ + +#ifndef TEMP_DIRECTORY /* can override from jconfig.h or Makefile */ +#define TEMP_DIRECTORY "/usr/tmp/" /* recommended setting for Unix */ +#endif + +static int next_file_num; /* to distinguish among several temp files */ + +#ifdef NO_MKTEMP + +#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */ +#define TEMP_FILE_NAME "%sJPG%03d.TMP" +#endif + +#ifndef NO_ERRNO_H +#include /* to define ENOENT */ +#endif + +/* ANSI C specifies that errno is a macro, but on older systems it's more + * likely to be a plain int variable. And not all versions of errno.h + * bother to declare it, so we have to in order to be most portable. Thus: + */ +#ifndef errno +extern int errno; +#endif + + +LOCAL void +select_file_name (char * fname) +{ + FILE * tfile; + + /* Keep generating file names till we find one that's not in use */ + for (;;) { + next_file_num++; /* advance counter */ + sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num); + if ((tfile = fopen(fname, READ_BINARY)) == NULL) { + /* fopen could have failed for a reason other than the file not + * being there; for example, file there but unreadable. + * If isn't available, then we cannot test the cause. + */ +#ifdef ENOENT + if (errno != ENOENT) + continue; +#endif + break; + } + fclose(tfile); /* oops, it's there; close tfile & try again */ + } +} + +#else /* ! NO_MKTEMP */ + +/* Note that mktemp() requires the initial filename to end in six X's */ +#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */ +#define TEMP_FILE_NAME "%sJPG%dXXXXXX" +#endif + +LOCAL void +select_file_name (char * fname) +{ + next_file_num++; /* advance counter */ + sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num); + mktemp(fname); /* make sure file name is unique */ + /* mktemp replaces the trailing XXXXXX with a unique string of characters */ +} + +#endif /* NO_MKTEMP */ + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL void * +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL void +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL void FAR * +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL void +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * It's impossible to do this in a portable way; our current solution is + * to make the user tell us (with a default value set at compile time). + * If you can actually get the available space, it's a good idea to subtract + * a slop factor of 5% or so. + */ + +#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ +#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */ +#endif + +GLOBAL long +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return cinfo->mem->max_memory_to_use - already_allocated; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + + +METHODDEF void +read_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFREAD(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF void +write_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFWRITE(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF void +close_backing_store (j_common_ptr cinfo, backing_store_ptr info) +{ + fclose(info->temp_file); /* close the file */ + unlink(info->temp_name); /* delete the file */ +/* If your system doesn't have unlink(), use remove() instead. + * remove() is the ANSI-standard name for this function, but if + * your system was ANSI you'd be using jmemansi.c, right? + */ + TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name); +} + + +/* + * Initial opening of a backing-store object. + */ + +GLOBAL void +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + select_file_name(info->temp_name); + if ((info->temp_file = fopen(info->temp_name, RW_BINARY)) == NULL) + ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name); + info->read_backing_store = read_backing_store; + info->write_backing_store = write_backing_store; + info->close_backing_store = close_backing_store; + TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL long +jpeg_mem_init (j_common_ptr cinfo) +{ + next_file_num = 0; /* initialize temp file name generator */ + return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ +} + +GLOBAL void +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/engine/jpeg-6/jmemnobs.c b/engine/jpeg-6/jmemnobs.c new file mode 100644 index 0000000..9ca2fb7 --- /dev/null +++ b/engine/jpeg-6/jmemnobs.c @@ -0,0 +1,106 @@ +/* + * jmemnobs.c + * + * Copyright (C) 1992-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a really simple implementation of the system- + * dependent portion of the JPEG memory manager. This implementation + * assumes that no backing-store files are needed: all required space + * can be obtained from ri.Malloc(). + * This is very portable in the sense that it'll compile on almost anything, + * but you'd better have lots of main memory (or virtual memory) if you want + * to process big images. + * Note that the max_memory_to_use option is ignored by this implementation. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +//#include "../renderer/tr_local.h" +#include "../code/quakedef.h" + +/* + * Memory allocation and ri.Freeing are controlled by the regular library + * routines ri.Malloc() and ri.Free(). + */ + +GLOBAL void * +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL void +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL void FAR * +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL void +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * Here we always say, "we got all you want bud!" + */ + +GLOBAL long +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return max_bytes_needed; +} + + +/* + * Backing store (temporary file) management. + * Since jpeg_mem_available always promised the moon, + * this should never be called and we can just error out. + */ + +GLOBAL void +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + ERREXIT(cinfo, JERR_NO_BACKING_STORE); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. Here, there isn't any. + */ + +GLOBAL long +jpeg_mem_init (j_common_ptr cinfo) +{ + return 0; /* just set max_memory_to_use to 0 */ +} + +GLOBAL void +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/engine/jpeg-6/jmemsys.h b/engine/jpeg-6/jmemsys.h new file mode 100644 index 0000000..033d29a --- /dev/null +++ b/engine/jpeg-6/jmemsys.h @@ -0,0 +1,182 @@ +/* + * jmemsys.h + * + * Copyright (C) 1992-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file defines the interface between the system-independent + * and system-dependent portions of the JPEG memory manager. No other + * modules need include it. (The system-independent portion is jmemmgr.c; + * there are several different versions of the system-dependent portion.) + * + * This file works as-is for the system-dependent memory managers supplied + * in the IJG distribution. You may need to modify it if you write a + * custom memory manager. If system-dependent changes are needed in + * this file, the best method is to #ifdef them based on a configuration + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_get_small jGetSmall +#define jpeg_free_small jFreeSmall +#define jpeg_get_large jGetLarge +#define jpeg_free_large jFreeLarge +#define jpeg_mem_available jMemAvail +#define jpeg_open_backing_store jOpenBackStore +#define jpeg_mem_init jMemInit +#define jpeg_mem_term jMemTerm +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * These two functions are used to allocate and release small chunks of + * memory. (Typically the total amount requested through jpeg_get_small is + * no more than 20K or so; this will be requested in chunks of a few K each.) + * Behavior should be the same as for the standard library functions malloc + * and free; in particular, jpeg_get_small must return NULL on failure. + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + * size of the object being freed, just in case it's needed. + * On an 80x86 machine using small-data memory model, these manage near heap. + */ + +EXTERN void * jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); +EXTERN void jpeg_free_small JPP((j_common_ptr cinfo, void * object, + size_t sizeofobject)); + +/* + * These two functions are used to allocate and release large chunks of + * memory (up to the total free space designated by jpeg_mem_available). + * The interface is the same as above, except that on an 80x86 machine, + * far pointers are used. On most other machines these are identical to + * the jpeg_get/free_small routines; but we keep them separate anyway, + * in case a different allocation strategy is desirable for large chunks. + */ + +EXTERN void FAR * jpeg_get_large JPP((j_common_ptr cinfo,size_t sizeofobject)); +EXTERN void jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + size_t sizeofobject)); + +/* + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + * matter, but that case should never come into play). This macro is needed + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + * On those machines, we expect that jconfig.h will provide a proper value. + * On machines with 32-bit flat address spaces, any large constant may be used. + * + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + * size_t and will be a multiple of sizeof(align_type). + */ + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ +#define MAX_ALLOC_CHUNK 1000000000L +#endif + +/* + * This routine computes the total space still available for allocation by + * jpeg_get_large. If more space than this is needed, backing store will be + * used. NOTE: any memory already allocated must not be counted. + * + * There is a minimum space requirement, corresponding to the minimum + * feasible buffer sizes; jmemmgr.c will request that much space even if + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + * all working storage in memory, is also passed in case it is useful. + * Finally, the total space already allocated is passed. If no better + * method is available, cinfo->mem->max_memory_to_use - already_allocated + * is often a suitable calculation. + * + * It is OK for jpeg_mem_available to underestimate the space available + * (that'll just lead to more backing-store access than is really necessary). + * However, an overestimate will lead to failure. Hence it's wise to subtract + * a slop factor from the true available space. 5% should be enough. + * + * On machines with lots of virtual memory, any large constant may be returned. + * Conversely, zero may be returned to always use the minimum amount of memory. + */ + +EXTERN long jpeg_mem_available JPP((j_common_ptr cinfo, + long min_bytes_needed, + long max_bytes_needed, + long already_allocated)); + + +/* + * This structure holds whatever state is needed to access a single + * backing-store object. The read/write/close method pointers are called + * by jmemmgr.c to manipulate the backing-store object; all other fields + * are private to the system-dependent backing store routines. + */ + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + +typedef unsigned short XMSH; /* type of extended-memory handles */ +typedef unsigned short EMSH; /* type of expanded-memory handles */ + +typedef union { + short file_handle; /* DOS file handle if it's a temp file */ + XMSH xms_handle; /* handle if it's a chunk of XMS */ + EMSH ems_handle; /* handle if it's a chunk of EMS */ +} handle_union; + +#endif /* USE_MSDOS_MEMMGR */ + +typedef struct backing_store_struct * backing_store_ptr; + +typedef struct backing_store_struct { + /* Methods for reading/writing/closing this backing-store object */ + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + backing_store_ptr info)); + + /* Private fields for system-dependent backing-store management */ +#ifdef USE_MSDOS_MEMMGR + /* For the MS-DOS manager (jmemdos.c), we need: */ + handle_union handle; /* reference to backing-store storage object */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else + /* For a typical implementation with temp files, we need: */ + FILE * temp_file; /* stdio reference to temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ +#endif +} backing_store_info; + +/* + * Initial opening of a backing-store object. This must fill in the + * read/write/close pointers in the object. The read/write routines + * may take an error exit if the specified maximum file size is exceeded. + * (If jpeg_mem_available always returns a large value, this routine can + * just take an error exit.) + */ + +EXTERN void jpeg_open_backing_store JPP((j_common_ptr cinfo, + backing_store_ptr info, + long total_bytes_needed)); + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. jpeg_mem_init will be called before anything is + * allocated (and, therefore, nothing in cinfo is of use except the error + * manager pointer). It should return a suitable default value for + * max_memory_to_use; this may subsequently be overridden by the surrounding + * application. (Note that max_memory_to_use is only important if + * jpeg_mem_available chooses to consult it ... no one else will.) + * jpeg_mem_term may assume that all requested memory has been freed and that + * all opened backing-store objects have been closed. + */ + +EXTERN long jpeg_mem_init JPP((j_common_ptr cinfo)); +EXTERN void jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/engine/jpeg-6/jmorecfg.h b/engine/jpeg-6/jmorecfg.h new file mode 100644 index 0000000..1fc0a19 --- /dev/null +++ b/engine/jpeg-6/jmorecfg.h @@ -0,0 +1,348 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +typedef long INT32; + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +//#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +//typedef long INT32; +//#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These defines are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +#define METHODDEF static /* a function called through method pointers */ +#define LOCAL static /* a function used only in its module */ +#define GLOBAL /* a function referenced thru EXTERNs */ +#define EXTERN extern /* a reference to a GLOBAL function */ + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#undef FAR +#define FAR far +#else +#undef FAR +#define FAR +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +//#ifndef HAVE_BOOLEAN +//typedef int boolean; +//#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + +/* Capability options common to encoder and decoder: */ + +#undef DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#undef DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#undef D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#undef D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#undef BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#undef IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#undef UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#undef QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#undef QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 4 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/engine/jpeg-6/jpegint.h b/engine/jpeg-6/jpegint.h new file mode 100644 index 0000000..ab5bee2 --- /dev/null +++ b/engine/jpeg-6/jpegint.h @@ -0,0 +1,388 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean call_pass_startup; /* True if pass_startup must be called */ + boolean is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_c_coef_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Forward DCT (also controls coefficient quantization) */ +struct jpeg_forward_dct { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + /* perhaps this should be an array??? */ + JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, + jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks)); +}; + +/* Entropy encoding */ +struct jpeg_entropy_encoder { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); + JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); +}; + +/* Marker writing */ +struct jpeg_marker_writer { + /* write_any_marker is exported for use by applications */ + /* Probably only COM and APPn markers should be written */ + JMETHOD(void, write_any_marker, (j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen)); + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean has_multiple_scans; /* True if file has multiple scans */ + boolean eoi_reached; /* True when EOI has been consumed */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_d_coef_controller { + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + /* Application-overridable marker processing methods */ + jpeg_marker_parser_method process_COM; + jpeg_marker_parser_method process_APPn[16]; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + boolean saw_SOI; /* found SOI? */ + boolean saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ +}; + +/* Entropy decoding */ +struct jpeg_entropy_decoder { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +}; + +/* Inverse DCT (also performs dequantization) */ +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +struct jpeg_inverse_dct { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_huff_encoder jIHEncoder +#define jinit_phuff_encoder jIPHEncoder +#define jinit_marker_writer jIMWriter +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_huff_decoder jIHDecoder +#define jinit_phuff_decoder jIPHDecoder +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jzero_far jZeroFar +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Compression module initialization routines */ +EXTERN void jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN void jinit_c_master_control JPP((j_compress_ptr cinfo, + boolean transcode_only)); +EXTERN void jinit_c_main_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN void jinit_c_prep_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN void jinit_c_coef_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN void jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN void jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN void jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN void jinit_huff_encoder JPP((j_compress_ptr cinfo)); +EXTERN void jinit_phuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN void jinit_marker_writer JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN void jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN void jinit_d_main_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN void jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN void jinit_d_post_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN void jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN void jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN void jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN void jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN void jinit_inverse_dct JPP((j_decompress_ptr cinfo)); +EXTERN void jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN void jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN void jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN void jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN void jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +/* Memory manager initialization */ +EXTERN void jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN long jdiv_round_up JPP((long a, long b)); +EXTERN long jround_up JPP((long a, long b)); +EXTERN void jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols)); +EXTERN void jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +EXTERN void jzero_far JPP((void FAR * target, size_t bytestozero)); +/* Constant tables in jutils.c */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/engine/jpeg-6/jpeglib.h b/engine/jpeg-6/jpeglib.h new file mode 100644 index 0000000..edfdda1 --- /dev/null +++ b/engine/jpeg-6/jpeglib.h @@ -0,0 +1,1051 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +typedef unsigned char boolean; +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "../jpeg-6/jconfig.h" /* widely used configuration options */ +#endif +#include "../jpeg-6/jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 60 /* Version 6 */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This field directly represents the contents of a JPEG DQT marker. + * Note: the values are always given in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is not currently used by the compressor. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + boolean is_decompressor; /* so common code can tell which is which */\ + int global_state /* for checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker: */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_create_compress jCreaCompress +#define jpeg_create_decompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN struct jpeg_error_mgr *jpeg_std_error JPP((struct jpeg_error_mgr *err)); + +/* Initialization and destruction of JPEG compression objects */ +/* NB: you must set up the error-manager BEFORE calling jpeg_create_xxx */ +EXTERN void jpeg_create_compress JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_create_decompress JPP((j_decompress_ptr cinfo)); +EXTERN void jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN void jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN void jpeg_stdio_src JPP((j_decompress_ptr cinfo, unsigned char *infile)); + +/* Default parameter setup for compression */ +EXTERN void jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN void jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN void jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN void jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN void jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN int jpeg_quality_scaling JPP((int quality)); +EXTERN void jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN JQUANT_TBL * jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN JHUFF_TBL * jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN void jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN JDIMENSION jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN void jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN JDIMENSION jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN void jpeg_write_marker JPP((j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN void jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN int jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN boolean jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN JDIMENSION jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN boolean jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN JDIMENSION jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN boolean jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN boolean jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN boolean jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN boolean jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN void jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN int jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN void jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN void jpeg_set_marker_processor JPP((j_decompress_ptr cinfo, + int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN jvirt_barray_ptr * jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN void jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN void jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN void jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN void jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN void jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN boolean jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "../jpeg-6/jpegint.h" /* fetch private declarations */ +#include "../jpeg-6/jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/engine/jpeg-6/jpegtran.c b/engine/jpeg-6/jpegtran.c new file mode 100644 index 0000000..f602c6b --- /dev/null +++ b/engine/jpeg-6/jpegtran.c @@ -0,0 +1,370 @@ +/* + * jpegtran.c + * + * Copyright (C) 1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a command-line user interface for JPEG transcoding. + * It is very similar to cjpeg.c, but provides lossless transcoding between + * different JPEG file formats. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include "jversion.h" /* for version message */ + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks declares it here */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + + +/* + * Argument-parsing code. + * The switch parser is designed to be useful with DOS-style command line + * syntax, ie, intermixed switches and file names, where only the switches + * to the left of a given file name affect processing of that file. + * The main program in this file doesn't actually use this capability... + */ + + +static const char * progname; /* program name for error messages */ +static char * outfilename; /* for -outfile switch */ + + +LOCAL void +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s [switches] ", progname); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, "inputfile outputfile\n"); +#else + fprintf(stderr, "[inputfile]\n"); +#endif + + fprintf(stderr, "Switches (names may be abbreviated):\n"); +#ifdef ENTROPY_OPT_SUPPORTED + fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n"); +#endif +#ifdef C_PROGRESSIVE_SUPPORTED + fprintf(stderr, " -progressive Create progressive JPEG file\n"); +#endif + fprintf(stderr, "Switches for advanced users:\n"); + fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n"); + fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n"); + fprintf(stderr, " -outfile name Specify name for output file\n"); + fprintf(stderr, " -verbose or -debug Emit debug output\n"); + fprintf(stderr, "Switches for wizards:\n"); +#ifdef C_ARITH_CODING_SUPPORTED + fprintf(stderr, " -arithmetic Use arithmetic coding\n"); +#endif +#ifdef C_MULTISCAN_FILES_SUPPORTED + fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n"); +#endif + exit(EXIT_FAILURE); +} + + +LOCAL int +parse_switches (j_compress_ptr cinfo, int argc, char **argv, + int last_file_arg_seen, boolean for_real) +/* Parse optional switches. + * Returns argv[] index of first file-name argument (== argc if none). + * Any file names with indexes <= last_file_arg_seen are ignored; + * they have presumably been processed in a previous iteration. + * (Pass 0 for last_file_arg_seen on the first or only iteration.) + * for_real is FALSE on the first (dummy) pass; we may skip any expensive + * processing. + */ +{ + int argn; + char * arg; + boolean simple_progressive; + char * scansarg = NULL; /* saves -scans parm if any */ + + /* Set up default JPEG parameters. */ + simple_progressive = FALSE; + outfilename = NULL; + cinfo->err->trace_level = 0; + + /* Scan command line options, adjust parameters */ + + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (*arg != '-') { + /* Not a switch, must be a file name argument */ + if (argn <= last_file_arg_seen) { + outfilename = NULL; /* -outfile applies to just one input file */ + continue; /* ignore this name if previously processed */ + } + break; /* else done parsing switches */ + } + arg++; /* advance past switch marker character */ + + if (keymatch(arg, "arithmetic", 1)) { + /* Use arithmetic coding. */ +#ifdef C_ARITH_CODING_SUPPORTED + cinfo->arith_code = TRUE; +#else + fprintf(stderr, "%s: sorry, arithmetic coding not supported\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { + /* Enable debug printouts. */ + /* On first -d, print version identification */ + static boolean printed_version = FALSE; + + if (! printed_version) { + fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n", + JVERSION, JCOPYRIGHT); + printed_version = TRUE; + } + cinfo->err->trace_level++; + + } else if (keymatch(arg, "maxmemory", 3)) { + /* Maximum memory in Kb (or Mb with 'm'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (ch == 'm' || ch == 'M') + lval *= 1000L; + cinfo->mem->max_memory_to_use = lval * 1000L; + + } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) { + /* Enable entropy parm optimization. */ +#ifdef ENTROPY_OPT_SUPPORTED + cinfo->optimize_coding = TRUE; +#else + fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "outfile", 4)) { + /* Set output file name. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + outfilename = argv[argn]; /* save it away for later use */ + + } else if (keymatch(arg, "progressive", 1)) { + /* Select simple progressive mode. */ +#ifdef C_PROGRESSIVE_SUPPORTED + simple_progressive = TRUE; + /* We must postpone execution until num_components is known. */ +#else + fprintf(stderr, "%s: sorry, progressive output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "restart", 1)) { + /* Restart interval in MCU rows (or in MCUs with 'b'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (lval < 0 || lval > 65535L) + usage(); + if (ch == 'b' || ch == 'B') { + cinfo->restart_interval = (unsigned int) lval; + cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */ + } else { + cinfo->restart_in_rows = (int) lval; + /* restart_interval will be computed during startup */ + } + + } else if (keymatch(arg, "scans", 2)) { + /* Set scan script. */ +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (++argn >= argc) /* advance to next argument */ + usage(); + scansarg = argv[argn]; + /* We must postpone reading the file in case -progressive appears. */ +#else + fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else { + usage(); /* bogus switch */ + } + } + + /* Post-switch-scanning cleanup */ + + if (for_real) { + +#ifdef C_PROGRESSIVE_SUPPORTED + if (simple_progressive) /* process -progressive; -scans can override */ + jpeg_simple_progression(cinfo); +#endif + +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (scansarg != NULL) /* process -scans if it was present */ + if (! read_scan_script(cinfo, scansarg)) + usage(); +#endif + } + + return argn; /* return index of next arg (file name) */ +} + + +/* + * The main program. + */ + +GLOBAL int +main (int argc, char **argv) +{ + struct jpeg_decompress_struct srcinfo; + struct jpeg_compress_struct dstinfo; + struct jpeg_error_mgr jsrcerr, jdsterr; +#ifdef PROGRESS_REPORT + struct cdjpeg_progress_mgr progress; +#endif + jvirt_barray_ptr * coef_arrays; + int file_index; + FILE * input_file; + FILE * output_file; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "jpegtran"; /* in case C library doesn't provide it */ + + /* Initialize the JPEG decompression object with default error handling. */ + srcinfo.err = jpeg_std_error(&jsrcerr); + jpeg_create_decompress(&srcinfo); + /* Initialize the JPEG compression object with default error handling. */ + dstinfo.err = jpeg_std_error(&jdsterr); + jpeg_create_compress(&dstinfo); + + /* Now safe to enable signal catcher. + * Note: we assume only the decompression object will have virtual arrays. + */ +#ifdef NEED_SIGNAL_CATCHER + enable_signal_catcher((j_common_ptr) &srcinfo); +#endif + + /* Scan command line to find file names. + * It is convenient to use just one switch-parsing routine, but the switch + * values read here are ignored; we will rescan the switches after opening + * the input file. + */ + + file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE); + jsrcerr.trace_level = jdsterr.trace_level; + +#ifdef TWO_FILE_COMMANDLINE + /* Must have either -outfile switch or explicit output file name */ + if (outfilename == NULL) { + if (file_index != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + outfilename = argv[file_index+1]; + } else { + if (file_index != argc-1) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + } +#else + /* Unix style: expect zero or one file name */ + if (file_index < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } +#endif /* TWO_FILE_COMMANDLINE */ + + /* Open the input file. */ + if (file_index < argc) { + if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ + input_file = read_stdin(); + } + + /* Open the output file. */ + if (outfilename != NULL) { + if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, outfilename); + exit(EXIT_FAILURE); + } + } else { + /* default output file is stdout */ + output_file = write_stdout(); + } + +#ifdef PROGRESS_REPORT + start_progress_monitor((j_common_ptr) &dstinfo, &progress); +#endif + + /* Specify data source for decompression */ + jpeg_stdio_src(&srcinfo, input_file); + + /* Read file header */ + (void) jpeg_read_header(&srcinfo, TRUE); + + /* Read source file as DCT coefficients */ + coef_arrays = jpeg_read_coefficients(&srcinfo); + + /* Initialize destination compression parameters from source values */ + jpeg_copy_critical_parameters(&srcinfo, &dstinfo); + + /* Adjust default compression parameters by re-parsing the options */ + file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); + + /* Specify data destination for compression */ + jpeg_stdio_dest(&dstinfo, output_file); + + /* Start compressor */ + jpeg_write_coefficients(&dstinfo, coef_arrays); + + /* ought to copy source comments here... */ + + /* Finish compression and release memory */ + jpeg_finish_compress(&dstinfo); + jpeg_destroy_compress(&dstinfo); + (void) jpeg_finish_decompress(&srcinfo); + jpeg_destroy_decompress(&srcinfo); + + /* Close files, if we opened them */ + if (input_file != stdin) + fclose(input_file); + if (output_file != stdout) + fclose(output_file); + +#ifdef PROGRESS_REPORT + end_progress_monitor((j_common_ptr) &dstinfo); +#endif + + /* All done. */ + exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/engine/jpeg-6/jquant1.c b/engine/jpeg-6/jquant1.c new file mode 100644 index 0000000..035e79a --- /dev/null +++ b/engine/jpeg-6/jquant1.c @@ -0,0 +1,856 @@ +/* + * jquant1.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 1-pass color quantization (color mapping) routines. + * These routines provide mapping to a fixed color map using equally spaced + * color values. Optional Floyd-Steinberg or ordered dithering is available. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_1PASS_SUPPORTED + + +/* + * The main purpose of 1-pass quantization is to provide a fast, if not very + * high quality, colormapped output capability. A 2-pass quantizer usually + * gives better visual quality; however, for quantized grayscale output this + * quantizer is perfectly adequate. Dithering is highly recommended with this + * quantizer, though you can turn it off if you really want to. + * + * In 1-pass quantization the colormap must be chosen in advance of seeing the + * image. We use a map consisting of all combinations of Ncolors[i] color + * values for the i'th component. The Ncolors[] values are chosen so that + * their product, the total number of colors, is no more than that requested. + * (In most cases, the product will be somewhat less.) + * + * Since the colormap is orthogonal, the representative value for each color + * component can be determined without considering the other components; + * then these indexes can be combined into a colormap index by a standard + * N-dimensional-array-subscript calculation. Most of the arithmetic involved + * can be precalculated and stored in the lookup table colorindex[]. + * colorindex[i][j] maps pixel value j in component i to the nearest + * representative value (grid plane) for that component; this index is + * multiplied by the array stride for component i, so that the + * index of the colormap entry closest to a given pixel value is just + * sum( colorindex[component-number][pixel-component-value] ) + * Aside from being fast, this scheme allows for variable spacing between + * representative values with no additional lookup cost. + * + * If gamma correction has been applied in color conversion, it might be wise + * to adjust the color grid spacing so that the representative colors are + * equidistant in linear space. At this writing, gamma correction is not + * implemented by jdcolor, so nothing is done here. + */ + + +/* Declarations for ordered dithering. + * + * We use a standard 16x16 ordered dither array. The basic concept of ordered + * dithering is described in many references, for instance Dale Schumacher's + * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991). + * In place of Schumacher's comparisons against a "threshold" value, we add a + * "dither" value to the input pixel and then round the result to the nearest + * output value. The dither value is equivalent to (0.5 - threshold) times + * the distance between output values. For ordered dithering, we assume that + * the output colors are equally spaced; if not, results will probably be + * worse, since the dither may be too much or too little at a given point. + * + * The normal calculation would be to form pixel value + dither, range-limit + * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual. + * We can skip the separate range-limiting step by extending the colorindex + * table in both directions. + */ + +#define ODITHER_SIZE 16 /* dimension of dither matrix */ +/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */ +#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */ +#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */ + +typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE]; +typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE]; + +static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = { + /* Bayer's order-4 dither array. Generated by the code given in + * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I. + * The values in this array must range from 0 to ODITHER_CELLS-1. + */ + { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, + { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, + { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, + { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, + { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, + { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, + { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, + { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, + { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, + { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, + { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, + { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, + { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, + { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, + { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, + { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } +}; + + +/* Declarations for Floyd-Steinberg dithering. + * + * Errors are accumulated into the array fserrors[], at a resolution of + * 1/16th of a pixel count. The error at a given pixel is propagated + * to its not-yet-processed neighbors using the standard F-S fractions, + * ... (here) 7/16 + * 3/16 5/16 1/16 + * We work left-to-right on even rows, right-to-left on odd rows. + * + * We can get away with a single array (holding one row's worth of errors) + * by using it to store the current row's errors at pixel columns not yet + * processed, but the next row's errors at columns already processed. We + * need only a few extra variables to hold the errors immediately around the + * current column. (If we are lucky, those variables are in registers, but + * even if not, they're probably cheaper to access than array elements are.) + * + * The fserrors[] array is indexed [component#][position]. + * We provide (#columns + 2) entries per component; the extra entry at each + * end saves us from special-casing the first and last pixels. + * + * Note: on a wide image, we might not have enough room in a PC's near data + * segment to hold the error array; so it is allocated with alloc_large. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef INT16 FSERROR; /* 16 bits should be enough */ +typedef int LOCFSERROR; /* use 'int' for calculation temps */ +#else +typedef INT32 FSERROR; /* may need more than 16 bits */ +typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */ +#endif + +typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ + + +/* Private subobject */ + +#define MAX_Q_COMPS 4 /* max components I can handle */ + +typedef struct { + struct jpeg_color_quantizer pub; /* public fields */ + + /* Initially allocated colormap is saved here */ + JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */ + int sv_actual; /* number of entries in use */ + + JSAMPARRAY colorindex; /* Precomputed mapping for speed */ + /* colorindex[i][j] = index of color closest to pixel value j in component i, + * premultiplied as described above. Since colormap indexes must fit into + * JSAMPLEs, the entries of this array will too. + */ + boolean is_padded; /* is the colorindex padded for odither? */ + + int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */ + + /* Variables for ordered dithering */ + int row_index; /* cur row's vertical index in dither matrix */ + ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */ + + /* Variables for Floyd-Steinberg dithering */ + FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */ + boolean on_odd_row; /* flag to remember which row we are on */ +} my_cquantizer; + +typedef my_cquantizer * my_cquantize_ptr; + + +/* + * Policy-making subroutines for create_colormap and create_colorindex. + * These routines determine the colormap to be used. The rest of the module + * only assumes that the colormap is orthogonal. + * + * * select_ncolors decides how to divvy up the available colors + * among the components. + * * output_value defines the set of representative values for a component. + * * largest_input_value defines the mapping from input values to + * representative values for a component. + * Note that the latter two routines may impose different policies for + * different components, though this is not currently done. + */ + + +LOCAL int +select_ncolors (j_decompress_ptr cinfo, int Ncolors[]) +/* Determine allocation of desired colors to components, */ +/* and fill in Ncolors[] array to indicate choice. */ +/* Return value is total number of colors (product of Ncolors[] values). */ +{ + int nc = cinfo->out_color_components; /* number of color components */ + int max_colors = cinfo->desired_number_of_colors; + int total_colors, iroot, i, j; + boolean changed; + long temp; + static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE }; + + /* We can allocate at least the nc'th root of max_colors per component. */ + /* Compute floor(nc'th root of max_colors). */ + iroot = 1; + do { + iroot++; + temp = iroot; /* set temp = iroot ** nc */ + for (i = 1; i < nc; i++) + temp *= iroot; + } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */ + iroot--; /* now iroot = floor(root) */ + + /* Must have at least 2 color values per component */ + if (iroot < 2) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp); + + /* Initialize to iroot color values for each component */ + total_colors = 1; + for (i = 0; i < nc; i++) { + Ncolors[i] = iroot; + total_colors *= iroot; + } + /* We may be able to increment the count for one or more components without + * exceeding max_colors, though we know not all can be incremented. + * Sometimes, the first component can be incremented more than once! + * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.) + * In RGB colorspace, try to increment G first, then R, then B. + */ + do { + changed = FALSE; + for (i = 0; i < nc; i++) { + j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i); + /* calculate new total_colors if Ncolors[j] is incremented */ + temp = total_colors / Ncolors[j]; + temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */ + if (temp > (long) max_colors) + break; /* won't fit, done with this pass */ + Ncolors[j]++; /* OK, apply the increment */ + total_colors = (int) temp; + changed = TRUE; + } + } while (changed); + + return total_colors; +} + + +LOCAL int +output_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return j'th output value, where j will range from 0 to maxj */ +/* The output values must fall in 0..MAXJSAMPLE in increasing order */ +{ + /* We always provide values 0 and MAXJSAMPLE for each component; + * any additional values are equally spaced between these limits. + * (Forcing the upper and lower values to the limits ensures that + * dithering can't produce a color outside the selected gamut.) + */ + return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj); +} + + +LOCAL int +largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return largest input value that should map to j'th output value */ +/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ +{ + /* Breakpoints are halfway between values returned by output_value */ + return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); +} + + +/* + * Create the colormap. + */ + +LOCAL void +create_colormap (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colormap; /* Created colormap */ + int total_colors; /* Number of distinct output colors */ + int i,j,k, nci, blksize, blkdist, ptr, val; + + /* Select number of colors for each component */ + total_colors = select_ncolors(cinfo, cquantize->Ncolors); + + /* Report selected color counts */ + if (cinfo->out_color_components == 3) + TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS, + total_colors, cquantize->Ncolors[0], + cquantize->Ncolors[1], cquantize->Ncolors[2]); + else + TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors); + + /* Allocate and fill in the colormap. */ + /* The colors are ordered in the map in standard row-major order, */ + /* i.e. rightmost (highest-indexed) color changes most rapidly. */ + + colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + /* blkdist is distance between groups of identical entries for a component */ + blkdist = total_colors; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colormap entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blkdist / nci; + for (j = 0; j < nci; j++) { + /* Compute j'th output value (out of nci) for component */ + val = output_value(cinfo, i, j, nci-1); + /* Fill in all colormap entries that have this value of this component */ + for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) { + /* fill in blksize entries beginning at ptr */ + for (k = 0; k < blksize; k++) + colormap[i][ptr+k] = (JSAMPLE) val; + } + } + blkdist = blksize; /* blksize of this color is blkdist of next */ + } + + /* Save the colormap in private storage, + * where it will survive color quantization mode changes. + */ + cquantize->sv_colormap = colormap; + cquantize->sv_actual = total_colors; +} + + +/* + * Create the color index table. + */ + +LOCAL void +create_colorindex (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPROW indexptr; + int i,j,k, nci, blksize, val, pad; + + /* For ordered dither, we pad the color index tables by MAXJSAMPLE in + * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE). + * This is not necessary in the other dithering modes. However, we + * flag whether it was done in case user changes dithering mode. + */ + if (cinfo->dither_mode == JDITHER_ORDERED) { + pad = MAXJSAMPLE*2; + cquantize->is_padded = TRUE; + } else { + pad = 0; + cquantize->is_padded = FALSE; + } + + cquantize->colorindex = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (MAXJSAMPLE+1 + pad), + (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + blksize = cquantize->sv_actual; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colorindex entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blksize / nci; + + /* adjust colorindex pointers to provide padding at negative indexes. */ + if (pad) + cquantize->colorindex[i] += MAXJSAMPLE; + + /* in loop, val = index of current output value, */ + /* and k = largest j that maps to current val */ + indexptr = cquantize->colorindex[i]; + val = 0; + k = largest_input_value(cinfo, i, 0, nci-1); + for (j = 0; j <= MAXJSAMPLE; j++) { + while (j > k) /* advance val if past boundary */ + k = largest_input_value(cinfo, i, ++val, nci-1); + /* premultiply so that no multiplication needed in main processing */ + indexptr[j] = (JSAMPLE) (val * blksize); + } + /* Pad at both ends if necessary */ + if (pad) + for (j = 1; j <= MAXJSAMPLE; j++) { + indexptr[-j] = indexptr[0]; + indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE]; + } + } +} + + +/* + * Create an ordered-dither array for a component having ncolors + * distinct output values. + */ + +LOCAL ODITHER_MATRIX_PTR +make_odither_array (j_decompress_ptr cinfo, int ncolors) +{ + ODITHER_MATRIX_PTR odither; + int j,k; + INT32 num,den; + + odither = (ODITHER_MATRIX_PTR) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(ODITHER_MATRIX)); + /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1). + * Hence the dither value for the matrix cell with fill order f + * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1). + * On 16-bit-int machine, be careful to avoid overflow. + */ + den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1)); + for (j = 0; j < ODITHER_SIZE; j++) { + for (k = 0; k < ODITHER_SIZE; k++) { + num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k]))) + * MAXJSAMPLE; + /* Ensure round towards zero despite C's lack of consistency + * about rounding negative values in integer division... + */ + odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den); + } + } + return odither; +} + + +/* + * Create the ordered-dither tables. + * Components having the same number of representative colors may + * share a dither table. + */ + +LOCAL void +create_odither_tables (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + ODITHER_MATRIX_PTR odither; + int i, j, nci; + + for (i = 0; i < cinfo->out_color_components; i++) { + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + odither = NULL; /* search for matching prior component */ + for (j = 0; j < i; j++) { + if (nci == cquantize->Ncolors[j]) { + odither = cquantize->odither[j]; + break; + } + } + if (odither == NULL) /* need a new table? */ + odither = make_odither_array(cinfo, nci); + cquantize->odither[i] = odither; + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF void +color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colorindex = cquantize->colorindex; + register int pixcode, ci; + register JSAMPROW ptrin, ptrout; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + register int nc = cinfo->out_color_components; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]); + } + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF void +color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW ptrin, ptrout; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]); + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF void +quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + int * dither; /* points to active row of dither matrix */ + int row_index, col_index; /* current indexes into dither matrix */ + int nc = cinfo->out_color_components; + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + jzero_far((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + row_index = cquantize->row_index; + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + colorindex_ci = cquantize->colorindex[ci]; + dither = cquantize->odither[ci][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE, + * select output value, accumulate into output code for this pixel. + * Range-limiting need not be done explicitly, as we have extended + * the colorindex table to produce the right answers for out-of-range + * inputs. The maximum dither is +- MAXJSAMPLE; this sets the + * required amount of padding. + */ + *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]]; + input_ptr += nc; + output_ptr++; + col_index = (col_index + 1) & ODITHER_MASK; + } + } + /* Advance row index for next row */ + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF void +quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int * dither0; /* points to active row of dither matrix */ + int * dither1; + int * dither2; + int row_index, col_index; /* current indexes into dither matrix */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + row_index = cquantize->row_index; + input_ptr = input_buf[row]; + output_ptr = output_buf[row]; + dither0 = cquantize->odither[0][row_index]; + dither1 = cquantize->odither[1][row_index]; + dither2 = cquantize->odither[2][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) + + dither0[col_index]]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) + + dither1[col_index]]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) + + dither2[col_index]]); + *output_ptr++ = (JSAMPLE) pixcode; + col_index = (col_index + 1) & ODITHER_MASK; + } + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF void +quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register LOCFSERROR cur; /* current error or pixel value */ + LOCFSERROR belowerr; /* error for pixel below cur */ + LOCFSERROR bpreverr; /* error for below/prev col */ + LOCFSERROR bnexterr; /* error for below/next col */ + LOCFSERROR delta; + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + JSAMPROW colormap_ci; + int pixcode; + int nc = cinfo->out_color_components; + int dir; /* 1 for left-to-right, -1 for right-to-left */ + int dirnc; /* dir * nc */ + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + jzero_far((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + input_ptr += (width-1) * nc; /* so point to rightmost pixel */ + output_ptr += width-1; + dir = -1; + dirnc = -nc; + errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */ + } else { + /* work left to right in this row */ + dir = 1; + dirnc = nc; + errorptr = cquantize->fserrors[ci]; /* => entry before first column */ + } + colorindex_ci = cquantize->colorindex[ci]; + colormap_ci = cquantize->sv_colormap[ci]; + /* Preset error values: no error propagated to first pixel from left */ + cur = 0; + /* and no error propagated to row below yet */ + belowerr = bpreverr = 0; + + for (col = width; col > 0; col--) { + /* cur holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4); + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE; this sets the required size + * of the range_limit array. + */ + cur += GETJSAMPLE(*input_ptr); + cur = GETJSAMPLE(range_limit[cur]); + /* Select output value, accumulate into output code for this pixel */ + pixcode = GETJSAMPLE(colorindex_ci[cur]); + *output_ptr += (JSAMPLE) pixcode; + /* Compute actual representation error at this pixel */ + /* Note: we can do this even though we don't have the final */ + /* pixel code, because the colormap is orthogonal. */ + cur -= GETJSAMPLE(colormap_ci[pixcode]); + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + bnexterr = cur; + delta = cur * 2; + cur += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr + cur); + cur += delta; /* form error * 5 */ + bpreverr = belowerr + cur; + belowerr = bnexterr; + cur += delta; /* form error * 7 */ + /* At this point cur contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + input_ptr += dirnc; /* advance input ptr to next column */ + output_ptr += dir; /* advance output ptr to next column */ + errorptr += dir; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error value into the + * final fserrors[] entry. Note we need not unload belowerr because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */ + } + cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE); + } +} + + +/* + * Allocate workspace for Floyd-Steinberg errors. + */ + +LOCAL void +alloc_fs_workspace (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) { + cquantize->fserrors[i] = (FSERRPTR) + (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + } +} + + +/* + * Initialize for one-pass color quantization. + */ + +METHODDEF void +start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + /* Install my colormap. */ + cinfo->colormap = cquantize->sv_colormap; + cinfo->actual_number_of_colors = cquantize->sv_actual; + + /* Initialize for desired dithering mode. */ + switch (cinfo->dither_mode) { + case JDITHER_NONE: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = color_quantize3; + else + cquantize->pub.color_quantize = color_quantize; + break; + case JDITHER_ORDERED: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = quantize3_ord_dither; + else + cquantize->pub.color_quantize = quantize_ord_dither; + cquantize->row_index = 0; /* initialize state for ordered dither */ + /* If user changed to ordered dither from another mode, + * we must recreate the color index table with padding. + * This will cost extra space, but probably isn't very likely. + */ + if (! cquantize->is_padded) + create_colorindex(cinfo); + /* Create ordered-dither tables if we didn't already. */ + if (cquantize->odither[0] == NULL) + create_odither_tables(cinfo); + break; + case JDITHER_FS: + cquantize->pub.color_quantize = quantize_fs_dither; + cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */ + /* Allocate Floyd-Steinberg workspace if didn't already. */ + if (cquantize->fserrors[0] == NULL) + alloc_fs_workspace(cinfo); + /* Initialize the propagated errors to zero. */ + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) + jzero_far((void FAR *) cquantize->fserrors[i], arraysize); + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } +} + + +/* + * Finish up at the end of the pass. + */ + +METHODDEF void +finish_pass_1_quant (j_decompress_ptr cinfo) +{ + /* no work in 1-pass case */ +} + + +/* + * Switch to a new external colormap between output passes. + * Shouldn't get to this module! + */ + +METHODDEF void +new_color_map_1_quant (j_decompress_ptr cinfo) +{ + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + + +/* + * Module initialization routine for 1-pass color quantization. + */ + +GLOBAL void +jinit_1pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_1_quant; + cquantize->pub.finish_pass = finish_pass_1_quant; + cquantize->pub.new_color_map = new_color_map_1_quant; + cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */ + cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */ + + /* Make sure my internal arrays won't overflow */ + if (cinfo->out_color_components > MAX_Q_COMPS) + ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1)) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1); + + /* Create the colormap and color index table. */ + create_colormap(cinfo); + create_colorindex(cinfo); + + /* Allocate Floyd-Steinberg workspace now if requested. + * We do this now since it is FAR storage and may affect the memory + * manager's space calculations. If the user changes to FS dither + * mode in a later pass, we will allocate the space then, and will + * possibly overrun the max_memory_to_use setting. + */ + if (cinfo->dither_mode == JDITHER_FS) + alloc_fs_workspace(cinfo); +} + +#endif /* QUANT_1PASS_SUPPORTED */ diff --git a/engine/jpeg-6/jquant2.c b/engine/jpeg-6/jquant2.c new file mode 100644 index 0000000..2504398 --- /dev/null +++ b/engine/jpeg-6/jquant2.c @@ -0,0 +1,1310 @@ +/* + * jquant2.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 2-pass color quantization (color mapping) routines. + * These routines provide selection of a custom color map for an image, + * followed by mapping of the image to that color map, with optional + * Floyd-Steinberg dithering. + * It is also possible to use just the second pass to map to an arbitrary + * externally-given color map. + * + * Note: ordered dithering is not supported, since there isn't any fast + * way to compute intercolor distances; it's unclear that ordered dither's + * fundamental assumptions even hold with an irregularly spaced color map. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_2PASS_SUPPORTED + + +/* + * This module implements the well-known Heckbert paradigm for color + * quantization. Most of the ideas used here can be traced back to + * Heckbert's seminal paper + * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", + * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. + * + * In the first pass over the image, we accumulate a histogram showing the + * usage count of each possible color. To keep the histogram to a reasonable + * size, we reduce the precision of the input; typical practice is to retain + * 5 or 6 bits per color, so that 8 or 4 different input values are counted + * in the same histogram cell. + * + * Next, the color-selection step begins with a box representing the whole + * color space, and repeatedly splits the "largest" remaining box until we + * have as many boxes as desired colors. Then the mean color in each + * remaining box becomes one of the possible output colors. + * + * The second pass over the image maps each input pixel to the closest output + * color (optionally after applying a Floyd-Steinberg dithering correction). + * This mapping is logically trivial, but making it go fast enough requires + * considerable care. + * + * Heckbert-style quantizers vary a good deal in their policies for choosing + * the "largest" box and deciding where to cut it. The particular policies + * used here have proved out well in experimental comparisons, but better ones + * may yet be found. + * + * In earlier versions of the IJG code, this module quantized in YCbCr color + * space, processing the raw upsampled data without a color conversion step. + * This allowed the color conversion math to be done only once per colormap + * entry, not once per pixel. However, that optimization precluded other + * useful optimizations (such as merging color conversion with upsampling) + * and it also interfered with desired capabilities such as quantizing to an + * externally-supplied colormap. We have therefore abandoned that approach. + * The present code works in the post-conversion color space, typically RGB. + * + * To improve the visual quality of the results, we actually work in scaled + * RGB space, giving G distances more weight than R, and R in turn more than + * B. To do everything in integer math, we must use integer scale factors. + * The 2/3/1 scale factors used here correspond loosely to the relative + * weights of the colors in the NTSC grayscale equation. + * If you want to use this code to quantize a non-RGB color space, you'll + * probably need to change these scale factors. + */ + +#define R_SCALE 2 /* scale R distances by this much */ +#define G_SCALE 3 /* scale G distances by this much */ +#define B_SCALE 1 /* and B by this much */ + +/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined + * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B + * and B,G,R orders. If you define some other weird order in jmorecfg.h, + * you'll get compile errors until you extend this logic. In that case + * you'll probably want to tweak the histogram sizes too. + */ + +#if RGB_RED == 0 +#define C0_SCALE R_SCALE +#endif +#if RGB_BLUE == 0 +#define C0_SCALE B_SCALE +#endif +#if RGB_GREEN == 1 +#define C1_SCALE G_SCALE +#endif +#if RGB_RED == 2 +#define C2_SCALE R_SCALE +#endif +#if RGB_BLUE == 2 +#define C2_SCALE B_SCALE +#endif + + +/* + * First we have the histogram data structure and routines for creating it. + * + * The number of bits of precision can be adjusted by changing these symbols. + * We recommend keeping 6 bits for G and 5 each for R and B. + * If you have plenty of memory and cycles, 6 bits all around gives marginally + * better results; if you are short of memory, 5 bits all around will save + * some space but degrade the results. + * To maintain a fully accurate histogram, we'd need to allocate a "long" + * (preferably unsigned long) for each cell. In practice this is overkill; + * we can get by with 16 bits per cell. Few of the cell counts will overflow, + * and clamping those that do overflow to the maximum value will give close- + * enough results. This reduces the recommended histogram size from 256Kb + * to 128Kb, which is a useful savings on PC-class machines. + * (In the second pass the histogram space is re-used for pixel mapping data; + * in that capacity, each cell must be able to store zero to the number of + * desired colors. 16 bits/cell is plenty for that too.) + * Since the JPEG code is intended to run in small memory model on 80x86 + * machines, we can't just allocate the histogram in one chunk. Instead + * of a true 3-D array, we use a row of pointers to 2-D arrays. Each + * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and + * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that + * on 80x86 machines, the pointer row is in near memory but the actual + * arrays are in far memory (same arrangement as we use for image arrays). + */ + +#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ + +/* These will do the right thing for either R,G,B or B,G,R color order, + * but you may not like the results for other color orders. + */ +#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ +#define HIST_C1_BITS 6 /* bits of precision in G histogram */ +#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ + +/* Number of elements along histogram axes. */ +#define HIST_C0_ELEMS (1<cquantize; + register JSAMPROW ptr; + register histptr histp; + register hist3d histogram = cquantize->histogram; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptr = input_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the histogram */ + histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] + [GETJSAMPLE(ptr[1]) >> C1_SHIFT] + [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; + /* increment, check for overflow and undo increment if so. */ + if (++(*histp) <= 0) + (*histp)--; + ptr += 3; + } + } +} + + +/* + * Next we have the really interesting routines: selection of a colormap + * given the completed histogram. + * These routines work with a list of "boxes", each representing a rectangular + * subset of the input color space (to histogram precision). + */ + +typedef struct { + /* The bounds of the box (inclusive); expressed as histogram indexes */ + int c0min, c0max; + int c1min, c1max; + int c2min, c2max; + /* The volume (actually 2-norm) of the box */ + INT32 volume; + /* The number of nonzero histogram cells within this box */ + long colorcount; +} box; + +typedef box * boxptr; + + +LOCAL boxptr +find_biggest_color_pop (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest color population */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register long maxc = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->colorcount > maxc && boxp->volume > 0) { + which = boxp; + maxc = boxp->colorcount; + } + } + return which; +} + + +LOCAL boxptr +find_biggest_volume (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest (scaled) volume */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register INT32 maxv = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->volume > maxv) { + which = boxp; + maxv = boxp->volume; + } + } + return which; +} + + +LOCAL void +update_box (j_decompress_ptr cinfo, boxptr boxp) +/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ +/* and recompute its volume and population */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + INT32 dist0,dist1,dist2; + long ccount; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + if (c0max > c0min) + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0min = c0min = c0; + goto have_c0min; + } + } + have_c0min: + if (c0max > c0min) + for (c0 = c0max; c0 >= c0min; c0--) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0max = c0max = c0; + goto have_c0max; + } + } + have_c0max: + if (c1max > c1min) + for (c1 = c1min; c1 <= c1max; c1++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1min = c1min = c1; + goto have_c1min; + } + } + have_c1min: + if (c1max > c1min) + for (c1 = c1max; c1 >= c1min; c1--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1max = c1max = c1; + goto have_c1max; + } + } + have_c1max: + if (c2max > c2min) + for (c2 = c2min; c2 <= c2max; c2++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2min = c2min = c2; + goto have_c2min; + } + } + have_c2min: + if (c2max > c2min) + for (c2 = c2max; c2 >= c2min; c2--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2max = c2max = c2; + goto have_c2max; + } + } + have_c2max: + + /* Update box volume. + * We use 2-norm rather than real volume here; this biases the method + * against making long narrow boxes, and it has the side benefit that + * a box is splittable iff norm > 0. + * Since the differences are expressed in histogram-cell units, + * we have to shift back to JSAMPLE units to get consistent distances; + * after which, we scale according to the selected distance scale factors. + */ + dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; + dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; + dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; + boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; + + /* Now scan remaining volume of box and compute population */ + ccount = 0; + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++, histp++) + if (*histp != 0) { + ccount++; + } + } + boxp->colorcount = ccount; +} + + +LOCAL int +median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, + int desired_colors) +/* Repeatedly select and split the largest box until we have enough boxes */ +{ + int n,lb; + int c0,c1,c2,cmax; + register boxptr b1,b2; + + while (numboxes < desired_colors) { + /* Select box to split. + * Current algorithm: by population for first half, then by volume. + */ + if (numboxes*2 <= desired_colors) { + b1 = find_biggest_color_pop(boxlist, numboxes); + } else { + b1 = find_biggest_volume(boxlist, numboxes); + } + if (b1 == NULL) /* no splittable boxes left! */ + break; + b2 = &boxlist[numboxes]; /* where new box will go */ + /* Copy the color bounds to the new box. */ + b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; + b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; + /* Choose which axis to split the box on. + * Current algorithm: longest scaled axis. + * See notes in update_box about scaling distances. + */ + c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; + c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; + c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; + /* We want to break any ties in favor of green, then red, blue last. + * This code does the right thing for R,G,B or B,G,R color orders only. + */ +#if RGB_RED == 0 + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } +#else + cmax = c1; n = 1; + if (c2 > cmax) { cmax = c2; n = 2; } + if (c0 > cmax) { n = 0; } +#endif + /* Choose split point along selected axis, and update box bounds. + * Current algorithm: split at halfway point. + * (Since the box has been shrunk to minimum volume, + * any split will produce two nonempty subboxes.) + * Note that lb value is max for lower box, so must be < old max. + */ + switch (n) { + case 0: + lb = (b1->c0max + b1->c0min) / 2; + b1->c0max = lb; + b2->c0min = lb+1; + break; + case 1: + lb = (b1->c1max + b1->c1min) / 2; + b1->c1max = lb; + b2->c1min = lb+1; + break; + case 2: + lb = (b1->c2max + b1->c2min) / 2; + b1->c2max = lb; + b2->c2min = lb+1; + break; + } + /* Update stats for boxes */ + update_box(cinfo, b1); + update_box(cinfo, b2); + numboxes++; + } + return numboxes; +} + + +LOCAL void +compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) +/* Compute representative color for a box, put it in colormap[icolor] */ +{ + /* Current algorithm: mean weighted by pixels (not colors) */ + /* Note it is important to get the rounding correct! */ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + long count; + long total = 0; + long c0total = 0; + long c1total = 0; + long c2total = 0; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) { + if ((count = *histp++) != 0) { + total += count; + c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; + c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; + c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; + } + } + } + + cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); + cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); + cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); +} + + +LOCAL void +select_colors (j_decompress_ptr cinfo, int desired_colors) +/* Master routine for color selection */ +{ + boxptr boxlist; + int numboxes; + int i; + + /* Allocate workspace for box list */ + boxlist = (boxptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box)); + /* Initialize one box containing whole space */ + numboxes = 1; + boxlist[0].c0min = 0; + boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; + boxlist[0].c1min = 0; + boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; + boxlist[0].c2min = 0; + boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; + /* Shrink it to actually-used volume and set its statistics */ + update_box(cinfo, & boxlist[0]); + /* Perform median-cut to produce final box list */ + numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); + /* Compute the representative color for each box, fill colormap */ + for (i = 0; i < numboxes; i++) + compute_color(cinfo, & boxlist[i], i); + cinfo->actual_number_of_colors = numboxes; + TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes); +} + + +/* + * These routines are concerned with the time-critical task of mapping input + * colors to the nearest color in the selected colormap. + * + * We re-use the histogram space as an "inverse color map", essentially a + * cache for the results of nearest-color searches. All colors within a + * histogram cell will be mapped to the same colormap entry, namely the one + * closest to the cell's center. This may not be quite the closest entry to + * the actual input color, but it's almost as good. A zero in the cache + * indicates we haven't found the nearest color for that cell yet; the array + * is cleared to zeroes before starting the mapping pass. When we find the + * nearest color for a cell, its colormap index plus one is recorded in the + * cache for future use. The pass2 scanning routines call fill_inverse_cmap + * when they need to use an unfilled entry in the cache. + * + * Our method of efficiently finding nearest colors is based on the "locally + * sorted search" idea described by Heckbert and on the incremental distance + * calculation described by Spencer W. Thomas in chapter III.1 of Graphics + * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that + * the distances from a given colormap entry to each cell of the histogram can + * be computed quickly using an incremental method: the differences between + * distances to adjacent cells themselves differ by a constant. This allows a + * fairly fast implementation of the "brute force" approach of computing the + * distance from every colormap entry to every histogram cell. Unfortunately, + * it needs a work array to hold the best-distance-so-far for each histogram + * cell (because the inner loop has to be over cells, not colormap entries). + * The work array elements have to be INT32s, so the work array would need + * 256Kb at our recommended precision. This is not feasible in DOS machines. + * + * To get around these problems, we apply Thomas' method to compute the + * nearest colors for only the cells within a small subbox of the histogram. + * The work array need be only as big as the subbox, so the memory usage + * problem is solved. Furthermore, we need not fill subboxes that are never + * referenced in pass2; many images use only part of the color gamut, so a + * fair amount of work is saved. An additional advantage of this + * approach is that we can apply Heckbert's locality criterion to quickly + * eliminate colormap entries that are far away from the subbox; typically + * three-fourths of the colormap entries are rejected by Heckbert's criterion, + * and we need not compute their distances to individual cells in the subbox. + * The speed of this approach is heavily influenced by the subbox size: too + * small means too much overhead, too big loses because Heckbert's criterion + * can't eliminate as many colormap entries. Empirically the best subbox + * size seems to be about 1/512th of the histogram (1/8th in each direction). + * + * Thomas' article also describes a refined method which is asymptotically + * faster than the brute-force method, but it is also far more complex and + * cannot efficiently be applied to small subboxes. It is therefore not + * useful for programs intended to be portable to DOS machines. On machines + * with plenty of memory, filling the whole histogram in one shot with Thomas' + * refined method might be faster than the present code --- but then again, + * it might not be any faster, and it's certainly more complicated. + */ + + +/* log2(histogram cells in update box) for each axis; this can be adjusted */ +#define BOX_C0_LOG (HIST_C0_BITS-3) +#define BOX_C1_LOG (HIST_C1_BITS-3) +#define BOX_C2_LOG (HIST_C2_BITS-3) + +#define BOX_C0_ELEMS (1<actual_number_of_colors; + int maxc0, maxc1, maxc2; + int centerc0, centerc1, centerc2; + int i, x, ncolors; + INT32 minmaxdist, min_dist, max_dist, tdist; + INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ + + /* Compute true coordinates of update box's upper corner and center. + * Actually we compute the coordinates of the center of the upper-corner + * histogram cell, which are the upper bounds of the volume we care about. + * Note that since ">>" rounds down, the "center" values may be closer to + * min than to max; hence comparisons to them must be "<=", not "<". + */ + maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); + centerc0 = (minc0 + maxc0) >> 1; + maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); + centerc1 = (minc1 + maxc1) >> 1; + maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); + centerc2 = (minc2 + maxc2) >> 1; + + /* For each color in colormap, find: + * 1. its minimum squared-distance to any point in the update box + * (zero if color is within update box); + * 2. its maximum squared-distance to any point in the update box. + * Both of these can be found by considering only the corners of the box. + * We save the minimum distance for each color in mindist[]; + * only the smallest maximum distance is of interest. + */ + minmaxdist = 0x7FFFFFFFL; + + for (i = 0; i < numcolors; i++) { + /* We compute the squared-c0-distance term, then add in the other two. */ + x = GETJSAMPLE(cinfo->colormap[0][i]); + if (x < minc0) { + tdist = (x - minc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else if (x > maxc0) { + tdist = (x - maxc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + min_dist = 0; + if (x <= centerc0) { + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[1][i]); + if (x < minc1) { + tdist = (x - minc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc1) { + tdist = (x - maxc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc1) { + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[2][i]); + if (x < minc2) { + tdist = (x - minc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc2) { + tdist = (x - maxc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc2) { + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } + } + + mindist[i] = min_dist; /* save away the results */ + if (max_dist < minmaxdist) + minmaxdist = max_dist; + } + + /* Now we know that no cell in the update box is more than minmaxdist + * away from some colormap entry. Therefore, only colors that are + * within minmaxdist of some part of the box need be considered. + */ + ncolors = 0; + for (i = 0; i < numcolors; i++) { + if (mindist[i] <= minmaxdist) + colorlist[ncolors++] = (JSAMPLE) i; + } + return ncolors; +} + + +LOCAL void +find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, + int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) +/* Find the closest colormap entry for each cell in the update box, + * given the list of candidate colors prepared by find_nearby_colors. + * Return the indexes of the closest entries in the bestcolor[] array. + * This routine uses Thomas' incremental distance calculation method to + * find the distance from a colormap entry to successive cells in the box. + */ +{ + int ic0, ic1, ic2; + int i, icolor; + register INT32 * bptr; /* pointer into bestdist[] array */ + JSAMPLE * cptr; /* pointer into bestcolor[] array */ + INT32 dist0, dist1; /* initial distance values */ + register INT32 dist2; /* current distance in inner loop */ + INT32 xx0, xx1; /* distance increments */ + register INT32 xx2; + INT32 inc0, inc1, inc2; /* initial values for increments */ + /* This array holds the distance to the nearest-so-far color for each cell */ + INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Initialize best-distance for each cell of the update box */ + bptr = bestdist; + for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) + *bptr++ = 0x7FFFFFFFL; + + /* For each color selected by find_nearby_colors, + * compute its distance to the center of each cell in the box. + * If that's less than best-so-far, update best distance and color number. + */ + + /* Nominal steps between cell centers ("x" in Thomas article) */ +#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) +#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) +#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) + + for (i = 0; i < numcolors; i++) { + icolor = GETJSAMPLE(colorlist[i]); + /* Compute (square of) distance from minc0/c1/c2 to this color */ + inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; + dist0 = inc0*inc0; + inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; + dist0 += inc1*inc1; + inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; + dist0 += inc2*inc2; + /* Form the initial difference increments */ + inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; + inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; + inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; + /* Now loop over all cells in box, updating distance per Thomas method */ + bptr = bestdist; + cptr = bestcolor; + xx0 = inc0; + for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { + dist1 = dist0; + xx1 = inc1; + for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { + dist2 = dist1; + xx2 = inc2; + for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { + if (dist2 < *bptr) { + *bptr = dist2; + *cptr = (JSAMPLE) icolor; + } + dist2 += xx2; + xx2 += 2 * STEP_C2 * STEP_C2; + bptr++; + cptr++; + } + dist1 += xx1; + xx1 += 2 * STEP_C1 * STEP_C1; + } + dist0 += xx0; + xx0 += 2 * STEP_C0 * STEP_C0; + } + } +} + + +LOCAL void +fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) +/* Fill the inverse-colormap entries in the update box that contains */ +/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ +/* we can fill as many others as we wish.) */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int minc0, minc1, minc2; /* lower left corner of update box */ + int ic0, ic1, ic2; + register JSAMPLE * cptr; /* pointer into bestcolor[] array */ + register histptr cachep; /* pointer into main cache array */ + /* This array lists the candidate colormap indexes. */ + JSAMPLE colorlist[MAXNUMCOLORS]; + int numcolors; /* number of candidate colors */ + /* This array holds the actually closest colormap index for each cell. */ + JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Convert cell coordinates to update box ID */ + c0 >>= BOX_C0_LOG; + c1 >>= BOX_C1_LOG; + c2 >>= BOX_C2_LOG; + + /* Compute true coordinates of update box's origin corner. + * Actually we compute the coordinates of the center of the corner + * histogram cell, which are the lower bounds of the volume we care about. + */ + minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); + minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); + minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); + + /* Determine which colormap entries are close enough to be candidates + * for the nearest entry to some cell in the update box. + */ + numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); + + /* Determine the actually nearest colors. */ + find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, + bestcolor); + + /* Save the best color numbers (plus 1) in the main cache array */ + c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ + c1 <<= BOX_C1_LOG; + c2 <<= BOX_C2_LOG; + cptr = bestcolor; + for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { + for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { + cachep = & histogram[c0+ic0][c1+ic1][c2]; + for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { + *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); + } + } + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF void +pass2_no_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register JSAMPROW inptr, outptr; + register histptr cachep; + register int c0, c1, c2; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the cache */ + c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; + c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; + c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; + cachep = & histogram[c0][c1][c2]; + /* If we have not seen this color before, find nearest colormap entry */ + /* and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, c0,c1,c2); + /* Now emit the colormap index for this cell */ + *outptr++ = (JSAMPLE) (*cachep - 1); + } + } +} + + +METHODDEF void +pass2_fs_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ + LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ + LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + JSAMPROW inptr; /* => current input pixel */ + JSAMPROW outptr; /* => current output pixel */ + histptr cachep; + int dir; /* +1 or -1 depending on direction */ + int dir3; /* 3*dir, for advancing inptr & errorptr */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + int *error_limit = cquantize->error_limiter; + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + inptr += (width-1) * 3; /* so point to rightmost pixel */ + outptr += width-1; + dir = -1; + dir3 = -3; + errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ + cquantize->on_odd_row = FALSE; /* flip for next time */ + } else { + /* work left to right in this row */ + dir = 1; + dir3 = 3; + errorptr = cquantize->fserrors; /* => entry before first real column */ + cquantize->on_odd_row = TRUE; /* flip for next time */ + } + /* Preset error values: no error propagated to first pixel from left */ + cur0 = cur1 = cur2 = 0; + /* and no error propagated to row below yet */ + belowerr0 = belowerr1 = belowerr2 = 0; + bpreverr0 = bpreverr1 = bpreverr2 = 0; + + for (col = width; col > 0; col--) { + /* curN holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); + cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); + cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); + /* Limit the error using transfer function set by init_error_limit. + * See comments with init_error_limit for rationale. + */ + cur0 = error_limit[cur0]; + cur1 = error_limit[cur1]; + cur2 = error_limit[cur2]; + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE (or less with error limiting); + * this sets the required size of the range_limit array. + */ + cur0 += GETJSAMPLE(inptr[0]); + cur1 += GETJSAMPLE(inptr[1]); + cur2 += GETJSAMPLE(inptr[2]); + cur0 = GETJSAMPLE(range_limit[cur0]); + cur1 = GETJSAMPLE(range_limit[cur1]); + cur2 = GETJSAMPLE(range_limit[cur2]); + /* Index into the cache with adjusted pixel value */ + cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; + /* If we have not seen this color before, find nearest colormap */ + /* entry and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); + /* Now emit the colormap index for this cell */ + { register int pixcode = *cachep - 1; + *outptr = (JSAMPLE) pixcode; + /* Compute representation error for this pixel */ + cur0 -= GETJSAMPLE(colormap0[pixcode]); + cur1 -= GETJSAMPLE(colormap1[pixcode]); + cur2 -= GETJSAMPLE(colormap2[pixcode]); + } + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + { register LOCFSERROR bnexterr, delta; + + bnexterr = cur0; /* Process component 0 */ + delta = cur0 * 2; + cur0 += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr0 + cur0); + cur0 += delta; /* form error * 5 */ + bpreverr0 = belowerr0 + cur0; + belowerr0 = bnexterr; + cur0 += delta; /* form error * 7 */ + bnexterr = cur1; /* Process component 1 */ + delta = cur1 * 2; + cur1 += delta; /* form error * 3 */ + errorptr[1] = (FSERROR) (bpreverr1 + cur1); + cur1 += delta; /* form error * 5 */ + bpreverr1 = belowerr1 + cur1; + belowerr1 = bnexterr; + cur1 += delta; /* form error * 7 */ + bnexterr = cur2; /* Process component 2 */ + delta = cur2 * 2; + cur2 += delta; /* form error * 3 */ + errorptr[2] = (FSERROR) (bpreverr2 + cur2); + cur2 += delta; /* form error * 5 */ + bpreverr2 = belowerr2 + cur2; + belowerr2 = bnexterr; + cur2 += delta; /* form error * 7 */ + } + /* At this point curN contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + inptr += dir3; /* Advance pixel pointers to next column */ + outptr += dir; + errorptr += dir3; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error values into the + * final fserrors[] entry. Note we need not unload belowerrN because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ + errorptr[1] = (FSERROR) bpreverr1; + errorptr[2] = (FSERROR) bpreverr2; + } +} + + +/* + * Initialize the error-limiting transfer function (lookup table). + * The raw F-S error computation can potentially compute error values of up to + * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be + * much less, otherwise obviously wrong pixels will be created. (Typical + * effects include weird fringes at color-area boundaries, isolated bright + * pixels in a dark area, etc.) The standard advice for avoiding this problem + * is to ensure that the "corners" of the color cube are allocated as output + * colors; then repeated errors in the same direction cannot cause cascading + * error buildup. However, that only prevents the error from getting + * completely out of hand; Aaron Giles reports that error limiting improves + * the results even with corner colors allocated. + * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty + * well, but the smoother transfer function used below is even better. Thanks + * to Aaron Giles for this idea. + */ + +LOCAL void +init_error_limit (j_decompress_ptr cinfo) +/* Allocate and fill in the error_limiter table */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + int * table; + int in, out; + + table = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int)); + table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ + cquantize->error_limiter = table; + +#define STEPSIZE ((MAXJSAMPLE+1)/16) + /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ + out = 0; + for (in = 0; in < STEPSIZE; in++, out++) { + table[in] = out; table[-in] = -out; + } + /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ + for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { + table[in] = out; table[-in] = -out; + } + /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ + for (; in <= MAXJSAMPLE; in++) { + table[in] = out; table[-in] = -out; + } +#undef STEPSIZE +} + + +/* + * Finish up at the end of each pass. + */ + +METHODDEF void +finish_pass1 (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Select the representative colors and fill in cinfo->colormap */ + cinfo->colormap = cquantize->sv_colormap; + select_colors(cinfo, cquantize->desired); + /* Force next pass to zero the color index table */ + cquantize->needs_zeroed = TRUE; +} + + +METHODDEF void +finish_pass2 (j_decompress_ptr cinfo) +{ + /* no work */ +} + + +/* + * Initialize for each processing pass. + */ + +METHODDEF void +start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int i; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + if (is_pre_scan) { + /* Set up method pointers */ + cquantize->pub.color_quantize = prescan_quantize; + cquantize->pub.finish_pass = finish_pass1; + cquantize->needs_zeroed = TRUE; /* Always zero histogram */ + } else { + /* Set up method pointers */ + if (cinfo->dither_mode == JDITHER_FS) + cquantize->pub.color_quantize = pass2_fs_dither; + else + cquantize->pub.color_quantize = pass2_no_dither; + cquantize->pub.finish_pass = finish_pass2; + + /* Make sure color count is acceptable */ + i = cinfo->actual_number_of_colors; + if (i < 1) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1); + if (i > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + + if (cinfo->dither_mode == JDITHER_FS) { + size_t arraysize = (size_t) ((cinfo->output_width + 2) * + (3 * SIZEOF(FSERROR))); + /* Allocate Floyd-Steinberg workspace if we didn't already. */ + if (cquantize->fserrors == NULL) + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + /* Initialize the propagated errors to zero. */ + jzero_far((void FAR *) cquantize->fserrors, arraysize); + /* Make the error-limit table if we didn't already. */ + if (cquantize->error_limiter == NULL) + init_error_limit(cinfo); + cquantize->on_odd_row = FALSE; + } + + } + /* Zero the histogram or inverse color map, if necessary */ + if (cquantize->needs_zeroed) { + for (i = 0; i < HIST_C0_ELEMS; i++) { + jzero_far((void FAR *) histogram[i], + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = FALSE; + } +} + + +/* + * Switch to a new external colormap between output passes. + */ + +METHODDEF void +new_color_map_2_quant (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Reset the inverse color map */ + cquantize->needs_zeroed = TRUE; +} + + +/* + * Module initialization routine for 2-pass color quantization. + */ + +GLOBAL void +jinit_2pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + int i; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_2_quant; + cquantize->pub.new_color_map = new_color_map_2_quant; + cquantize->fserrors = NULL; /* flag optional arrays not allocated */ + cquantize->error_limiter = NULL; + + /* Make sure jdmaster didn't give me a case I can't handle */ + if (cinfo->out_color_components != 3) + ERREXIT(cinfo, JERR_NOTIMPL); + + /* Allocate the histogram/inverse colormap storage */ + cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d)); + for (i = 0; i < HIST_C0_ELEMS; i++) { + cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = TRUE; /* histogram is garbage now */ + + /* Allocate storage for the completed colormap, if required. + * We do this now since it is FAR storage and may affect + * the memory manager's space calculations. + */ + if (cinfo->enable_2pass_quant) { + /* Make sure color count is acceptable */ + int desired = cinfo->desired_number_of_colors; + /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */ + if (desired < 8) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (desired > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + cquantize->sv_colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3); + cquantize->desired = desired; + } else + cquantize->sv_colormap = NULL; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + /* Allocate Floyd-Steinberg workspace if necessary. + * This isn't really needed until pass 2, but again it is FAR storage. + * Although we will cope with a later change in dither_mode, + * we do not promise to honor max_memory_to_use if dither_mode changes. + */ + if (cinfo->dither_mode == JDITHER_FS) { + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR)))); + /* Might as well create the error-limiting table too. */ + init_error_limit(cinfo); + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/engine/jpeg-6/jutils.c b/engine/jpeg-6/jutils.c new file mode 100644 index 0000000..4ba2a54 --- /dev/null +++ b/engine/jpeg-6/jutils.c @@ -0,0 +1,175 @@ +/* + * jutils.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains tables and miscellaneous utility routines needed + * for both compression and decompression. + * Note we prefix all global names with "j" to minimize conflicts with + * a surrounding application. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element + * of a DCT block read in natural order (left to right, top to bottom). + */ + +const int jpeg_zigzag_order[DCTSIZE2] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +/* + * jpeg_natural_order[i] is the natural-order position of the i'th element + * of zigzag order. + * + * When reading corrupted data, the Huffman decoders could attempt + * to reference an entry beyond the end of this array (if the decoded + * zero run length reaches past the end of the block). To prevent + * wild stores without adding an inner-loop test, we put some extra + * "63"s after the real entries. This will cause the extra coefficient + * to be stored in location 63 of the block, not somewhere random. + * The worst case would be a run-length of 15, which means we need 16 + * fake entries. + */ + +const int jpeg_natural_order[DCTSIZE2+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + + +/* + * Arithmetic utilities + */ + +GLOBAL long +jdiv_round_up (long a, long b) +/* Compute a/b rounded up to next integer, ie, ceil(a/b) */ +/* Assumes a >= 0, b > 0 */ +{ + return (a + b - 1L) / b; +} + + +GLOBAL long +jround_up (long a, long b) +/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */ +/* Assumes a >= 0, b > 0 */ +{ + a += b - 1L; + return a - (a % b); +} + + +/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays + * and coefficient-block arrays. This won't work on 80x86 because the arrays + * are FAR and we're assuming a small-pointer memory model. However, some + * DOS compilers provide far-pointer versions of memcpy() and memset() even + * in the small-model libraries. These will be used if USE_FMEM is defined. + * Otherwise, the routines below do it the hard way. (The performance cost + * is not all that great, because these routines aren't very heavily used.) + */ + +#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */ +#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size) +#define FMEMZERO(target,size) MEMZERO(target,size) +#else /* 80x86 case, define if we can */ +#ifdef USE_FMEM +#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) +#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) +#endif +#endif + + +GLOBAL void +jcopy_sample_rows (JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols) +/* Copy some rows of samples from one place to another. + * num_rows rows are copied from input_array[source_row++] + * to output_array[dest_row++]; these areas may overlap for duplication. + * The source and destination arrays must be at least as wide as num_cols. + */ +{ + register JSAMPROW inptr, outptr; +#ifdef FMEMCOPY + register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE)); +#else + register JDIMENSION count; +#endif + register int row; + + input_array += source_row; + output_array += dest_row; + + for (row = num_rows; row > 0; row--) { + inptr = *input_array++; + outptr = *output_array++; +#ifdef FMEMCOPY + FMEMCOPY(outptr, inptr, count); +#else + for (count = num_cols; count > 0; count--) + *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ +#endif + } +} + + +GLOBAL void +jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks) +/* Copy a row of coefficient blocks from one place to another. */ +{ +#ifdef FMEMCOPY + FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); +#else + register JCOEFPTR inptr, outptr; + register long count; + + inptr = (JCOEFPTR) input_row; + outptr = (JCOEFPTR) output_row; + for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) { + *outptr++ = *inptr++; + } +#endif +} + + +GLOBAL void +jzero_far (void FAR * target, size_t bytestozero) +/* Zero out a chunk of FAR memory. */ +/* This might be sample-array data, block-array data, or alloc_large data. */ +{ +#ifdef FMEMZERO + FMEMZERO(target, bytestozero); +#else + register char FAR * ptr = (char FAR *) target; + register size_t count; + + for (count = bytestozero; count > 0; count--) { + *ptr++ = 0; + } +#endif +} diff --git a/engine/jpeg-6/jversion.h b/engine/jpeg-6/jversion.h new file mode 100644 index 0000000..f2f1b8d --- /dev/null +++ b/engine/jpeg-6/jversion.h @@ -0,0 +1,14 @@ +/* + * jversion.h + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#define JVERSION "6 2-Aug-95" + +#define JCOPYRIGHT "Copyright (C) 1995, Thomas G. Lane"