From 65424fa11b847ba4686fb5f2aa7929a309cb561e Mon Sep 17 00:00:00 2001 From: refraction Date: Fri, 6 Feb 2009 19:52:59 +0000 Subject: [PATCH] git-svn-id: http://pcsx2.googlecode.com/svn/trunk@425 96395faa-99c1-11dd-bbfe-3dabce05a288 --- plugins/CDVDiso/ReadMe.txt | 78 + plugins/CDVDiso/build.sh | 16 + plugins/CDVDiso/src/3rdparty/bzip2/LICENSE | 43 + plugins/CDVDiso/src/3rdparty/bzip2/README | 205 + .../CDVDiso/src/3rdparty/bzip2/blocksort.c | 1094 + plugins/CDVDiso/src/3rdparty/bzip2/bzlib.c | 1571 ++ plugins/CDVDiso/src/3rdparty/bzip2/bzlib.h | 282 + .../src/3rdparty/bzip2/bzlib_private.h | 503 + plugins/CDVDiso/src/3rdparty/bzip2/compress.c | 672 + plugins/CDVDiso/src/3rdparty/bzip2/crctable.c | 104 + .../CDVDiso/src/3rdparty/bzip2/decompress.c | 626 + plugins/CDVDiso/src/3rdparty/bzip2/huffman.c | 205 + .../CDVDiso/src/3rdparty/bzip2/randtable.c | 84 + plugins/CDVDiso/src/3rdparty/zlib/ChangeLog | 855 + plugins/CDVDiso/src/3rdparty/zlib/Makefile.am | 6 + plugins/CDVDiso/src/3rdparty/zlib/README | 125 + plugins/CDVDiso/src/3rdparty/zlib/adler32.c | 149 + plugins/CDVDiso/src/3rdparty/zlib/compress.c | 79 + plugins/CDVDiso/src/3rdparty/zlib/crc32.c | 423 + plugins/CDVDiso/src/3rdparty/zlib/crc32.h | 441 + plugins/CDVDiso/src/3rdparty/zlib/deflate.c | 1736 ++ plugins/CDVDiso/src/3rdparty/zlib/deflate.h | 331 + plugins/CDVDiso/src/3rdparty/zlib/gzio.c | 1026 + plugins/CDVDiso/src/3rdparty/zlib/infback.c | 623 + plugins/CDVDiso/src/3rdparty/zlib/inffast.c | 318 + plugins/CDVDiso/src/3rdparty/zlib/inffast.h | 11 + plugins/CDVDiso/src/3rdparty/zlib/inffixed.h | 94 + plugins/CDVDiso/src/3rdparty/zlib/inflate.c | 1368 ++ plugins/CDVDiso/src/3rdparty/zlib/inflate.h | 115 + plugins/CDVDiso/src/3rdparty/zlib/inftrees.c | 329 + plugins/CDVDiso/src/3rdparty/zlib/inftrees.h | 55 + plugins/CDVDiso/src/3rdparty/zlib/trees.c | 1219 ++ plugins/CDVDiso/src/3rdparty/zlib/trees.h | 128 + plugins/CDVDiso/src/3rdparty/zlib/uncompr.c | 61 + plugins/CDVDiso/src/3rdparty/zlib/zconf.h | 332 + plugins/CDVDiso/src/3rdparty/zlib/zlib.h | 1357 ++ plugins/CDVDiso/src/3rdparty/zlib/zutil.c | 318 + plugins/CDVDiso/src/3rdparty/zlib/zutil.h | 269 + plugins/CDVDiso/src/CDVDiso.h | 130 + plugins/CDVDiso/src/CDVDisop.c | 452 + plugins/CDVDiso/src/Linux/CDVDiso.glade | 403 + plugins/CDVDiso/src/Linux/Config.c | 59 + plugins/CDVDiso/src/Linux/Config.h | 20 + plugins/CDVDiso/src/Linux/Linux.c | 76 + plugins/CDVDiso/src/Linux/Makefile | 33 + plugins/CDVDiso/src/Linux/callbacks.c | 74 + plugins/CDVDiso/src/Linux/callbacks.h | 34 + plugins/CDVDiso/src/Linux/conf.c | 865 + plugins/CDVDiso/src/Linux/interface.c | 220 + plugins/CDVDiso/src/Linux/interface.h | 5 + plugins/CDVDiso/src/Linux/support.c | 144 + plugins/CDVDiso/src/Linux/support.h | 69 + plugins/CDVDiso/src/Win32/CDVDiso.def | 26 + plugins/CDVDiso/src/Win32/CDVDiso.rc | 134 + .../CDVDiso/src/Win32/CDVDiso_vs2008.vcproj | 810 + plugins/CDVDiso/src/Win32/Config.c | 47 + plugins/CDVDiso/src/Win32/Config.h | 3 + plugins/CDVDiso/src/Win32/Makefile | 57 + plugins/CDVDiso/src/Win32/Win32.c | 353 + plugins/CDVDiso/src/Win32/afxresmw.h | 5 + plugins/CDVDiso/src/Win32/resource.h | 28 + .../Win32/vsprops/pcsx2_plugin_common.vsprops | 34 + .../CDVDiso/src/Win32/vsprops/postBuild.tmpl | 21 + .../src/Win32/vsprops/postBuild.unknown | 21 + .../CDVDiso/src/Win32/vsprops/preBuild.cmd | 20 + .../src/Win32/vsprops/svnrev_template.h | 18 + .../src/Win32/vsprops/svnrev_unknown.h | 23 + plugins/CDVDiso/src/common/PS2Edefs.h | 885 + plugins/CDVDiso/src/common/PS2Etypes.h | 219 + plugins/CDVDiso/src/libiso.c | 933 + plugins/CDVDiso/src/libiso.h | 65 + plugins/CDVDiso/src/mkiso/Makefile | 27 + plugins/CDVDiso/src/mkiso/Makefile.mingw | 31 + plugins/CDVDiso/src/mkiso/mkiso.c | 153 + plugins/CDVDiso/src/mkiso/mkiso.dsp | 206 + plugins/CDVDiso/src/mkiso/mkiso.dsw | 29 + plugins/CDVDiso_vs2008.sln | 20 + plugins/SPU2ghz_vs2008.sln | 26 + plugins/ZeroPAD_2008.sln | 20 + plugins/ZeroSPU2_2008.sln | 20 + plugins/build.sh | 60 +- plugins/fetch.sh | 94 + plugins/spu2ghz/CHANGELOG.TXT | 154 + plugins/spu2ghz/LGPL.txt | 503 + plugins/spu2ghz/License.txt | 17 + .../src/3rdparty/SoundTouch/3dnow_win.cpp | 350 + .../src/3rdparty/SoundTouch/AAFilter.cpp | 184 + .../src/3rdparty/SoundTouch/AAFilter.h | 91 + .../src/3rdparty/SoundTouch/BPMDetect.h | 159 + .../3rdparty/SoundTouch/FIFOSampleBuffer.cpp | 252 + .../3rdparty/SoundTouch/FIFOSampleBuffer.h | 174 + .../src/3rdparty/SoundTouch/FIFOSamplePipe.h | 217 + .../src/3rdparty/SoundTouch/FIRFilter.cpp | 272 + .../src/3rdparty/SoundTouch/FIRFilter.h | 163 + .../src/3rdparty/SoundTouch/Makefile.am | 46 + .../3rdparty/SoundTouch/RateTransposer.cpp | 626 + .../src/3rdparty/SoundTouch/RateTransposer.h | 162 + .../spu2ghz/src/3rdparty/SoundTouch/STTypes.h | 202 + .../src/3rdparty/SoundTouch/SoundTouch.cpp | 474 + .../src/3rdparty/SoundTouch/SoundTouch.h | 252 + .../src/3rdparty/SoundTouch/TDStretch.cpp | 940 + .../src/3rdparty/SoundTouch/TDStretch.h | 236 + .../src/3rdparty/SoundTouch/WavFile.cpp | 714 + .../spu2ghz/src/3rdparty/SoundTouch/WavFile.h | 253 + .../src/3rdparty/SoundTouch/cpu_detect.h | 62 + .../SoundTouch/cpu_detect_x86_gcc.cpp | 138 + .../SoundTouch/cpu_detect_x86_win.cpp | 126 + .../src/3rdparty/SoundTouch/mmx_optimized.cpp | 305 + .../src/3rdparty/SoundTouch/sse_optimized.cpp | 484 + plugins/spu2ghz/src/3rdparty/liba52/a52.h | 62 + .../src/3rdparty/liba52/a52_internal.h | 123 + .../spu2ghz/src/3rdparty/liba52/attributes.h | 29 + .../src/3rdparty/liba52/bit_allocate.c | 265 + .../spu2ghz/src/3rdparty/liba52/bitstream.c | 95 + .../spu2ghz/src/3rdparty/liba52/bitstream.h | 77 + plugins/spu2ghz/src/3rdparty/liba52/config.h | 124 + .../src/3rdparty/liba52/configure.incl | 19 + plugins/spu2ghz/src/3rdparty/liba52/downmix.c | 655 + plugins/spu2ghz/src/3rdparty/liba52/imdct.c | 432 + .../spu2ghz/src/3rdparty/liba52/inttypes.h | 13 + .../spu2ghz/src/3rdparty/liba52/mm_accel.h | 37 + plugins/spu2ghz/src/3rdparty/liba52/parse.c | 903 + plugins/spu2ghz/src/3rdparty/liba52/tables.h | 246 + plugins/spu2ghz/src/3rdparty/liba52/tendra.h | 35 + plugins/spu2ghz/src/Win32/SPU2ghz.def | 57 + plugins/spu2ghz/src/Win32/SPU2ghz.rc | 268 + .../spu2ghz/src/Win32/SPU2ghz_vs2008.vcproj | 1074 + plugins/spu2ghz/src/Win32/config.cpp | 618 + plugins/spu2ghz/src/Win32/config.h | 169 + plugins/spu2ghz/src/Win32/dialogs.h | 16 + plugins/spu2ghz/src/Win32/dsound51.cpp | 690 + plugins/spu2ghz/src/Win32/dsoundout.cpp | 459 + plugins/spu2ghz/src/Win32/dsp.cpp | 174 + plugins/spu2ghz/src/Win32/dsp.h | 56 + plugins/spu2ghz/src/Win32/resource.h | 86 + .../Win32/vsprops/pcsx2_plugin_common.vsprops | 34 + .../spu2ghz/src/Win32/vsprops/postBuild.tmpl | 21 + .../src/Win32/vsprops/postBuild.unknown | 21 + .../spu2ghz/src/Win32/vsprops/preBuild.cmd | 20 + .../src/Win32/vsprops/svnrev_template.h | 18 + .../src/Win32/vsprops/svnrev_unknown.h | 23 + plugins/spu2ghz/src/Win32/xaudio2out.cpp | 235 + plugins/spu2ghz/src/common/PS2Edefs.h | 885 + plugins/spu2ghz/src/common/PS2Etypes.h | 219 + plugins/spu2ghz/src/debug.cpp | 258 + plugins/spu2ghz/src/debug.h | 36 + plugins/spu2ghz/src/decoder.cpp | 385 + plugins/spu2ghz/src/defs.h | 325 + plugins/spu2ghz/src/dma.cpp | 510 + plugins/spu2ghz/src/dma.h | 31 + plugins/spu2ghz/src/lowpass.cpp | 67 + plugins/spu2ghz/src/lowpass.h | 27 + plugins/spu2ghz/src/mixer.cpp | 1448 ++ plugins/spu2ghz/src/mixer.h | 26 + plugins/spu2ghz/src/regs.h | 184 + plugins/spu2ghz/src/regtable.h | 308 + plugins/spu2ghz/src/sndout.cpp | 892 + plugins/spu2ghz/src/sndout.h | 91 + plugins/spu2ghz/src/spdif.h | 112 + plugins/spu2ghz/src/spu2.cpp | 2037 ++ plugins/spu2ghz/src/spu2.h | 227 + plugins/spu2ghz/src/spu2replay.cpp | 196 + plugins/spu2ghz/src/spu2replay.h | 35 + plugins/spu2ghz/src/utf8.cpp | 320 + plugins/spu2ghz/src/utf8.h | 36 + plugins/spu2ghz/src/wavedump_wav.cpp | 196 + plugins/spu2ghz/src/waveout.cpp | 278 + plugins/zerogs/build.sh | 32 + plugins/zerogs/dx/GS.h | 749 + plugins/zerogs/dx/GSmain.cpp | 1049 + plugins/zerogs/dx/Mem.cpp | 904 + plugins/zerogs/dx/Mem.h | 486 + plugins/zerogs/dx/README.txt | 13 + plugins/zerogs/dx/Regs.cpp | 1116 + plugins/zerogs/dx/Regs.h | 122 + plugins/zerogs/dx/Win32/Conf.cpp | 117 + plugins/zerogs/dx/Win32/GSsoftdx.def | 35 + plugins/zerogs/dx/Win32/Win32.cpp | 269 + plugins/zerogs/dx/Win32/Win32.h | 9 + plugins/zerogs/dx/Win32/aviUtil.h | 484 + plugins/zerogs/dx/Win32/plugin.def | 31 + plugins/zerogs/dx/Win32/ps2fx.dat | Bin 0 -> 3457692 bytes plugins/zerogs/dx/Win32/resource.h | 45 + plugins/zerogs/dx/Win32/resrc1.h | 87 + .../Win32/vsprops/pcsx2_plugin_common.vsprops | 34 + .../zerogs/dx/Win32/vsprops/postBuild.tmpl | 21 + .../zerogs/dx/Win32/vsprops/postBuild.unknown | 21 + plugins/zerogs/dx/Win32/vsprops/preBuild.cmd | 20 + .../zerogs/dx/Win32/vsprops/svnrev_template.h | 18 + .../zerogs/dx/Win32/vsprops/svnrev_unknown.h | 23 + plugins/zerogs/dx/Win32/zerogs.bmp | Bin 0 -> 921654 bytes plugins/zerogs/dx/Win32/zerogs.rc | 235 + plugins/zerogs/dx/Win32/zerogs_2008.vcproj | 424 + .../dx/ZeroGSShaders/ZeroGSShaders.vcproj | 185 + .../zerogs/dx/ZeroGSShaders/copytozerogs.bat | 1 + .../zerogs/dx/ZeroGSShaders/zerogsshaders.cpp | 407 + .../zerogs/dx/ZeroGSShaders/zerogsshaders.h | 118 + plugins/zerogs/dx/backup.bat | 4 + plugins/zerogs/dx/buildshaders.bat | 3 + plugins/zerogs/dx/common.h | 1142 + plugins/zerogs/dx/common/PS2Edefs.h | 885 + plugins/zerogs/dx/common/PS2Etypes.h | 219 + plugins/zerogs/dx/memcpy_amd.cpp | 479 + plugins/zerogs/dx/ps2hw.fx | 993 + plugins/zerogs/dx/ps2hw_ctx0.fx | 33 + plugins/zerogs/dx/ps2hw_ctx1.fx | 32 + plugins/zerogs/dx/targets.cpp | 3729 ++++ plugins/zerogs/dx/targets.h | 232 + plugins/zerogs/dx/x86-32.asm | 1353 ++ plugins/zerogs/dx/x86-64.asm | 1090 + plugins/zerogs/dx/x86.cpp | 573 + plugins/zerogs/dx/x86.h | 184 + plugins/zerogs/dx/zerogs.cpp | 5106 +++++ plugins/zerogs/dx/zerogs.h | 514 + plugins/zerogs/opengl/GS.h | 845 + plugins/zerogs/opengl/GSmain.cpp | 1400 ++ plugins/zerogs/opengl/Linux/Conf.cpp | 114 + plugins/zerogs/opengl/Linux/Linux.cpp | 430 + plugins/zerogs/opengl/Linux/Linux.h | 26 + plugins/zerogs/opengl/Linux/Makefile.am | 6 + plugins/zerogs/opengl/Linux/buildgui.sh | 9 + plugins/zerogs/opengl/Linux/callbacks.c | 34 + plugins/zerogs/opengl/Linux/callbacks.h | 14 + plugins/zerogs/opengl/Linux/interface.c | 341 + plugins/zerogs/opengl/Linux/interface.h | 6 + plugins/zerogs/opengl/Linux/support.c | 144 + plugins/zerogs/opengl/Linux/support.h | 69 + plugins/zerogs/opengl/Linux/zerogs.glade | 714 + plugins/zerogs/opengl/Makefile.am | 49 + plugins/zerogs/opengl/Mem.cpp | 903 + plugins/zerogs/opengl/Mem.h | 487 + plugins/zerogs/opengl/README.txt | 13 + plugins/zerogs/opengl/Regs.cpp | 1008 + plugins/zerogs/opengl/Regs.h | 101 + plugins/zerogs/opengl/Win32/Conf.cpp | 100 + plugins/zerogs/opengl/Win32/Win32.cpp | 246 + plugins/zerogs/opengl/Win32/Win32.h | 9 + plugins/zerogs/opengl/Win32/aviUtil.h | 484 + plugins/zerogs/opengl/Win32/jconfig.h | 52 + plugins/zerogs/opengl/Win32/jmorecfg.h | 363 + plugins/zerogs/opengl/Win32/jpeglib.h | 1099 + plugins/zerogs/opengl/Win32/libjpeg.lib | Bin 0 -> 470518 bytes plugins/zerogs/opengl/Win32/libjpeg64.lib | Bin 0 -> 1010392 bytes plugins/zerogs/opengl/Win32/ps2hw.dat | Bin 0 -> 106682 bytes plugins/zerogs/opengl/Win32/resource.h | 45 + plugins/zerogs/opengl/Win32/resrc1.h | 79 + .../Win32/vsprops/pcsx2_plugin_common.vsprops | 34 + .../opengl/Win32/vsprops/postBuild.tmpl | 21 + .../opengl/Win32/vsprops/postBuild.unknown | 21 + .../zerogs/opengl/Win32/vsprops/preBuild.cmd | 20 + .../opengl/Win32/vsprops/svnrev_template.h | 18 + .../opengl/Win32/vsprops/svnrev_unknown.h | 23 + plugins/zerogs/opengl/Win32/zerogs.bmp | Bin 0 -> 921654 bytes plugins/zerogs/opengl/Win32/zerogs.def | 36 + plugins/zerogs/opengl/Win32/zerogs.rc | 228 + .../zerogs/opengl/Win32/zerogsogl_2008.vcproj | 550 + plugins/zerogs/opengl/Win32/zlib/adler32.c | 74 + plugins/zerogs/opengl/Win32/zlib/compress.c | 79 + plugins/zerogs/opengl/Win32/zlib/crc32.c | 311 + plugins/zerogs/opengl/Win32/zlib/crc32.h | 441 + plugins/zerogs/opengl/Win32/zlib/deflate.c | 1502 ++ plugins/zerogs/opengl/Win32/zlib/deflate.h | 326 + plugins/zerogs/opengl/Win32/zlib/gzio.c | 1005 + plugins/zerogs/opengl/Win32/zlib/infback.c | 619 + plugins/zerogs/opengl/Win32/zlib/inffast.c | 305 + plugins/zerogs/opengl/Win32/zlib/inffast.h | 11 + plugins/zerogs/opengl/Win32/zlib/inffixed.h | 94 + plugins/zerogs/opengl/Win32/zlib/inflate.c | 1270 ++ plugins/zerogs/opengl/Win32/zlib/inflate.h | 117 + plugins/zerogs/opengl/Win32/zlib/inftrees.c | 321 + plugins/zerogs/opengl/Win32/zlib/inftrees.h | 55 + plugins/zerogs/opengl/Win32/zlib/trees.c | 1215 ++ plugins/zerogs/opengl/Win32/zlib/trees.h | 128 + plugins/zerogs/opengl/Win32/zlib/uncompr.c | 61 + plugins/zerogs/opengl/Win32/zlib/zconf.h | 323 + plugins/zerogs/opengl/Win32/zlib/zlib.h | 1200 ++ plugins/zerogs/opengl/Win32/zlib/zutil.c | 319 + plugins/zerogs/opengl/Win32/zlib/zutil.h | 258 + .../zerogs/opengl/ZeroGSShaders/Makefile.am | 2 + plugins/zerogs/opengl/ZeroGSShaders/ZLib.lib | Bin 0 -> 101154 bytes .../opengl/ZeroGSShaders/ZeroGSShaders.vcproj | 191 + .../ZeroGSShaders/ZeroGSShaders_2005.sln | 23 + .../ZeroGSShaders/ZeroGSShaders_2005.vcproj | 335 + .../opengl/ZeroGSShaders/copytozerogs.bat | 1 + .../opengl/ZeroGSShaders/zerogsshaders.cpp | 337 + .../opengl/ZeroGSShaders/zerogsshaders.h | 89 + .../zerogs/opengl/ZeroGSShaders/zlib/crc32.h | 441 + .../opengl/ZeroGSShaders/zlib/deflate.h | 331 + .../opengl/ZeroGSShaders/zlib/inffast.h | 11 + .../opengl/ZeroGSShaders/zlib/inffixed.h | 94 + .../opengl/ZeroGSShaders/zlib/inflate.h | 115 + .../opengl/ZeroGSShaders/zlib/inftrees.h | 55 + .../zerogs/opengl/ZeroGSShaders/zlib/trees.h | 128 + .../zerogs/opengl/ZeroGSShaders/zlib/zconf.h | 332 + .../opengl/ZeroGSShaders/zlib/zconf.in.h | 332 + .../zerogs/opengl/ZeroGSShaders/zlib/zlib.h | 1357 ++ .../zerogs/opengl/ZeroGSShaders/zlib/zutil.h | 269 + plugins/zerogs/opengl/ZeroGSShaders/zpipe.cpp | 115 + plugins/zerogs/opengl/ZeroGSShaders/zpipe.h | 7 + plugins/zerogs/opengl/buildshaders.bat | 3 + plugins/zerogs/opengl/common.h | 1142 + plugins/zerogs/opengl/common/PS2Edefs.h | 885 + plugins/zerogs/opengl/common/PS2Etypes.h | 219 + plugins/zerogs/opengl/compile | 1 + plugins/zerogs/opengl/configure | 6701 ++++++ plugins/zerogs/opengl/configure.ac | 150 + plugins/zerogs/opengl/ctx0/ps2hw_ctx.fx | 24 + plugins/zerogs/opengl/ctx1/ps2hw_ctx.fx | 23 + plugins/zerogs/opengl/depcomp | 529 + plugins/zerogs/opengl/glprocs.c | 17864 ++++++++++++++++ plugins/zerogs/opengl/glprocs.h | 2213 ++ plugins/zerogs/opengl/install-sh | 323 + plugins/zerogs/opengl/memcpy_amd.cpp | 478 + plugins/zerogs/opengl/missing | 360 + plugins/zerogs/opengl/mkinstalldirs | 158 + plugins/zerogs/opengl/ps2hw.fx | 841 + plugins/zerogs/opengl/rasterfont.cpp | 147 + plugins/zerogs/opengl/rasterfont.h | 22 + plugins/zerogs/opengl/targets.cpp | 3547 +++ plugins/zerogs/opengl/targets.h | 160 + plugins/zerogs/opengl/x86-32.S | 1002 + plugins/zerogs/opengl/x86-32.asm | 652 + plugins/zerogs/opengl/x86-64.S | 906 + plugins/zerogs/opengl/x86-64.asm | 1091 + plugins/zerogs/opengl/x86.cpp | 571 + plugins/zerogs/opengl/x86.h | 182 + plugins/zerogs/opengl/zerogs.cpp | 6016 ++++++ plugins/zerogs/opengl/zerogs.h | 555 + plugins/zerogs/opengl/zerogsmath.h | 903 + plugins/zerogs/opengl/zpipe.cpp | 115 + plugins/zerogs/opengl/zpipe.h | 7 + plugins/zerogs_2008.sln | 31 + plugins/zeropad/Linux/callbacks.h | 46 + plugins/zeropad/Linux/interface.c | 640 + plugins/zeropad/Linux/interface.h | 6 + plugins/zeropad/Linux/linux.cpp | 829 + plugins/zeropad/Linux/support.c | 144 + plugins/zeropad/Linux/support.h | 69 + plugins/zeropad/Linux/zeropad.glade | 1194 ++ plugins/zeropad/Makefile.am | 30 + plugins/zeropad/Windows/ZeroPAD.def | 18 + plugins/zeropad/Windows/ZeroPAD.rc | 136 + plugins/zeropad/Windows/ZeroPAD_2008.vcproj | 232 + plugins/zeropad/Windows/libs/pthread.h | 1368 ++ plugins/zeropad/Windows/libs/pthreadVC2.lib | Bin 0 -> 29280 bytes plugins/zeropad/Windows/libs/sched.h | 178 + plugins/zeropad/Windows/libs/semaphore.h | 166 + plugins/zeropad/Windows/resource.h | 70 + .../vsprops/pcsx2_plugin_common.vsprops | 34 + .../zeropad/Windows/vsprops/postBuild.tmpl | 21 + .../zeropad/Windows/vsprops/postBuild.unknown | 21 + plugins/zeropad/Windows/vsprops/preBuild.cmd | 20 + .../zeropad/Windows/vsprops/svnrev_template.h | 18 + .../zeropad/Windows/vsprops/svnrev_unknown.h | 23 + plugins/zeropad/Windows/win.cpp | 457 + plugins/zeropad/build.sh | 30 + plugins/zeropad/common/PS2Edefs.h | 885 + plugins/zeropad/common/PS2Etypes.h | 219 + plugins/zeropad/configure.ac | 103 + plugins/zeropad/depcomp | 529 + plugins/zeropad/mkinstalldirs | 158 + plugins/zeropad/zeropad.cpp | 528 + plugins/zeropad/zeropad.h | 134 + .../3rdparty/SoundTouch/3dnow_win.cpp | 350 + .../zerospu2/3rdparty/SoundTouch/AAFilter.cpp | 184 + .../zerospu2/3rdparty/SoundTouch/AAFilter.h | 91 + .../zerospu2/3rdparty/SoundTouch/BPMDetect.h | 159 + .../3rdparty/SoundTouch/FIFOSampleBuffer.cpp | 252 + .../3rdparty/SoundTouch/FIFOSampleBuffer.h | 174 + .../3rdparty/SoundTouch/FIFOSamplePipe.h | 217 + .../3rdparty/SoundTouch/FIRFilter.cpp | 272 + .../zerospu2/3rdparty/SoundTouch/FIRFilter.h | 163 + .../zerospu2/3rdparty/SoundTouch/Makefile.am | 46 + .../3rdparty/SoundTouch/RateTransposer.cpp | 626 + .../3rdparty/SoundTouch/RateTransposer.h | 162 + .../zerospu2/3rdparty/SoundTouch/STTypes.h | 202 + .../3rdparty/SoundTouch/SoundTouch.cpp | 474 + .../zerospu2/3rdparty/SoundTouch/SoundTouch.h | 252 + .../3rdparty/SoundTouch/TDStretch.cpp | 940 + .../zerospu2/3rdparty/SoundTouch/TDStretch.h | 236 + .../zerospu2/3rdparty/SoundTouch/WavFile.cpp | 714 + .../zerospu2/3rdparty/SoundTouch/WavFile.h | 253 + .../zerospu2/3rdparty/SoundTouch/cpu_detect.h | 62 + .../SoundTouch/cpu_detect_x86_gcc.cpp | 138 + .../SoundTouch/cpu_detect_x86_win.cpp | 126 + .../3rdparty/SoundTouch/mmx_optimized.cpp | 305 + .../3rdparty/SoundTouch/sse_optimized.cpp | 484 + plugins/zerospu2/Linux/Alsa.cpp | 155 + plugins/zerospu2/Linux/Linux.cpp | 198 + plugins/zerospu2/Linux/Linux.h | 75 + plugins/zerospu2/Linux/OSS.cpp | 121 + plugins/zerospu2/Linux/buildgui.sh | 9 + plugins/zerospu2/Linux/callbacks.c | 26 + plugins/zerospu2/Linux/callbacks.h | 10 + plugins/zerospu2/Linux/interface.c | 130 + plugins/zerospu2/Linux/interface.h | 6 + plugins/zerospu2/Linux/support.c | 144 + plugins/zerospu2/Linux/support.h | 69 + plugins/zerospu2/Linux/zerospu2.glade | 195 + plugins/zerospu2/Makefile.am | 34 + plugins/zerospu2/Win32/Win32.cpp | 180 + plugins/zerospu2/Win32/ZeroSPU2.def | 33 + plugins/zerospu2/Win32/ZeroSPU2.rc | 136 + plugins/zerospu2/Win32/ZeroSPU2_2008.vcproj | 339 + plugins/zerospu2/Win32/dsound51.cpp | 248 + plugins/zerospu2/Win32/resource.h | 28 + .../Win32/vsprops/pcsx2_plugin_common.vsprops | 34 + plugins/zerospu2/Win32/vsprops/postBuild.tmpl | 21 + .../zerospu2/Win32/vsprops/postBuild.unknown | 21 + plugins/zerospu2/Win32/vsprops/preBuild.cmd | 20 + .../zerospu2/Win32/vsprops/svnrev_template.h | 18 + .../zerospu2/Win32/vsprops/svnrev_unknown.h | 23 + plugins/zerospu2/build.sh | 28 + plugins/zerospu2/common/PS2Edefs.h | 885 + plugins/zerospu2/common/PS2Etypes.h | 219 + plugins/zerospu2/compile | 1 + plugins/zerospu2/configure.ac | 103 + plugins/zerospu2/depcomp | 529 + plugins/zerospu2/install-sh | 323 + plugins/zerospu2/misc.h | 147 + plugins/zerospu2/missing | 360 + plugins/zerospu2/mkinstalldirs | 158 + plugins/zerospu2/reg.h | 182 + plugins/zerospu2/voices.cpp | 249 + plugins/zerospu2/zerodma.cpp | 271 + plugins/zerospu2/zerospu2.cpp | 1632 ++ plugins/zerospu2/zerospu2.h | 399 + 427 files changed, 167147 insertions(+), 49 deletions(-) create mode 100644 plugins/CDVDiso/ReadMe.txt create mode 100644 plugins/CDVDiso/build.sh create mode 100644 plugins/CDVDiso/src/3rdparty/bzip2/LICENSE create mode 100644 plugins/CDVDiso/src/3rdparty/bzip2/README create mode 100644 plugins/CDVDiso/src/3rdparty/bzip2/blocksort.c create mode 100644 plugins/CDVDiso/src/3rdparty/bzip2/bzlib.c create mode 100644 plugins/CDVDiso/src/3rdparty/bzip2/bzlib.h create mode 100644 plugins/CDVDiso/src/3rdparty/bzip2/bzlib_private.h create mode 100644 plugins/CDVDiso/src/3rdparty/bzip2/compress.c create mode 100644 plugins/CDVDiso/src/3rdparty/bzip2/crctable.c create mode 100644 plugins/CDVDiso/src/3rdparty/bzip2/decompress.c create mode 100644 plugins/CDVDiso/src/3rdparty/bzip2/huffman.c create mode 100644 plugins/CDVDiso/src/3rdparty/bzip2/randtable.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/ChangeLog create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/Makefile.am create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/README create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/adler32.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/compress.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/crc32.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/crc32.h create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/deflate.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/deflate.h create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/gzio.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/infback.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/inffast.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/inffast.h create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/inffixed.h create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/inflate.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/inflate.h create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/inftrees.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/inftrees.h create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/trees.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/trees.h create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/uncompr.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/zconf.h create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/zlib.h create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/zutil.c create mode 100644 plugins/CDVDiso/src/3rdparty/zlib/zutil.h create mode 100644 plugins/CDVDiso/src/CDVDiso.h create mode 100644 plugins/CDVDiso/src/CDVDisop.c create mode 100644 plugins/CDVDiso/src/Linux/CDVDiso.glade create mode 100644 plugins/CDVDiso/src/Linux/Config.c create mode 100644 plugins/CDVDiso/src/Linux/Config.h create mode 100644 plugins/CDVDiso/src/Linux/Linux.c create mode 100644 plugins/CDVDiso/src/Linux/Makefile create mode 100644 plugins/CDVDiso/src/Linux/callbacks.c create mode 100644 plugins/CDVDiso/src/Linux/callbacks.h create mode 100644 plugins/CDVDiso/src/Linux/conf.c create mode 100644 plugins/CDVDiso/src/Linux/interface.c create mode 100644 plugins/CDVDiso/src/Linux/interface.h create mode 100644 plugins/CDVDiso/src/Linux/support.c create mode 100644 plugins/CDVDiso/src/Linux/support.h create mode 100644 plugins/CDVDiso/src/Win32/CDVDiso.def create mode 100644 plugins/CDVDiso/src/Win32/CDVDiso.rc create mode 100644 plugins/CDVDiso/src/Win32/CDVDiso_vs2008.vcproj create mode 100644 plugins/CDVDiso/src/Win32/Config.c create mode 100644 plugins/CDVDiso/src/Win32/Config.h create mode 100644 plugins/CDVDiso/src/Win32/Makefile create mode 100644 plugins/CDVDiso/src/Win32/Win32.c create mode 100644 plugins/CDVDiso/src/Win32/afxresmw.h create mode 100644 plugins/CDVDiso/src/Win32/resource.h create mode 100644 plugins/CDVDiso/src/Win32/vsprops/pcsx2_plugin_common.vsprops create mode 100644 plugins/CDVDiso/src/Win32/vsprops/postBuild.tmpl create mode 100644 plugins/CDVDiso/src/Win32/vsprops/postBuild.unknown create mode 100644 plugins/CDVDiso/src/Win32/vsprops/preBuild.cmd create mode 100644 plugins/CDVDiso/src/Win32/vsprops/svnrev_template.h create mode 100644 plugins/CDVDiso/src/Win32/vsprops/svnrev_unknown.h create mode 100644 plugins/CDVDiso/src/common/PS2Edefs.h create mode 100644 plugins/CDVDiso/src/common/PS2Etypes.h create mode 100644 plugins/CDVDiso/src/libiso.c create mode 100644 plugins/CDVDiso/src/libiso.h create mode 100644 plugins/CDVDiso/src/mkiso/Makefile create mode 100644 plugins/CDVDiso/src/mkiso/Makefile.mingw create mode 100644 plugins/CDVDiso/src/mkiso/mkiso.c create mode 100644 plugins/CDVDiso/src/mkiso/mkiso.dsp create mode 100644 plugins/CDVDiso/src/mkiso/mkiso.dsw create mode 100644 plugins/CDVDiso_vs2008.sln create mode 100644 plugins/SPU2ghz_vs2008.sln create mode 100644 plugins/ZeroPAD_2008.sln create mode 100644 plugins/ZeroSPU2_2008.sln create mode 100644 plugins/fetch.sh create mode 100644 plugins/spu2ghz/CHANGELOG.TXT create mode 100644 plugins/spu2ghz/LGPL.txt create mode 100644 plugins/spu2ghz/License.txt create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/3dnow_win.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.h create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/BPMDetect.h create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.h create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSamplePipe.h create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.h create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/Makefile.am create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.h create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/STTypes.h create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.h create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.h create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.h create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect.h create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_win.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/mmx_optimized.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/SoundTouch/sse_optimized.cpp create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/a52.h create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/a52_internal.h create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/attributes.h create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/bit_allocate.c create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/bitstream.c create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/bitstream.h create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/config.h create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/configure.incl create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/downmix.c create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/imdct.c create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/inttypes.h create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/mm_accel.h create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/parse.c create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/tables.h create mode 100644 plugins/spu2ghz/src/3rdparty/liba52/tendra.h create mode 100644 plugins/spu2ghz/src/Win32/SPU2ghz.def create mode 100644 plugins/spu2ghz/src/Win32/SPU2ghz.rc create mode 100644 plugins/spu2ghz/src/Win32/SPU2ghz_vs2008.vcproj create mode 100644 plugins/spu2ghz/src/Win32/config.cpp create mode 100644 plugins/spu2ghz/src/Win32/config.h create mode 100644 plugins/spu2ghz/src/Win32/dialogs.h create mode 100644 plugins/spu2ghz/src/Win32/dsound51.cpp create mode 100644 plugins/spu2ghz/src/Win32/dsoundout.cpp create mode 100644 plugins/spu2ghz/src/Win32/dsp.cpp create mode 100644 plugins/spu2ghz/src/Win32/dsp.h create mode 100644 plugins/spu2ghz/src/Win32/resource.h create mode 100644 plugins/spu2ghz/src/Win32/vsprops/pcsx2_plugin_common.vsprops create mode 100644 plugins/spu2ghz/src/Win32/vsprops/postBuild.tmpl create mode 100644 plugins/spu2ghz/src/Win32/vsprops/postBuild.unknown create mode 100644 plugins/spu2ghz/src/Win32/vsprops/preBuild.cmd create mode 100644 plugins/spu2ghz/src/Win32/vsprops/svnrev_template.h create mode 100644 plugins/spu2ghz/src/Win32/vsprops/svnrev_unknown.h create mode 100644 plugins/spu2ghz/src/Win32/xaudio2out.cpp create mode 100644 plugins/spu2ghz/src/common/PS2Edefs.h create mode 100644 plugins/spu2ghz/src/common/PS2Etypes.h create mode 100644 plugins/spu2ghz/src/debug.cpp create mode 100644 plugins/spu2ghz/src/debug.h create mode 100644 plugins/spu2ghz/src/decoder.cpp create mode 100644 plugins/spu2ghz/src/defs.h create mode 100644 plugins/spu2ghz/src/dma.cpp create mode 100644 plugins/spu2ghz/src/dma.h create mode 100644 plugins/spu2ghz/src/lowpass.cpp create mode 100644 plugins/spu2ghz/src/lowpass.h create mode 100644 plugins/spu2ghz/src/mixer.cpp create mode 100644 plugins/spu2ghz/src/mixer.h create mode 100644 plugins/spu2ghz/src/regs.h create mode 100644 plugins/spu2ghz/src/regtable.h create mode 100644 plugins/spu2ghz/src/sndout.cpp create mode 100644 plugins/spu2ghz/src/sndout.h create mode 100644 plugins/spu2ghz/src/spdif.h create mode 100644 plugins/spu2ghz/src/spu2.cpp create mode 100644 plugins/spu2ghz/src/spu2.h create mode 100644 plugins/spu2ghz/src/spu2replay.cpp create mode 100644 plugins/spu2ghz/src/spu2replay.h create mode 100644 plugins/spu2ghz/src/utf8.cpp create mode 100644 plugins/spu2ghz/src/utf8.h create mode 100644 plugins/spu2ghz/src/wavedump_wav.cpp create mode 100644 plugins/spu2ghz/src/waveout.cpp create mode 100644 plugins/zerogs/build.sh create mode 100644 plugins/zerogs/dx/GS.h create mode 100644 plugins/zerogs/dx/GSmain.cpp create mode 100644 plugins/zerogs/dx/Mem.cpp create mode 100644 plugins/zerogs/dx/Mem.h create mode 100644 plugins/zerogs/dx/README.txt create mode 100644 plugins/zerogs/dx/Regs.cpp create mode 100644 plugins/zerogs/dx/Regs.h create mode 100644 plugins/zerogs/dx/Win32/Conf.cpp create mode 100644 plugins/zerogs/dx/Win32/GSsoftdx.def create mode 100644 plugins/zerogs/dx/Win32/Win32.cpp create mode 100644 plugins/zerogs/dx/Win32/Win32.h create mode 100644 plugins/zerogs/dx/Win32/aviUtil.h create mode 100644 plugins/zerogs/dx/Win32/plugin.def create mode 100644 plugins/zerogs/dx/Win32/ps2fx.dat create mode 100644 plugins/zerogs/dx/Win32/resource.h create mode 100644 plugins/zerogs/dx/Win32/resrc1.h create mode 100644 plugins/zerogs/dx/Win32/vsprops/pcsx2_plugin_common.vsprops create mode 100644 plugins/zerogs/dx/Win32/vsprops/postBuild.tmpl create mode 100644 plugins/zerogs/dx/Win32/vsprops/postBuild.unknown create mode 100644 plugins/zerogs/dx/Win32/vsprops/preBuild.cmd create mode 100644 plugins/zerogs/dx/Win32/vsprops/svnrev_template.h create mode 100644 plugins/zerogs/dx/Win32/vsprops/svnrev_unknown.h create mode 100644 plugins/zerogs/dx/Win32/zerogs.bmp create mode 100644 plugins/zerogs/dx/Win32/zerogs.rc create mode 100644 plugins/zerogs/dx/Win32/zerogs_2008.vcproj create mode 100644 plugins/zerogs/dx/ZeroGSShaders/ZeroGSShaders.vcproj create mode 100644 plugins/zerogs/dx/ZeroGSShaders/copytozerogs.bat create mode 100644 plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp create mode 100644 plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.h create mode 100644 plugins/zerogs/dx/backup.bat create mode 100644 plugins/zerogs/dx/buildshaders.bat create mode 100644 plugins/zerogs/dx/common.h create mode 100644 plugins/zerogs/dx/common/PS2Edefs.h create mode 100644 plugins/zerogs/dx/common/PS2Etypes.h create mode 100644 plugins/zerogs/dx/memcpy_amd.cpp create mode 100644 plugins/zerogs/dx/ps2hw.fx create mode 100644 plugins/zerogs/dx/ps2hw_ctx0.fx create mode 100644 plugins/zerogs/dx/ps2hw_ctx1.fx create mode 100644 plugins/zerogs/dx/targets.cpp create mode 100644 plugins/zerogs/dx/targets.h create mode 100644 plugins/zerogs/dx/x86-32.asm create mode 100644 plugins/zerogs/dx/x86-64.asm create mode 100644 plugins/zerogs/dx/x86.cpp create mode 100644 plugins/zerogs/dx/x86.h create mode 100644 plugins/zerogs/dx/zerogs.cpp create mode 100644 plugins/zerogs/dx/zerogs.h create mode 100644 plugins/zerogs/opengl/GS.h create mode 100644 plugins/zerogs/opengl/GSmain.cpp create mode 100644 plugins/zerogs/opengl/Linux/Conf.cpp create mode 100644 plugins/zerogs/opengl/Linux/Linux.cpp create mode 100644 plugins/zerogs/opengl/Linux/Linux.h create mode 100644 plugins/zerogs/opengl/Linux/Makefile.am create mode 100644 plugins/zerogs/opengl/Linux/buildgui.sh create mode 100644 plugins/zerogs/opengl/Linux/callbacks.c create mode 100644 plugins/zerogs/opengl/Linux/callbacks.h create mode 100644 plugins/zerogs/opengl/Linux/interface.c create mode 100644 plugins/zerogs/opengl/Linux/interface.h create mode 100644 plugins/zerogs/opengl/Linux/support.c create mode 100644 plugins/zerogs/opengl/Linux/support.h create mode 100644 plugins/zerogs/opengl/Linux/zerogs.glade create mode 100644 plugins/zerogs/opengl/Makefile.am create mode 100644 plugins/zerogs/opengl/Mem.cpp create mode 100644 plugins/zerogs/opengl/Mem.h create mode 100644 plugins/zerogs/opengl/README.txt create mode 100644 plugins/zerogs/opengl/Regs.cpp create mode 100644 plugins/zerogs/opengl/Regs.h create mode 100644 plugins/zerogs/opengl/Win32/Conf.cpp create mode 100644 plugins/zerogs/opengl/Win32/Win32.cpp create mode 100644 plugins/zerogs/opengl/Win32/Win32.h create mode 100644 plugins/zerogs/opengl/Win32/aviUtil.h create mode 100644 plugins/zerogs/opengl/Win32/jconfig.h create mode 100644 plugins/zerogs/opengl/Win32/jmorecfg.h create mode 100644 plugins/zerogs/opengl/Win32/jpeglib.h create mode 100644 plugins/zerogs/opengl/Win32/libjpeg.lib create mode 100644 plugins/zerogs/opengl/Win32/libjpeg64.lib create mode 100644 plugins/zerogs/opengl/Win32/ps2hw.dat create mode 100644 plugins/zerogs/opengl/Win32/resource.h create mode 100644 plugins/zerogs/opengl/Win32/resrc1.h create mode 100644 plugins/zerogs/opengl/Win32/vsprops/pcsx2_plugin_common.vsprops create mode 100644 plugins/zerogs/opengl/Win32/vsprops/postBuild.tmpl create mode 100644 plugins/zerogs/opengl/Win32/vsprops/postBuild.unknown create mode 100644 plugins/zerogs/opengl/Win32/vsprops/preBuild.cmd create mode 100644 plugins/zerogs/opengl/Win32/vsprops/svnrev_template.h create mode 100644 plugins/zerogs/opengl/Win32/vsprops/svnrev_unknown.h create mode 100644 plugins/zerogs/opengl/Win32/zerogs.bmp create mode 100644 plugins/zerogs/opengl/Win32/zerogs.def create mode 100644 plugins/zerogs/opengl/Win32/zerogs.rc create mode 100644 plugins/zerogs/opengl/Win32/zerogsogl_2008.vcproj create mode 100644 plugins/zerogs/opengl/Win32/zlib/adler32.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/compress.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/crc32.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/crc32.h create mode 100644 plugins/zerogs/opengl/Win32/zlib/deflate.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/deflate.h create mode 100644 plugins/zerogs/opengl/Win32/zlib/gzio.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/infback.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/inffast.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/inffast.h create mode 100644 plugins/zerogs/opengl/Win32/zlib/inffixed.h create mode 100644 plugins/zerogs/opengl/Win32/zlib/inflate.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/inflate.h create mode 100644 plugins/zerogs/opengl/Win32/zlib/inftrees.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/inftrees.h create mode 100644 plugins/zerogs/opengl/Win32/zlib/trees.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/trees.h create mode 100644 plugins/zerogs/opengl/Win32/zlib/uncompr.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/zconf.h create mode 100644 plugins/zerogs/opengl/Win32/zlib/zlib.h create mode 100644 plugins/zerogs/opengl/Win32/zlib/zutil.c create mode 100644 plugins/zerogs/opengl/Win32/zlib/zutil.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/Makefile.am create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/ZLib.lib create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/ZeroGSShaders.vcproj create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.sln create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.vcproj create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/copytozerogs.bat create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zlib/crc32.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zlib/deflate.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zlib/inffast.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zlib/inflate.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zlib/trees.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zlib/zlib.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zlib/zutil.h create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zpipe.cpp create mode 100644 plugins/zerogs/opengl/ZeroGSShaders/zpipe.h create mode 100644 plugins/zerogs/opengl/buildshaders.bat create mode 100644 plugins/zerogs/opengl/common.h create mode 100644 plugins/zerogs/opengl/common/PS2Edefs.h create mode 100644 plugins/zerogs/opengl/common/PS2Etypes.h create mode 100644 plugins/zerogs/opengl/compile create mode 100644 plugins/zerogs/opengl/configure create mode 100644 plugins/zerogs/opengl/configure.ac create mode 100644 plugins/zerogs/opengl/ctx0/ps2hw_ctx.fx create mode 100644 plugins/zerogs/opengl/ctx1/ps2hw_ctx.fx create mode 100644 plugins/zerogs/opengl/depcomp create mode 100644 plugins/zerogs/opengl/glprocs.c create mode 100644 plugins/zerogs/opengl/glprocs.h create mode 100644 plugins/zerogs/opengl/install-sh create mode 100644 plugins/zerogs/opengl/memcpy_amd.cpp create mode 100644 plugins/zerogs/opengl/missing create mode 100644 plugins/zerogs/opengl/mkinstalldirs create mode 100644 plugins/zerogs/opengl/ps2hw.fx create mode 100644 plugins/zerogs/opengl/rasterfont.cpp create mode 100644 plugins/zerogs/opengl/rasterfont.h create mode 100644 plugins/zerogs/opengl/targets.cpp create mode 100644 plugins/zerogs/opengl/targets.h create mode 100644 plugins/zerogs/opengl/x86-32.S create mode 100644 plugins/zerogs/opengl/x86-32.asm create mode 100644 plugins/zerogs/opengl/x86-64.S create mode 100644 plugins/zerogs/opengl/x86-64.asm create mode 100644 plugins/zerogs/opengl/x86.cpp create mode 100644 plugins/zerogs/opengl/x86.h create mode 100644 plugins/zerogs/opengl/zerogs.cpp create mode 100644 plugins/zerogs/opengl/zerogs.h create mode 100644 plugins/zerogs/opengl/zerogsmath.h create mode 100644 plugins/zerogs/opengl/zpipe.cpp create mode 100644 plugins/zerogs/opengl/zpipe.h create mode 100644 plugins/zerogs_2008.sln create mode 100644 plugins/zeropad/Linux/callbacks.h create mode 100644 plugins/zeropad/Linux/interface.c create mode 100644 plugins/zeropad/Linux/interface.h create mode 100644 plugins/zeropad/Linux/linux.cpp create mode 100644 plugins/zeropad/Linux/support.c create mode 100644 plugins/zeropad/Linux/support.h create mode 100644 plugins/zeropad/Linux/zeropad.glade create mode 100644 plugins/zeropad/Makefile.am create mode 100644 plugins/zeropad/Windows/ZeroPAD.def create mode 100644 plugins/zeropad/Windows/ZeroPAD.rc create mode 100644 plugins/zeropad/Windows/ZeroPAD_2008.vcproj create mode 100644 plugins/zeropad/Windows/libs/pthread.h create mode 100644 plugins/zeropad/Windows/libs/pthreadVC2.lib create mode 100644 plugins/zeropad/Windows/libs/sched.h create mode 100644 plugins/zeropad/Windows/libs/semaphore.h create mode 100644 plugins/zeropad/Windows/resource.h create mode 100644 plugins/zeropad/Windows/vsprops/pcsx2_plugin_common.vsprops create mode 100644 plugins/zeropad/Windows/vsprops/postBuild.tmpl create mode 100644 plugins/zeropad/Windows/vsprops/postBuild.unknown create mode 100644 plugins/zeropad/Windows/vsprops/preBuild.cmd create mode 100644 plugins/zeropad/Windows/vsprops/svnrev_template.h create mode 100644 plugins/zeropad/Windows/vsprops/svnrev_unknown.h create mode 100644 plugins/zeropad/Windows/win.cpp create mode 100644 plugins/zeropad/build.sh create mode 100644 plugins/zeropad/common/PS2Edefs.h create mode 100644 plugins/zeropad/common/PS2Etypes.h create mode 100644 plugins/zeropad/configure.ac create mode 100644 plugins/zeropad/depcomp create mode 100644 plugins/zeropad/mkinstalldirs create mode 100644 plugins/zeropad/zeropad.cpp create mode 100644 plugins/zeropad/zeropad.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/3dnow_win.cpp create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/AAFilter.cpp create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/AAFilter.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/BPMDetect.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.cpp create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/FIFOSamplePipe.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.cpp create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/Makefile.am create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.cpp create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/STTypes.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.cpp create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/TDStretch.cpp create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/TDStretch.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/WavFile.cpp create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/WavFile.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/cpu_detect.h create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_win.cpp create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/mmx_optimized.cpp create mode 100644 plugins/zerospu2/3rdparty/SoundTouch/sse_optimized.cpp create mode 100644 plugins/zerospu2/Linux/Alsa.cpp create mode 100644 plugins/zerospu2/Linux/Linux.cpp create mode 100644 plugins/zerospu2/Linux/Linux.h create mode 100644 plugins/zerospu2/Linux/OSS.cpp create mode 100644 plugins/zerospu2/Linux/buildgui.sh create mode 100644 plugins/zerospu2/Linux/callbacks.c create mode 100644 plugins/zerospu2/Linux/callbacks.h create mode 100644 plugins/zerospu2/Linux/interface.c create mode 100644 plugins/zerospu2/Linux/interface.h create mode 100644 plugins/zerospu2/Linux/support.c create mode 100644 plugins/zerospu2/Linux/support.h create mode 100644 plugins/zerospu2/Linux/zerospu2.glade create mode 100644 plugins/zerospu2/Makefile.am create mode 100644 plugins/zerospu2/Win32/Win32.cpp create mode 100644 plugins/zerospu2/Win32/ZeroSPU2.def create mode 100644 plugins/zerospu2/Win32/ZeroSPU2.rc create mode 100644 plugins/zerospu2/Win32/ZeroSPU2_2008.vcproj create mode 100644 plugins/zerospu2/Win32/dsound51.cpp create mode 100644 plugins/zerospu2/Win32/resource.h create mode 100644 plugins/zerospu2/Win32/vsprops/pcsx2_plugin_common.vsprops create mode 100644 plugins/zerospu2/Win32/vsprops/postBuild.tmpl create mode 100644 plugins/zerospu2/Win32/vsprops/postBuild.unknown create mode 100644 plugins/zerospu2/Win32/vsprops/preBuild.cmd create mode 100644 plugins/zerospu2/Win32/vsprops/svnrev_template.h create mode 100644 plugins/zerospu2/Win32/vsprops/svnrev_unknown.h create mode 100644 plugins/zerospu2/build.sh create mode 100644 plugins/zerospu2/common/PS2Edefs.h create mode 100644 plugins/zerospu2/common/PS2Etypes.h create mode 100644 plugins/zerospu2/compile create mode 100644 plugins/zerospu2/configure.ac create mode 100644 plugins/zerospu2/depcomp create mode 100644 plugins/zerospu2/install-sh create mode 100644 plugins/zerospu2/misc.h create mode 100644 plugins/zerospu2/missing create mode 100644 plugins/zerospu2/mkinstalldirs create mode 100644 plugins/zerospu2/reg.h create mode 100644 plugins/zerospu2/voices.cpp create mode 100644 plugins/zerospu2/zerodma.cpp create mode 100644 plugins/zerospu2/zerospu2.cpp create mode 100644 plugins/zerospu2/zerospu2.h diff --git a/plugins/CDVDiso/ReadMe.txt b/plugins/CDVDiso/ReadMe.txt new file mode 100644 index 0000000000..b1a915352f --- /dev/null +++ b/plugins/CDVDiso/ReadMe.txt @@ -0,0 +1,78 @@ +CDVDiso v0.5 +------------ + + This is an extension to use with play station2 emulators + as PCSX2 (only one right now). + The plugin is free open source code. + +Linux requeriments: +------------------ + You need the GTK library, compiled with GTK v1.2.5, + the Zlib library (v1.1.3) and the bz2 library (v1.0.0). + +Usage: +----- + Place the file "libCDVDiso.so" (linux) or "CDVDiso.dll" (win32) at the Plugin + directory of the Emulator to use it. + + Linux only: Also place the cfgCDVDiso file at your $HOME directory or at the + Emulator directory. + +Configuration: +------------- + You can either write the iso you want to use in the config dialog, or everytime + you run the emu open it, if you're doing this don't write anything in the dialog. + +Creating an iso (linux only): +--------------- + To create an iso you can use the buttons 'Create Iso' or 'Create Compressed Iso', + the file will be the one in the Iso Edit, and the Cdrom Device is the cdrom that + will be used as source. + The compression method is specified by the Compression Method Combo. + + Note: This will fail if the file in the Iso Edit already exists (if it's + compressed the .Z or .bz suffix will be added). + +Compressed isos: +--------------- + You must create them by the Compress Iso button, this will create a .Z or .bz + file (the compressed image) and a .Z.table or .bz.index file (this is a table, + for speed reasons), both will be created in the same dir the selected iso + image, the original image will not be deleted and/or changed, and also you can + decompress the compressed iso with Decompress Iso button. + The compression method is specified by the Compression Method Combo. + + Note: you only can decompress the images with the Decompress button, not with + compress or bzip2. + +Compression Method: +------------------ + .Z - compress faster: this will compress faster, but not as good as the .bz. + .bz - compress better: will compress better, but slower. + +Changes: +------- + v0.5: + * Added block dumping code + * Added BZ2/Z2 format ;) + * Added optimaze asm code of zlib with vsnet2003 only. Compression / Uncompression should be faster now (shadow) + * Added Vsnet2005 beta1 project files + amd64 asm optimaze code for zlib (shadow) + + v0.4: + * Rewrote mostly ;) + * .bz is still unsupported + + v0.3: + * Better Iso detection, thx florin :) + * Updated to PS2Edefs v0.4.5 + + v0.2: + * Added support for isos using 2048 blocksize + * Nero images are supported + * Better extension filtering + + v0.1: + * First Release + * Tested with Pcsx2 + + Email: diff --git a/plugins/CDVDiso/build.sh b/plugins/CDVDiso/build.sh new file mode 100644 index 0000000000..daf35304d3 --- /dev/null +++ b/plugins/CDVDiso/build.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +curdir=`pwd` + +echo ---------------- +echo Building CDVDiso +echo ---------------- + +cd ${curdir}/src/Linux +make $@ + +# copy the files +if [ -s cfgCDVDiso ] && [ -s libCDVDiso.so ] +then +cp cfgCDVDiso libCDVDiso.so ${PCSX2PLUGINS} +fi diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/LICENSE b/plugins/CDVDiso/src/3rdparty/bzip2/LICENSE new file mode 100644 index 0000000000..383aabe35f --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/bzip2/LICENSE @@ -0,0 +1,43 @@ + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2006 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. 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. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, Cambridge, UK. +jseward@bzip.org +bzip2/libbzip2 version 1.0.4 of 20 December 2006 + +-------------------------------------------------------------------------- diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/README b/plugins/CDVDiso/src/3rdparty/bzip2/README new file mode 100644 index 0000000000..3b819daf3f --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/bzip2/README @@ -0,0 +1,205 @@ + +This is the README for bzip2/libzip2. +This version is fully compatible with the previous public releases. + +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in this file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +Complete documentation is available in Postscript form (manual.ps), +PDF (manual.pdf) or html (manual.html). A plain-text version of the +manual page is available as bzip2.txt. + + +HOW TO BUILD -- UNIX + +Type 'make'. This builds the library libbz2.a and then the programs +bzip2 and bzip2recover. Six self-tests are run. If the self-tests +complete ok, carry on to installation: + +To install in /usr/local/bin, /usr/local/lib, /usr/local/man and +/usr/local/include, type + + make install + +To install somewhere else, eg, /xxx/yyy/{bin,lib,man,include}, type + + make install PREFIX=/xxx/yyy + +If you are (justifiably) paranoid and want to see what 'make install' +is going to do, you can first do + + make -n install or + make -n install PREFIX=/xxx/yyy respectively. + +The -n instructs make to show the commands it would execute, but not +actually execute them. + + +HOW TO BUILD -- UNIX, shared library libbz2.so. + +Do 'make -f Makefile-libbz2_so'. This Makefile seems to work for +Linux-ELF (RedHat 7.2 on an x86 box), with gcc. I make no claims +that it works for any other platform, though I suspect it probably +will work for most platforms employing both ELF and gcc. + +bzip2-shared, a client of the shared library, is also built, but not +self-tested. So I suggest you also build using the normal Makefile, +since that conducts a self-test. A second reason to prefer the +version statically linked to the library is that, on x86 platforms, +building shared objects makes a valuable register (%ebx) unavailable +to gcc, resulting in a slowdown of 10%-20%, at least for bzip2. + +Important note for people upgrading .so's from 0.9.0/0.9.5 to version +1.0.X. All the functions in the library have been renamed, from (eg) +bzCompress to BZ2_bzCompress, to avoid namespace pollution. +Unfortunately this means that the libbz2.so created by +Makefile-libbz2_so will not work with any program which used an older +version of the library. I do encourage library clients to make the +effort to upgrade to use version 1.0, since it is both faster and more +robust than previous versions. + + +HOW TO BUILD -- Windows 95, NT, DOS, Mac, etc. + +It's difficult for me to support compilation on all these platforms. +My approach is to collect binaries for these platforms, and put them +on the master web site (http://www.bzip.org). Look there. However +(FWIW), bzip2-1.0.X is very standard ANSI C and should compile +unmodified with MS Visual C. If you have difficulties building, you +might want to read README.COMPILATION.PROBLEMS. + +At least using MS Visual C++ 6, you can build from the unmodified +sources by issuing, in a command shell: + + nmake -f makefile.msc + +(you may need to first run the MSVC-provided script VCVARS32.BAT + so as to set up paths to the MSVC tools correctly). + + +VALIDATION + +Correct operation, in the sense that a compressed file can always be +decompressed to reproduce the original, is obviously of paramount +importance. To validate bzip2, I used a modified version of Mark +Nelson's churn program. Churn is an automated test driver which +recursively traverses a directory structure, using bzip2 to compress +and then decompress each file it encounters, and checking that the +decompressed data is the same as the original. + + + +Please read and be aware of the following: + +WARNING: + + This program and library (attempts to) compress data by + performing several non-trivial transformations on it. + Unless you are 100% familiar with *all* the algorithms + contained herein, and with the consequences of modifying them, + you should NOT meddle with the compression or decompression + machinery. Incorrect changes can and very likely *will* + lead to disastrous loss of data. + + +DISCLAIMER: + + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the complexity + of the algorithms, and, in particular, the presence of various + special cases in the code which occur with very low but non-zero + probability make it impossible to rule out the possibility of bugs + remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS + PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER + SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. + Indeed, I very much hope the opposite is true. bzip2/libbzip2 + has been carefully constructed and extensively tested. + + +PATENTS: + + To the best of my knowledge, bzip2/libbzip2 does not use any + patented algorithms. However, I do not have the resources + to carry out a patent search. Therefore I cannot give any + guarantee of the above statement. + + + +WHAT'S NEW IN 0.9.0 (as compared to 0.1pl2) ? + + * Approx 10% faster compression, 30% faster decompression + * -t (test mode) is a lot quicker + * Can decompress concatenated compressed files + * Programming interface, so programs can directly read/write .bz2 files + * Less restrictive (BSD-style) licensing + * Flag handling more compatible with GNU gzip + * Much more documentation, i.e., a proper user manual + * Hopefully, improved portability (at least of the library) + +WHAT'S NEW IN 0.9.5 ? + + * Compression speed is much less sensitive to the input + data than in previous versions. Specifically, the very + slow performance caused by repetitive data is fixed. + * Many small improvements in file and flag handling. + * A Y2K statement. + +WHAT'S NEW IN 1.0.0 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.2 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.3 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.4 ? + + See the CHANGES file. + + +I hope you find bzip2 useful. Feel free to contact me at + jseward@bzip.org +if you have any suggestions or queries. Many people mailed me with +comments, suggestions and patches after the releases of bzip-0.15, +bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, +1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this +feedback. I thank you for your comments. + +bzip2's "home" is http://www.bzip.org/ + +Julian Seward +jseward@bzip.org +Cambridge, UK. + +18 July 1996 (version 0.15) +25 August 1996 (version 0.21) + 7 August 1997 (bzip2, version 0.1) +29 August 1997 (bzip2, version 0.1pl2) +23 August 1998 (bzip2, version 0.9.0) + 8 June 1999 (bzip2, version 0.9.5) + 4 Sept 1999 (bzip2, version 0.9.5d) + 5 May 2000 (bzip2, version 1.0pre8) +30 December 2001 (bzip2, version 1.0.2pre1) +15 February 2005 (bzip2, version 1.0.3) +20 December 2006 (bzip2, version 1.0.4) diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/blocksort.c b/plugins/CDVDiso/src/3rdparty/bzip2/blocksort.c new file mode 100644 index 0000000000..aceb5e9508 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/bzip2/blocksort.c @@ -0,0 +1,1094 @@ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +void fallbackSimpleSort ( UInt32* fmap, + UInt32* eclass, + Int32 lo, + Int32 hi ) +{ + Int32 i, j, tmp; + UInt32 ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for ( i = hi-4; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for ( i = hi-1; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define fvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + fswap(fmap[yyp1], fmap[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + + +#define fmin(a,b) ((a) < (b)) ? (a) : (b) + +#define fpush(lz,hz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; } + +#define fpop(lz,hz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; } + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + + +static +void fallbackQSort3 ( UInt32* fmap, + UInt32* eclass, + Int32 loSt, + Int32 hiSt ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m; + Int32 sp, lo, hi; + UInt32 med, r, r3; + Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; + Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush ( loSt, hiSt ); + + while (sp > 0) { + + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); + + fpop ( lo, hi ); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort ( fmap, eclass, lo, hi ); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + avoid bad cases. Median of 9 seems to help but + looks rather expensive. This too seems to work but + is cheaper. Guidance for the magic constants + 7621 and 32768 is taken from Sedgewick's algorithms + book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) med = eclass[fmap[lo]]; else + if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unLo]] - (Int32)med; + if (n == 0) { + fswap(fmap[unLo], fmap[ltLo]); + ltLo++; unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unHi]] - (Int32)med; + if (n == 0) { + fswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); + + if (gtHi < ltLo) continue; + + n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); + m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush ( lo, n ); + fpush ( m, hi ); + } else { + fpush ( m, hi ); + fpush ( lo, n ); + } + } +} + +#undef fmin +#undef fpush +#undef fpop +#undef fswap +#undef fvswap +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + eclass exists for [0 .. nblock-1] + ((UChar*)eclass) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)eclass) [0 .. nblock-1] holds block + All other areas of eclass destroyed + fmap [0 .. nblock-1] holds sorted order + bhtab [ 0 .. 2+(nblock/32) ] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort ( UInt32* fmap, + UInt32* eclass, + UInt32* bhtab, + Int32 nblock, + Int32 verb ) +{ + Int32 ftab[257]; + Int32 ftabCopy[256]; + Int32 H, i, j, k, l, r, cc, cc1; + Int32 nNotDone; + Int32 nBhtab; + UChar* eclass8 = (UChar*)eclass; + + /*-- + Initial 1-char radix sort to generate + initial fmap and initial BH bits. + --*/ + if (verb >= 4) + VPrintf0 ( " bucket sorting ...\n" ); + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + (nblock / 32); + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /*-- + Inductively refine the buckets. Kind-of an + "exponential radix sort" (!), inspired by the + Manber-Myers suffix array construction algorithm. + --*/ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + + if (verb >= 4) + VPrintf1 ( " depth %6d has ", H ); + + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) j = i; + k = fmap[i] - H; if (k < 0) k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3 ( fmap, eclass, l, r ); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { SET_BH(i); cc = cc1; }; + } + } + } + + if (verb >= 4) + VPrintf1 ( "%6d unresolved strings\n", nNotDone ); + + H *= 2; + if (H > nblock || nNotDone == 0) break; + } + + /*-- + Reconstruct the original block in + eclass8 [0 .. nblock-1], since the + previous phase destroyed it. + --*/ + if (verb >= 4) + VPrintf0 ( " reconstructing block ...\n" ); + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (UChar)j; + } + AssertH ( j < 256, 1005 ); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +Bool mainGtU ( UInt32 i1, + UInt32 i2, + UChar* block, + UInt16* quadrant, + UInt32 nblock, + Int32* budget ) +{ + Int32 k; + UChar c1, c2; + UInt16 s1, s2; + + AssertD ( i1 != i2, "mainGtU" ); + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 9 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 10 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 11 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 12 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + + k = nblock + 8; + + do { + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + k -= 8; + (*budget)--; + } + while (k >= 0); + + return False; +} + + +/*---------------------------------------------*/ +/*-- + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. +--*/ +static +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + +static +void mainSimpleSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 lo, + Int32 hi, + Int32 d, + Int32* budget ) +{ + Int32 i, j, h, bigN, hp; + UInt32 v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (True) { + + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/*-- + The following is an implementation of + an elegant 3-way quicksort for strings, + described in a paper "Fast Algorithms for + Sorting and Searching Strings", by Robert + Sedgewick and Jon L. Bentley. +--*/ + +#define mswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define mvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + mswap(ptr[yyp1], ptr[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + +static +__inline__ +UChar mmed3 ( UChar a, UChar b, UChar c ) +{ + UChar t; + if (a > b) { t = a; a = b; b = t; }; + if (b > c) { + b = c; + if (a > b) b = a; + } + return b; +} + +#define mmin(a,b) ((a) < (b)) ? (a) : (b) + +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; } + +#define mpop(lz,hz,dz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; } + + +#define mnextsize(az) (nextHi[az]-nextLo[az]) + +#define mnextswap(az,bz) \ + { Int32 tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } + + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static +void mainQSort3 ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 loSt, + Int32 hiSt, + Int32 dSt, + Int32* budget ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m, med; + Int32 sp, lo, hi, d; + + Int32 stackLo[MAIN_QSORT_STACK_SIZE]; + Int32 stackHi[MAIN_QSORT_STACK_SIZE]; + Int32 stackD [MAIN_QSORT_STACK_SIZE]; + + Int32 nextLo[3]; + Int32 nextHi[3]; + Int32 nextD [3]; + + sp = 0; + mpush ( loSt, hiSt, dSt ); + + while (sp > 0) { + + AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); + + mpop ( lo, hi, d ); + if (hi - lo < MAIN_QSORT_SMALL_THRESH || + d > MAIN_QSORT_DEPTH_THRESH) { + mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); + if (*budget < 0) return; + continue; + } + + med = (Int32) + mmed3 ( block[ptr[ lo ]+d], + block[ptr[ hi ]+d], + block[ptr[ (lo+hi)>>1 ]+d] ); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (True) { + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; unLo++; continue; + }; + if (n > 0) break; + unLo++; + } + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; unHi--; continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "mainQSort3(2)" ); + + if (gtHi < ltLo) { + mpush(lo, hi, d+1 ); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); + + mpush (nextLo[0], nextHi[0], nextD[0]); + mpush (nextLo[1], nextHi[1], nextD[1]); + mpush (nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mswap +#undef mvswap +#undef mpush +#undef mpop +#undef mmin +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > N_OVERSHOOT + block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)block32) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)block32) [0 .. nblock-1] holds block + All other areas of block32 destroyed + ftab [0 .. 65536 ] destroyed + ptr [0 .. nblock-1] holds sorted order + if (*budget < 0), sorting was abandoned +*/ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static +void mainSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + UInt32* ftab, + Int32 nblock, + Int32 verb, + Int32* budget ) +{ + Int32 i, j, k, ss, sb; + Int32 runningOrder[256]; + Bool bigDone[256]; + Int32 copyStart[256]; + Int32 copyEnd [256]; + UChar c1; + Int32 numQSorted; + UInt16 s; + if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); + + /*-- set up the 2-byte frequency table --*/ + for (i = 65536; i >= 0; i--) ftab[i] = 0; + + j = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); + ftab[j]++; + } + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); + + /*-- Complete the initial radix sort --*/ + for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; + + s = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-3; + } + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + } + + /*-- + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + --*/ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + Int32 vv; + Int32 h = 1; + do h = 3 * h + 1; while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /*-- + The main sorting loop. + --*/ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /*-- + Process big buckets, starting with the least full. + Basically this is a 3-step process in which we call + mainQSort3 to sort the small buckets [ss, j], but + also make a big effort to avoid the calls if we can. + --*/ + ss = runningOrder[i]; + + /*-- + Step 1: + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j], for j != ss. + Hopefully previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + --*/ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if ( ! (ftab[sb] & SETMASK) ) { + Int32 lo = ftab[sb] & CLEARMASK; + Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + if (verb >= 4) + VPrintf4 ( " qsort [0x%x, 0x%x] " + "done %d this %d\n", + ss, j, numQSorted, hi - lo + 1 ); + mainQSort3 ( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + numQSorted += (hi - lo + 1); + if (*budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH ( !bigDone[ss], 1006 ); + + /*-- + Step 2: + Now scan this big bucket [ss] so as to synthesise the + sorted order for small buckets [t, ss] for all t, + including, magically, the bucket [ss,ss] too. + This will avoid doing Real Work in subsequent Step 1's. + --*/ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyStart[c1]++ ] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyEnd[c1]-- ] = k; + } + } + + AssertH ( (copyStart[ss]-1 == copyEnd[ss]) + || + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + Necessity for this case is demonstrated by compressing + a sequence of approximately 48.5 million of character + 251; 1.0.0/1.0.1 will then die here. */ + (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), + 1007 ) + + for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; + + /*-- + Step 3: + The [ss] big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + + The quadrant array provides a way to incrementally + cache sort orderings, as they appear, so as to + make subsequent comparisons in fullGtU() complete + faster. For repetitive blocks this makes a big + difference (but not big enough to be able to avoid + the fallback sorting mechanism, exponential radix sort). + + The precise meaning is: at all times: + + for 0 <= i < nblock and 0 <= j <= nblock + + if block[i] != block[j], + + then the relative values of quadrant[i] and + quadrant[j] are meaningless. + + else { + if quadrant[i] < quadrant[j] + then the string starting at i lexicographically + precedes the string starting at j + + else if quadrant[i] > quadrant[j] + then the string starting at j lexicographically + precedes the string starting at i + + else + the relative ordering of the strings starting + at i and j has not yet been determined. + } + --*/ + bigDone[ss] = True; + + if (i < 255) { + Int32 bbStart = ftab[ss << 8] & CLEARMASK; + Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + Int32 shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + Int32 a2update = ptr[bbStart + j]; + UInt16 qVal = (UInt16)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); + } + + } + + if (verb >= 4) + VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", + nblock, numQSorted, nblock - numQSorted ); +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)arr2) [0 .. nblock-1] holds block + arr1 exists for [0 .. nblock-1] + + Post: + ((UChar*)arr2) [0 .. nblock-1] holds block + All other areas of block destroyed + ftab [ 0 .. 65536 ] destroyed + arr1 [0 .. nblock-1] holds sorted order +*/ +void BZ2_blockSort ( EState* s ) +{ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt32* ftab = s->ftab; + Int32 nblock = s->nblock; + Int32 verb = s->verbosity; + Int32 wfact = s->workFactor; + UInt16* quadrant; + Int32 budget; + Int32 budgetInit; + Int32 i; + + if (nblock < 10000) { + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } else { + /* Calculate the location for quadrant, remembering to get + the alignment right. Assumes that &(block[0]) is at least + 2-byte aligned -- this should be ok since block is really + the first section of arr2. + */ + i = nblock+BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (UInt16*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + transition point at very roughly the same place as + with v0.1 and v0.9.0. + Not that it particularly matters any more, since the + resulting compressed stream is now the same regardless + of whether or not we use the main sort or fallback sort. + */ + if (wfact < 1 ) wfact = 1; + if (wfact > 100) wfact = 100; + budgetInit = nblock * ((wfact-1) / 3); + budget = budgetInit; + + mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); + if (verb >= 3) + VPrintf3 ( " %d work, %d block, ratio %5.2f\n", + budgetInit - budget, + nblock, + (float)(budgetInit - budget) / + (float)(nblock==0 ? 1 : nblock) ); + if (budget < 0) { + if (verb >= 2) + VPrintf0 ( " too repetitive; using fallback" + " sorting algorithm\n" ); + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) + { s->origPtr = i; break; }; + + AssertH( s->origPtr != -1, 1003 ); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.c b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.c new file mode 100644 index 0000000000..5b70a84bbc --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.c @@ -0,0 +1,1571 @@ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). + fixed bzWrite/bzRead to ignore zero-length requests. + fixed bzread to correctly handle read requests after EOF. + wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +#ifndef BZ_NO_STDIO +void BZ2_bz__AssertH__fail ( int errcode ) +{ + fprintf(stderr, + "\n\nbzip2/libbzip2: internal error number %d.\n" + "This is a bug in bzip2/libbzip2, %s.\n" + "Please report it to me at: jseward@bzip.org. If this happened\n" + "when you were using some program which uses libbzip2 as a\n" + "component, you should also report this bug to the author(s)\n" + "of that program. Please make an effort to report this bug;\n" + "timely and accurate bug reports eventually lead to higher\n" + "quality software. Thanks. Julian Seward, 15 February 2005.\n\n", + errcode, + BZ2_bzlibVersion() + ); + + if (errcode == 1007) { + fprintf(stderr, + "\n*** A special note about internal error number 1007 ***\n" + "\n" + "Experience suggests that a common cause of i.e. 1007\n" + "is unreliable memory or other hardware. The 1007 assertion\n" + "just happens to cross-check the results of huge numbers of\n" + "memory reads/writes, and so acts (unintendedly) as a stress\n" + "test of your memory system.\n" + "\n" + "I suggest the following: try compressing the file again,\n" + "possibly monitoring progress in detail with the -vv flag.\n" + "\n" + "* If the error cannot be reproduced, and/or happens at different\n" + " points in compression, you may have a flaky memory system.\n" + " Try a memory-test program. I have used Memtest86\n" + " (www.memtest86.com). At the time of writing it is free (GPLd).\n" + " Memtest86 tests memory much more thorougly than your BIOSs\n" + " power-on test, and may find failures that the BIOS doesn't.\n" + "\n" + "* If the error can be repeatably reproduced, this is a bug in\n" + " bzip2, and I would very much like to hear about it. Please\n" + " let me know, and, ideally, save a copy of the file causing the\n" + " problem -- without which I will be unable to investigate it.\n" + "\n" + ); + } + + exit(3); +} +#endif + + +/*---------------------------------------------------*/ +static +int bz_config_ok ( void ) +{ + if (sizeof(int) != 4) return 0; + if (sizeof(short) != 2) return 0; + if (sizeof(char) != 1) return 0; + return 1; +} + + +/*---------------------------------------------------*/ +static +void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) +{ + void* v = malloc ( items * size ); + return v; +} + +static +void default_bzfree ( void* opaque, void* addr ) +{ + if (addr != NULL) free ( addr ); +} + + +/*---------------------------------------------------*/ +static +void prepare_new_block ( EState* s ) +{ + Int32 i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC ( s->blockCRC ); + for (i = 0; i < 256; i++) s->inUse[i] = False; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +void init_RL ( EState* s ) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +Bool isempty_RL ( EState* s ) +{ + if (s->state_in_ch < 256 && s->state_in_len > 0) + return False; else + return True; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressInit) + ( bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 n; + EState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL || + blockSize100k < 1 || blockSize100k > 9 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(EState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + + s->arr1 = NULL; + s->arr2 = NULL; + s->ftab = NULL; + + n = 100000 * blockSize100k; + s->arr1 = BZALLOC( n * sizeof(UInt32) ); + s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); + s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); + + if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + if (s != NULL) BZFREE(s); + return BZ_MEM_ERROR; + } + + s->blockNo = 0; + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->combinedCRC = 0; + s->blockSize100k = blockSize100k; + s->nblockMAX = 100000 * blockSize100k - 19; + s->verbosity = verbosity; + s->workFactor = workFactor; + + s->block = (UChar*)s->arr2; + s->mtfv = (UInt16*)s->arr1; + s->zbits = NULL; + s->ptr = (UInt32*)s->arr1; + + strm->state = s; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + init_RL ( s ); + prepare_new_block ( s ); + return BZ_OK; +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block ( EState* s ) +{ + Int32 i; + UChar ch = (UChar)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC( s->blockCRC, ch ); + } + s->inUse[s->state_in_ch] = True; + switch (s->state_in_len) { + case 1: + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 2: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 3: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len-4] = True; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = ((UChar)(s->state_in_len-4)); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL ( EState* s ) +{ + if (s->state_in_ch < 256) add_pair_to_block ( s ); + init_RL ( s ); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ +{ \ + UInt32 zchh = (UInt32)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && \ + zs->state_in_len == 1) { \ + UChar ch = (UChar)(zs->state_in_ch); \ + BZ_UPDATE_CRC( zs->blockCRC, ch ); \ + zs->inUse[zs->state_in_ch] = True; \ + zs->block[zs->nblock] = (UChar)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || \ + zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block ( zs ); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +Bool copy_input_until_stop ( EState* s ) +{ + Bool progress_in = False; + + if (s->mode == BZ_M_RUNNING) { + + /*-- fast track the common case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + } + + } else { + + /*-- general, uncommon case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- flush/finish end? --*/ + if (s->avail_in_expect == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + s->avail_in_expect--; + } + } + return progress_in; +} + + +/*---------------------------------------------------*/ +static +Bool copy_output_until_stop ( EState* s ) +{ + Bool progress_out = False; + + while (True) { + + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + progress_out = True; + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + return progress_out; +} + + +/*---------------------------------------------------*/ +static +Bool handle_compress ( bz_stream* strm ) +{ + Bool progress_in = False; + Bool progress_out = False; + EState* s = strm->state; + + while (True) { + + if (s->state == BZ_S_OUTPUT) { + progress_out |= copy_output_until_stop ( s ); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + prepare_new_block ( s ); + s->state = BZ_S_INPUT; + if (s->mode == BZ_M_FLUSHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + } + + if (s->state == BZ_S_INPUT) { + progress_in |= copy_input_until_stop ( s ); + if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + flush_RL ( s ); + BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); + s->state = BZ_S_OUTPUT; + } + else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock ( s, False ); + s->state = BZ_S_OUTPUT; + } + else + if (s->strm->avail_in == 0) { + break; + } + } + + } + + return progress_in || progress_out; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) +{ + Bool progress; + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + preswitch: + switch (s->mode) { + + case BZ_M_IDLE: + return BZ_SEQUENCE_ERROR; + + case BZ_M_RUNNING: + if (action == BZ_RUN) { + progress = handle_compress ( strm ); + return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; + } + else + if (action == BZ_FLUSH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto preswitch; + } + else + if (action == BZ_FINISH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto preswitch; + } + else + return BZ_PARAM_ERROR; + + case BZ_M_FLUSHING: + if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; + + case BZ_M_FINISHING: + if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (!progress) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FINISH_OK; + s->mode = BZ_M_IDLE; + return BZ_STREAM_END; + } + return BZ_OK; /*--not reached--*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) +{ + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + BZFREE(strm->state); + + strm->state = NULL; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/*--- Decompression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressInit) + ( bz_stream* strm, + int verbosity, + int small ) +{ + DState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL) return BZ_PARAM_ERROR; + if (small != 0 && small != 1) return BZ_PARAM_ERROR; + if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; + + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(DState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + strm->state = s; + s->state = BZ_X_MAGIC_1; + s->bsLive = 0; + s->bsBuff = 0; + s->calculatedCombinedCRC = 0; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + s->smallDecompress = (Bool)small; + s->ll4 = NULL; + s->ll16 = NULL; + s->tt = NULL; + s->currBlockNo = 0; + s->verbosity = verbosity; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_FAST ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + /* restore */ + UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; + UChar c_state_out_ch = s->state_out_ch; + Int32 c_state_out_len = s->state_out_len; + Int32 c_nblock_used = s->nblock_used; + Int32 c_k0 = s->k0; + UInt32* c_tt = s->tt; + UInt32 c_tPos = s->tPos; + char* cs_next_out = s->strm->next_out; + unsigned int cs_avail_out = s->strm->avail_out; + /* end restore */ + + UInt32 avail_out_INIT = cs_avail_out; + Int32 s_save_nblockPP = s->save_nblock+1; + unsigned int total_out_lo32_old; + + while (True) { + + /* try to finish existing run */ + if (c_state_out_len > 0) { + while (True) { + if (cs_avail_out == 0) goto return_notr; + if (c_state_out_len == 1) break; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + c_state_out_len--; + cs_next_out++; + cs_avail_out--; + } + s_state_out_len_eq_one: + { + if (cs_avail_out == 0) { + c_state_out_len = 1; goto return_notr; + }; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + cs_next_out++; + cs_avail_out--; + } + } + /* Only caused by corrupt data stream? */ + if (c_nblock_used > s_save_nblockPP) + return True; + + /* can a new run be started? */ + if (c_nblock_used == s_save_nblockPP) { + c_state_out_len = 0; goto return_notr; + }; + c_state_out_ch = c_k0; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (k1 != c_k0) { + c_k0 = k1; goto s_state_out_len_eq_one; + }; + if (c_nblock_used == s_save_nblockPP) + goto s_state_out_len_eq_one; + + c_state_out_len = 2; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + c_state_out_len = 3; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + BZ_GET_FAST_C(k1); c_nblock_used++; + c_state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST_C(c_k0); c_nblock_used++; + } + + return_notr: + total_out_lo32_old = s->strm->total_out_lo32; + s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); + if (s->strm->total_out_lo32 < total_out_lo32_old) + s->strm->total_out_hi32++; + + /* save */ + s->calculatedBlockCRC = c_calculatedBlockCRC; + s->state_out_ch = c_state_out_ch; + s->state_out_len = c_state_out_len; + s->nblock_used = c_nblock_used; + s->k0 = c_k0; + s->tt = c_tt; + s->tPos = c_tPos; + s->strm->next_out = cs_next_out; + s->strm->avail_out = cs_avail_out; + /* end save */ + } + return False; +} + + + +/*---------------------------------------------------*/ +__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_SMALL ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) +{ + Bool corrupt; + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + while (True) { + if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; + if (s->state == BZ_X_OUTPUT) { + if (s->smallDecompress) + corrupt = unRLE_obuf_to_output_SMALL ( s ); else + corrupt = unRLE_obuf_to_output_FAST ( s ); + if (corrupt) return BZ_DATA_ERROR; + if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { + BZ_FINALISE_CRC ( s->calculatedBlockCRC ); + if (s->verbosity >= 3) + VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, + s->calculatedBlockCRC ); + if (s->verbosity >= 2) VPrintf0 ( "]" ); + if (s->calculatedBlockCRC != s->storedBlockCRC) + return BZ_DATA_ERROR; + s->calculatedCombinedCRC + = (s->calculatedCombinedCRC << 1) | + (s->calculatedCombinedCRC >> 31); + s->calculatedCombinedCRC ^= s->calculatedBlockCRC; + s->state = BZ_X_BLKHDR_1; + } else { + return BZ_OK; + } + } + if (s->state >= BZ_X_MAGIC_1) { + Int32 r = BZ2_decompress ( s ); + if (r == BZ_STREAM_END) { + if (s->verbosity >= 3) + VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", + s->storedCombinedCRC, s->calculatedCombinedCRC ); + if (s->calculatedCombinedCRC != s->storedCombinedCRC) + return BZ_DATA_ERROR; + return r; + } + if (s->state != BZ_X_OUTPUT) return r; + } + } + + AssertH ( 0, 6001 ); + + return 0; /*NOTREACHED*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) +{ + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->tt != NULL) BZFREE(s->tt); + if (s->ll16 != NULL) BZFREE(s->ll16); + if (s->ll4 != NULL) BZFREE(s->ll4); + + BZFREE(strm->state); + strm->state = NULL; + + return BZ_OK; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ +/*--- File I/O stuff ---*/ +/*---------------------------------------------------*/ + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +typedef + struct { + FILE* handle; + Char buf[BZ_MAX_UNUSED]; + Int32 bufN; + Bool writing; + bz_stream strm; + Int32 lastErr; + Bool initialisedOk; + } + bzFile; + + +/*---------------------------------------------*/ +static Bool myfeof ( FILE* f ) +{ + Int32 c = fgetc ( f ); + if (c == EOF) return True; + ungetc ( c, f ); + return False; +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzWriteOpen) + ( int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 ret; + bzFile* bzf = NULL; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (blockSize100k < 1 || blockSize100k > 9) || + (workFactor < 0 || workFactor > 250) || + (verbosity < 0 || verbosity > 4)) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + bzf->initialisedOk = False; + bzf->bufN = 0; + bzf->handle = f; + bzf->writing = True; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + if (workFactor == 0) workFactor = 30; + ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = 0; + bzf->initialisedOk = True; + return bzf; +} + + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWrite) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return; }; + + bzf->strm.avail_in = len; + bzf->strm.next_in = buf; + + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); + if (ret != BZ_RUN_OK) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (bzf->strm.avail_in == 0) + { BZ_SETERR(BZ_OK); return; }; + } +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWriteClose) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ) +{ + BZ2_bzWriteClose64 ( bzerror, b, abandon, + nbytes_in, NULL, nbytes_out, NULL ); +} + + +void BZ_API(BZ2_bzWriteClose64) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; + if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; + if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; + if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; + + if ((!abandon) && bzf->lastErr == BZ_OK) { + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (ret == BZ_STREAM_END) break; + } + } + + if ( !abandon && !ferror ( bzf->handle ) ) { + fflush ( bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (nbytes_in_lo32 != NULL) + *nbytes_in_lo32 = bzf->strm.total_in_lo32; + if (nbytes_in_hi32 != NULL) + *nbytes_in_hi32 = bzf->strm.total_in_hi32; + if (nbytes_out_lo32 != NULL) + *nbytes_out_lo32 = bzf->strm.total_out_lo32; + if (nbytes_out_hi32 != NULL) + *nbytes_out_hi32 = bzf->strm.total_out_hi32; + + BZ_SETERR(BZ_OK); + BZ2_bzCompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzReadOpen) + ( int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused ) +{ + bzFile* bzf = NULL; + int ret; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (small != 0 && small != 1) || + (verbosity < 0 || verbosity > 4) || + (unused == NULL && nUnused != 0) || + (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + + bzf->initialisedOk = False; + bzf->handle = f; + bzf->bufN = 0; + bzf->writing = False; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + while (nUnused > 0) { + bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; + unused = ((void*)( 1 + ((UChar*)(unused)) )); + nUnused--; + } + + ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + + bzf->initialisedOk = True; + return bzf; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) +{ + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + + if (bzf->initialisedOk) + (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzRead) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return 0; }; + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (True) { + + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread ( bzf->buf, sizeof(UChar), + BZ_MAX_UNUSED, bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + + if (ret != BZ_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return 0; }; + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) + { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; + + if (ret == BZ_STREAM_END) + { BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; }; + if (bzf->strm.avail_out == 0) + { BZ_SETERR(BZ_OK); return len; }; + + } + + return 0; /*not reached*/ +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadGetUnused) + ( int* bzerror, + BZFILE* b, + void** unused, + int* nUnused ) +{ + bzFile* bzf = (bzFile*)b; + if (bzf == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (bzf->lastErr != BZ_STREAM_END) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (unused == NULL || nUnused == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + + BZ_SETERR(BZ_OK); + *nUnused = bzf->strm.avail_in; + *unused = bzf->strm.next_in; +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffCompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + blockSize100k < 1 || blockSize100k > 9 || + verbosity < 0 || verbosity > 4 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzCompressInit ( &strm, blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress ( &strm, BZ_FINISH ); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd ( &strm ); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffDecompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + (small != 0 && small != 1) || + verbosity < 0 || verbosity > 4) + return BZ_PARAM_ERROR; + + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzDecompress ( &strm ); + if (ret == BZ_OK) goto output_overflow_or_eof; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzDecompressEnd ( &strm ); + return BZ_OK; + + output_overflow_or_eof: + if (strm.avail_out > 0) { + BZ2_bzDecompressEnd ( &strm ); + return BZ_UNEXPECTED_EOF; + } else { + BZ2_bzDecompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + }; + + errhandler: + BZ2_bzDecompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +/*-- + return version like "0.9.5d, 4-Sept-1999". +--*/ +const char * BZ_API(BZ2_bzlibVersion)(void) +{ + return BZ_VERSION; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ + +#if defined(_WIN32) || defined(OS2) || defined(MSDOS) +# include +# include +# define SET_BINARY_MODE(file) _setmode(_fileno(file),O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif +static +BZFILE * bzopen_or_bzdopen + ( const char *path, /* no use when bzdopen */ + int fd, /* no use when bzdopen */ + const char *mode, + int open_mode) /* bzopen: 0, bzdopen:1 */ +{ + int bzerr; + char unused[BZ_MAX_UNUSED]; + int blockSize100k = 9; + int writing = 0; + char mode2[10] = ""; + FILE *fp = NULL; + BZFILE *bzfp = NULL; + int verbosity = 0; + int workFactor = 30; + int smallMode = 0; + int nUnused = 0; + + if (mode == NULL) return NULL; + while (*mode) { + switch (*mode) { + case 'r': + writing = 0; break; + case 'w': + writing = 1; break; + case 's': + smallMode = 1; break; + default: + if (isdigit((int)(*mode))) { + blockSize100k = *mode-BZ_HDR_0; + } + } + mode++; + } + strcat(mode2, writing ? "w" : "r" ); + strcat(mode2,"b"); /* binary mode */ + + if (open_mode==0) { + if (path==NULL || strcmp(path,"")==0) { + fp = (writing ? stdout : stdin); + SET_BINARY_MODE(fp); + } else { + fp = fopen(path,mode2); + } + } else { +#ifdef BZ_STRICT_ANSI + fp = NULL; +#else + fp = _fdopen(fd,mode2); +#endif + } + if (fp == NULL) return NULL; + + if (writing) { + /* Guard against total chaos and anarchy -- JRS */ + if (blockSize100k < 1) blockSize100k = 1; + if (blockSize100k > 9) blockSize100k = 9; + bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, + verbosity,workFactor); + } else { + bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, + unused,nUnused); + } + if (bzfp == NULL) { + if (fp != stdin && fp != stdout) fclose(fp); + return NULL; + } + return bzfp; +} + + +/*---------------------------------------------------*/ +/*-- + open file for read or write. + ex) bzopen("file","w9") + case path="" or NULL => use stdin or stdout. +--*/ +BZFILE * BZ_API(BZ2_bzopen) + ( const char *path, + const char *mode ) +{ + return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); +} + + +/*---------------------------------------------------*/ +BZFILE * BZ_API(BZ2_bzdopen) + ( int fd, + const char *mode ) +{ + return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) +{ + int bzerr, nread; + if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; + nread = BZ2_bzRead(&bzerr,b,buf,len); + if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { + return nread; + } else { + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) +{ + int bzerr; + + BZ2_bzWrite(&bzerr,b,buf,len); + if(bzerr == BZ_OK){ + return len; + }else{ + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzflush) (BZFILE *b) +{ + /* do nothing now... */ + return 0; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzclose) (BZFILE* b) +{ + int bzerr; + FILE *fp; + + if (b==NULL) {return;} + fp = ((bzFile *)b)->handle; + if(((bzFile*)b)->writing){ + BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); + if(bzerr != BZ_OK){ + BZ2_bzWriteClose(NULL,b,1,NULL,NULL); + } + }else{ + BZ2_bzReadClose(&bzerr,b); + } + if(fp!=stdin && fp!=stdout){ + fclose(fp); + } +} + + +/*---------------------------------------------------*/ +/*-- + return last error code +--*/ +static const char *bzerrorstrings[] = { + "OK" + ,"SEQUENCE_ERROR" + ,"PARAM_ERROR" + ,"MEM_ERROR" + ,"DATA_ERROR" + ,"DATA_ERROR_MAGIC" + ,"IO_ERROR" + ,"UNEXPECTED_EOF" + ,"OUTBUFF_FULL" + ,"CONFIG_ERROR" + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ +}; + + +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) +{ + int err = ((bzFile *)b)->lastErr; + + if(err>0) err = 0; + *errnum = err; + return bzerrorstrings[err*-1]; +} +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.h b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.h new file mode 100644 index 0000000000..941c9c5908 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib.h @@ -0,0 +1,282 @@ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_H +#define _BZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef + struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; + } + bz_stream; + + +#ifndef BZ_IMPORT +#define BZ_EXPORT +#endif + +#ifndef BZ_NO_STDIO +/* Need a definitition for FILE */ +#include +#endif + +#ifdef _WIN32 +# include +# ifdef small + /* windows.h define small to char */ +# undef small +# endif +# ifdef BZ_EXPORT +# define BZ_API(func) WINAPI func +# define BZ_EXTERN extern +# else + /* import windows dll dynamically */ +# define BZ_API(func) (WINAPI * func) +# define BZ_EXTERN +# endif +#else +# define BZ_API(func) func +# define BZ_EXTERN extern +#endif + + +/*-- Core (low-level) library functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( + bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( + bz_stream* strm, + int action + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( + bz_stream *strm, + int verbosity, + int small + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( + bz_stream *strm + ); + + + +/*-- High(er) level library functions --*/ + +#ifndef BZ_NO_STDIO +#define BZ_MAX_UNUSED 5000 + +typedef void BZFILE; + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( + int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( + int* bzerror, + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( + int* bzerror, + BZFILE* b, + void** unused, + int* nUnused + ); + +BZ_EXTERN int BZ_API(BZ2_bzRead) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( + int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 + ); +#endif + + +/*-- Utility functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity + ); + + +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ + +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( + void + ); + +#ifndef BZ_NO_STDIO +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( + const char *path, + const char *mode + ); + +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( + int fd, + const char *mode + ); + +BZ_EXTERN int BZ_API(BZ2_bzread) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzwrite) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzflush) ( + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzclose) ( + BZFILE* b + ); + +BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( + BZFILE *b, + int *errnum + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/bzlib_private.h b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib_private.h new file mode 100644 index 0000000000..df7a22dd31 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/bzip2/bzlib_private.h @@ -0,0 +1,503 @@ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_PRIVATE_H +#define _BZLIB_PRIVATE_H + +#include + +#ifndef BZ_NO_STDIO +#include +#include +#include +#endif + +#include "bzlib.h" + + + +/*-- General stuff. --*/ + +#define BZ_VERSION "1.0.4, 20-Dec-2006" + +typedef char Char; +typedef unsigned char Bool; +typedef unsigned char UChar; +typedef int Int32; +typedef unsigned int UInt32; +typedef short Int16; +typedef unsigned short UInt16; + +#define True ((Bool)1) +#define False ((Bool)0) + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef BZ_NO_STDIO + +extern void BZ2_bz__AssertH__fail ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } + +#if BZ_DEBUG +#define AssertD(cond,msg) \ + { if (!(cond)) { \ + fprintf ( stderr, \ + "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ + exit(1); \ + }} +#else +#define AssertD(cond,msg) /* */ +#endif + +#define VPrintf0(zf) \ + fprintf(stderr,zf) +#define VPrintf1(zf,za1) \ + fprintf(stderr,zf,za1) +#define VPrintf2(zf,za1,za2) \ + fprintf(stderr,zf,za1,za2) +#define VPrintf3(zf,za1,za2,za3) \ + fprintf(stderr,zf,za1,za2,za3) +#define VPrintf4(zf,za1,za2,za3,za4) \ + fprintf(stderr,zf,za1,za2,za3,za4) +#define VPrintf5(zf,za1,za2,za3,za4,za5) \ + fprintf(stderr,zf,za1,za2,za3,za4,za5) + +#else + +extern void bz_internal_error ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) bz_internal_error ( errcode ); } +#define AssertD(cond,msg) do { } while (0) +#define VPrintf0(zf) do { } while (0) +#define VPrintf1(zf,za1) do { } while (0) +#define VPrintf2(zf,za1,za2) do { } while (0) +#define VPrintf3(zf,za1,za2,za3) do { } while (0) +#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) +#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) + +#endif + + +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) +#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + + +/*-- Stuff for randomising repetitive blocks. --*/ + +extern Int32 BZ2_rNums[512]; + +#define BZ_RAND_DECLS \ + Int32 rNToGo; \ + Int32 rTPos \ + +#define BZ_RAND_INIT_MASK \ + s->rNToGo = 0; \ + s->rTPos = 0 \ + +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) + +#define BZ_RAND_UPD_MASK \ + if (s->rNToGo == 0) { \ + s->rNToGo = BZ2_rNums[s->rTPos]; \ + s->rTPos++; \ + if (s->rTPos == 512) s->rTPos = 0; \ + } \ + s->rNToGo--; + + + +/*-- Stuff for doing CRCs. --*/ + +extern UInt32 BZ2_crc32Table[256]; + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + BZ2_crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + Int32 mode; + Int32 state; + + /* remembers avail_in when flush/finish requested */ + UInt32 avail_in_expect; + + /* for doing the block sorting */ + UInt32* arr1; + UInt32* arr2; + UInt32* ftab; + Int32 origPtr; + + /* aliases for arr1 and arr2 */ + UInt32* ptr; + UChar* block; + UInt16* mtfv; + UChar* zbits; + + /* for deciding when to use the fallback sorting algorithm */ + Int32 workFactor; + + /* run-length-encoding of the input */ + UInt32 state_in_ch; + Int32 state_in_len; + BZ_RAND_DECLS; + + /* input and output limits and current posns */ + Int32 nblock; + Int32 nblockMAX; + Int32 numZ; + Int32 state_out_pos; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + UChar unseqToSeq[256]; + + /* the buffer for bit stream creation */ + UInt32 bsBuff; + Int32 bsLive; + + /* block and combined CRCs */ + UInt32 blockCRC; + UInt32 combinedCRC; + + /* misc administratium */ + Int32 verbosity; + Int32 blockNo; + Int32 blockSize100k; + + /* stuff for coding the MTF values */ + Int32 nMTF; + Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + /* second dimension: only 3 needed; 4 makes index calculations faster */ + UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; + + } + EState; + + + +/*-- externs for compression. --*/ + +extern void +BZ2_blockSort ( EState* ); + +extern void +BZ2_compressBlock ( EState*, Bool ); + +extern void +BZ2_bsInitWrite ( EState* ); + +extern void +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); + +extern void +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); + + + +/*-- states for decompression. --*/ + +#define BZ_X_IDLE 1 +#define BZ_X_OUTPUT 2 + +#define BZ_X_MAGIC_1 10 +#define BZ_X_MAGIC_2 11 +#define BZ_X_MAGIC_3 12 +#define BZ_X_MAGIC_4 13 +#define BZ_X_BLKHDR_1 14 +#define BZ_X_BLKHDR_2 15 +#define BZ_X_BLKHDR_3 16 +#define BZ_X_BLKHDR_4 17 +#define BZ_X_BLKHDR_5 18 +#define BZ_X_BLKHDR_6 19 +#define BZ_X_BCRC_1 20 +#define BZ_X_BCRC_2 21 +#define BZ_X_BCRC_3 22 +#define BZ_X_BCRC_4 23 +#define BZ_X_RANDBIT 24 +#define BZ_X_ORIGPTR_1 25 +#define BZ_X_ORIGPTR_2 26 +#define BZ_X_ORIGPTR_3 27 +#define BZ_X_MAPPING_1 28 +#define BZ_X_MAPPING_2 29 +#define BZ_X_SELECTOR_1 30 +#define BZ_X_SELECTOR_2 31 +#define BZ_X_SELECTOR_3 32 +#define BZ_X_CODING_1 33 +#define BZ_X_CODING_2 34 +#define BZ_X_CODING_3 35 +#define BZ_X_MTF_1 36 +#define BZ_X_MTF_2 37 +#define BZ_X_MTF_3 38 +#define BZ_X_MTF_4 39 +#define BZ_X_MTF_5 40 +#define BZ_X_MTF_6 41 +#define BZ_X_ENDHDR_2 42 +#define BZ_X_ENDHDR_3 43 +#define BZ_X_ENDHDR_4 44 +#define BZ_X_ENDHDR_5 45 +#define BZ_X_ENDHDR_6 46 +#define BZ_X_CCRC_1 47 +#define BZ_X_CCRC_2 48 +#define BZ_X_CCRC_3 49 +#define BZ_X_CCRC_4 50 + + + +/*-- Constants for the fast MTF decoder. --*/ + +#define MTFA_SIZE 4096 +#define MTFL_SIZE 16 + + + +/*-- Structure holding all the decompression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* state indicator for this stream */ + Int32 state; + + /* for doing the final run-length decoding */ + UChar state_out_ch; + Int32 state_out_len; + Bool blockRandomised; + BZ_RAND_DECLS; + + /* the buffer for bit stream reading */ + UInt32 bsBuff; + Int32 bsLive; + + /* misc administratium */ + Int32 blockSize100k; + Bool smallDecompress; + Int32 currBlockNo; + Int32 verbosity; + + /* for undoing the Burrows-Wheeler transform */ + Int32 origPtr; + UInt32 tPos; + Int32 k0; + Int32 unzftab[256]; + Int32 nblock_used; + Int32 cftab[257]; + Int32 cftabCopy[257]; + + /* for undoing the Burrows-Wheeler transform (FAST) */ + UInt32 *tt; + + /* for undoing the Burrows-Wheeler transform (SMALL) */ + UInt16 *ll16; + UChar *ll4; + + /* stored and calculated CRCs */ + UInt32 storedBlockCRC; + UInt32 storedCombinedCRC; + UInt32 calculatedBlockCRC; + UInt32 calculatedCombinedCRC; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + Bool inUse16[16]; + UChar seqToUnseq[256]; + + /* for decoding the MTF values */ + UChar mtfa [MTFA_SIZE]; + Int32 mtfbase[256 / MTFL_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 minLens[BZ_N_GROUPS]; + + /* save area for scalars in the main decompress code */ + Int32 save_i; + Int32 save_j; + Int32 save_t; + Int32 save_alphaSize; + Int32 save_nGroups; + Int32 save_nSelectors; + Int32 save_EOB; + Int32 save_groupNo; + Int32 save_groupPos; + Int32 save_nextSym; + Int32 save_nblockMAX; + Int32 save_nblock; + Int32 save_es; + Int32 save_N; + Int32 save_curr; + Int32 save_zt; + Int32 save_zn; + Int32 save_zvec; + Int32 save_zj; + Int32 save_gSel; + Int32 save_gMinlen; + Int32* save_gLimit; + Int32* save_gBase; + Int32* save_gPerm; + + } + DState; + + + +/*-- Macros for decompression. --*/ + +#define BZ_GET_FAST(cccc) \ + s->tPos = s->tt[s->tPos]; \ + cccc = (UChar)(s->tPos & 0xff); \ + s->tPos >>= 8; + +#define BZ_GET_FAST_C(cccc) \ + c_tPos = c_tt[c_tPos]; \ + cccc = (UChar)(c_tPos & 0xff); \ + c_tPos >>= 8; + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + +#define GET_LL4(i) \ + ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) + +#define SET_LL(i,n) \ + { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + +#define GET_LL(i) \ + (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) + +#define BZ_GET_SMALL(cccc) \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); + + +/*-- externs for decompression. --*/ + +extern Int32 +BZ2_indexIntoF ( Int32, Int32* ); + +extern Int32 +BZ2_decompress ( DState* ); + +extern void +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, + Int32, Int32, Int32 ); + + +#endif + + +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ + +#ifdef BZ_NO_STDIO +#ifndef NULL +#define NULL 0 +#endif +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/compress.c b/plugins/CDVDiso/src/3rdparty/bzip2/compress.c new file mode 100644 index 0000000000..7be1976f69 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/bzip2/compress.c @@ -0,0 +1,672 @@ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- changed setting of nGroups in sendMTFValues() + so as to do a bit better on small files +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +void BZ2_bsInitWrite ( EState* s ) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static +void bsFinishWrite ( EState* s ) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +#define bsNEEDW(nz) \ +{ \ + while (s->bsLive >= 8) { \ + s->zbits[s->numZ] \ + = (UChar)(s->bsBuff >> 24); \ + s->numZ++; \ + s->bsBuff <<= 8; \ + s->bsLive -= 8; \ + } \ +} + + +/*---------------------------------------------------*/ +static +__inline__ +void bsW ( EState* s, Int32 n, UInt32 v ) +{ + bsNEEDW ( n ); + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutUInt32 ( EState* s, UInt32 u ) +{ + bsW ( s, 8, (u >> 24) & 0xffL ); + bsW ( s, 8, (u >> 16) & 0xffL ); + bsW ( s, 8, (u >> 8) & 0xffL ); + bsW ( s, 8, u & 0xffL ); +} + + +/*---------------------------------------------------*/ +static +void bsPutUChar ( EState* s, UChar c ) +{ + bsW( s, 8, (UInt32)c ); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e ( EState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +static +void generateMTFValues ( EState* s ) +{ + UChar yy[256]; + Int32 i, j; + Int32 zPend; + Int32 wr; + Int32 EOB; + + /* + After sorting (eg, here), + s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, + and + ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] + holds the original block data. + + The first thing to do is generate the MTF values, + and put them in + ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. + Because there are strictly fewer or equal MTF values + than block values, ptr values in this area are overwritten + with MTF values only when they are no longer needed. + + The final compressed bitstream is generated into the + area starting at + (UChar*) (&((UChar*)s->arr2)[s->nblock]) + + These storage aliases are set up in bzCompressInit(), + except for the last one, which is arranged in + compressBlock(). + */ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt16* mtfv = s->mtfv; + + makeMaps_e ( s ); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; + + for (i = 0; i < s->nblock; i++) { + UChar ll_i; + AssertD ( wr <= i, "generateMTFValues(1)" ); + j = ptr[i]-1; if (j < 0) j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); + + if (yy[0] == ll_i) { + zPend++; + } else { + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + { + register UChar rtmp; + register UChar* ryy_j; + register UChar rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while ( rll_i != rtmp ) { + register UChar rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; + } + + } + } + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + + mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static +void sendMTFValues ( EState* s ) +{ + Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; + Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; + Int32 nGroups, nBytes; + + /*-- + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + is a global since the decoder also needs it. + + Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + are also globals only used in this proc. + Made global to keep stack frame size small. + --*/ + + + UInt16 cost[BZ_N_GROUPS]; + Int32 fave[BZ_N_GROUPS]; + + UInt16* mtfv = s->mtfv; + + if (s->verbosity >= 3) + VPrintf3( " %d in block, %d after MTF & 1-2 coding, " + "%d+2 syms in use\n", + s->nblock, s->nMTF, s->nInUse ); + + alphaSize = s->nInUse+2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH ( s->nMTF > 0, 3001 ); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + Int32 nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs-1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups-nPart) % 2 == 1)) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + if (s->verbosity >= 3) + VPrintf5( " initial group %d, [%d .. %d], " + "has %d syms (%4.1f%%)\n", + nPart, gs, ge, aFreq, + (100.0 * (float)aFreq) / (float)(s->nMTF) ); + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge+1; + remF -= aFreq; + } + } + + /*--- + Iterate up to BZ_N_ITERS times to improve the tables. + ---*/ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + + for (t = 0; t < nGroups; t++) fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + + /*--- + Set up an auxiliary length table which is used to fast-track + the common case (nGroups == 6). + ---*/ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (True) { + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + + /*-- + Calculate the cost of this group as coded + by each of the coding tables. + --*/ + for (t = 0; t < nGroups; t++) cost[t] = 0; + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register UInt32 cost01, cost23, cost45; + register UInt16 icv; + cost01 = cost23 = cost45 = 0; + +# define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; \ + + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); + +# undef BZ_ITER + + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + UInt16 icv = mtfv[i]; + for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; + } + } + + /*-- + Find the coding table which is best for this group, + and record its identity in the selector table. + --*/ + bc = 999999999; bt = -1; + for (t = 0; t < nGroups; t++) + if (cost[t] < bc) { bc = cost[t]; bt = t; }; + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /*-- + Increment the symbol frequencies for the selected table. + --*/ + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + +# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ + + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); + +# undef BZ_ITUR + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) + s->rfreq[bt][ mtfv[i] ]++; + } + + gs = ge+1; + } + if (s->verbosity >= 3) { + VPrintf2 ( " pass %d: size is %d, grp uses are ", + iter+1, totc/8 ); + for (t = 0; t < nGroups; t++) + VPrintf1 ( "%d ", fave[t] ); + VPrintf0 ( "\n" ); + } + + /*-- + Recompute the tables based on the accumulated frequencies. + --*/ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), + alphaSize, 17 /*20*/ ); + } + + + AssertH( nGroups < 8, 3002 ); + AssertH( nSelectors < 32768 && + nSelectors <= (2 + (900000 / BZ_G_SIZE)), + 3003 ); + + + /*--- Compute MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while ( ll_i != tmp ) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); + AssertH ( !(minLen < 1), 3005 ); + BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), + minLen, maxLen, alphaSize ); + } + + /*--- Transmit the mapping table. ---*/ + { + Bool inUse16[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = False; + for (j = 0; j < 16; j++) + if (s->inUse[i * 16 + j]) inUse16[i] = True; + } + + nBytes = s->numZ; + for (i = 0; i < 16; i++) + if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) { + if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); + } + + if (s->verbosity >= 3) + VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW ( s, 3, nGroups ); + bsW ( s, 15, nSelectors ); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); + bsW(s,1,0); + } + if (s->verbosity >= 3) + VPrintf1( "selectors %d, ", s->numZ-nBytes ); + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + Int32 curr = s->len[t][0]; + bsW ( s, 5, curr ); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; + bsW ( s, 1, 0 ); + } + } + + if (s->verbosity >= 3) + VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (True) { + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + AssertH ( s->selector[selCtr] < nGroups, 3006 ); + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + UInt16 mtfv_i; + UChar* s_len_sel_selCtr + = &(s->len[s->selector[selCtr]][0]); + Int32* s_code_sel_selCtr + = &(s->code[s->selector[selCtr]][0]); + +# define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW ( s, \ + s_len_sel_selCtr[mtfv_i], \ + s_code_sel_selCtr[mtfv_i] ) + + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); + +# undef BZ_ITAH + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + bsW ( s, + s->len [s->selector[selCtr]] [mtfv[i]], + s->code [s->selector[selCtr]] [mtfv[i]] ); + } + } + + + gs = ge+1; + selCtr++; + } + AssertH( selCtr == nSelectors, 3007 ); + + if (s->verbosity >= 3) + VPrintf1( "codes %d\n", s->numZ-nBytes ); +} + + +/*---------------------------------------------------*/ +void BZ2_compressBlock ( EState* s, Bool is_last_block ) +{ + if (s->nblock > 0) { + + BZ_FINALISE_CRC ( s->blockCRC ); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) s->numZ = 0; + + if (s->verbosity >= 2) + VPrintf4( " block %d: crc = 0x%08x, " + "combined CRC = 0x%08x, size = %d\n", + s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); + + BZ2_blockSort ( s ); + } + + s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite ( s ); + bsPutUChar ( s, BZ_HDR_B ); + bsPutUChar ( s, BZ_HDR_Z ); + bsPutUChar ( s, BZ_HDR_h ); + bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); + } + + if (s->nblock > 0) { + + bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); + bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); + bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutUInt32 ( s, s->blockCRC ); + + /*-- + Now a single bit indicating (non-)randomisation. + As of version 0.9.5, we use a better sorting algorithm + which makes randomisation unnecessary. So always set + the randomised bit to 'no'. Of course, the decoder + still needs to be able to handle randomised blocks + so as to maintain backwards compatibility with + older versions of bzip2. + --*/ + bsW(s,1,0); + + bsW ( s, 24, s->origPtr ); + generateMTFValues ( s ); + sendMTFValues ( s ); + } + + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + + bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); + bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); + bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); + bsPutUInt32 ( s, s->combinedCRC ); + if (s->verbosity >= 2) + VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); + bsFinishWrite ( s ); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/crctable.c b/plugins/CDVDiso/src/3rdparty/bzip2/crctable.c new file mode 100644 index 0000000000..5fd7cf6506 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/bzip2/crctable.c @@ -0,0 +1,104 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for doing CRCs ---*/ +/*--- crctable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +UInt32 BZ2_crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, + 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, + 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, + 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, + 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, + 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, + 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, + 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, + 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, + 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, + 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, + 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, + 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, + 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, + 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, + 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, + 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, + 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, + 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, + 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, + 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, + 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, + 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, + 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, + 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, + 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, + 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, + 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, + 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, + 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, + 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, + 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, + 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, + 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, + 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, + 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, + 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, + 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, + 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, + 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, + 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, + 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, + 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, + 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, + 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, + 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, + 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, + 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, + 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, + 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, + 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, + 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, + 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, + 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, + 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, + 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, + 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, + 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, + 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, + 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, + 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, + 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, + 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, + 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L +}; + + +/*-------------------------------------------------------------*/ +/*--- end crctable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/decompress.c b/plugins/CDVDiso/src/3rdparty/bzip2/decompress.c new file mode 100644 index 0000000000..4aa7f53c0c --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/bzip2/decompress.c @@ -0,0 +1,626 @@ + +/*-------------------------------------------------------------*/ +/*--- Decompression machinery ---*/ +/*--- decompress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +static +void makeMaps_d ( DState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->seqToUnseq[s->nInUse] = i; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +#define RETURN(rrr) \ + { retVal = rrr; goto save_state_and_return; }; + +#define GET_BITS(lll,vvv,nnn) \ + case lll: s->state = lll; \ + while (True) { \ + if (s->bsLive >= nnn) { \ + UInt32 v; \ + v = (s->bsBuff >> \ + (s->bsLive-nnn)) & ((1 << nnn)-1); \ + s->bsLive -= nnn; \ + vvv = v; \ + break; \ + } \ + if (s->strm->avail_in == 0) RETURN(BZ_OK); \ + s->bsBuff \ + = (s->bsBuff << 8) | \ + ((UInt32) \ + (*((UChar*)(s->strm->next_in)))); \ + s->bsLive += 8; \ + s->strm->next_in++; \ + s->strm->avail_in--; \ + s->strm->total_in_lo32++; \ + if (s->strm->total_in_lo32 == 0) \ + s->strm->total_in_hi32++; \ + } + +#define GET_UCHAR(lll,uuu) \ + GET_BITS(lll,uuu,8) + +#define GET_BIT(lll,uuu) \ + GET_BITS(lll,uuu,1) + +/*---------------------------------------------------*/ +#define GET_MTF_VAL(label1,label2,lval) \ +{ \ + if (groupPos == 0) { \ + groupNo++; \ + if (groupNo >= nSelectors) \ + RETURN(BZ_DATA_ERROR); \ + groupPos = BZ_G_SIZE; \ + gSel = s->selector[groupNo]; \ + gMinlen = s->minLens[gSel]; \ + gLimit = &(s->limit[gSel][0]); \ + gPerm = &(s->perm[gSel][0]); \ + gBase = &(s->base[gSel][0]); \ + } \ + groupPos--; \ + zn = gMinlen; \ + GET_BITS(label1, zvec, zn); \ + while (1) { \ + if (zn > 20 /* the longest code */) \ + RETURN(BZ_DATA_ERROR); \ + if (zvec <= gLimit[zn]) break; \ + zn++; \ + GET_BIT(label2, zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + if (zvec - gBase[zn] < 0 \ + || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ + RETURN(BZ_DATA_ERROR); \ + lval = gPerm[zvec - gBase[zn]]; \ +} + + +/*---------------------------------------------------*/ +Int32 BZ2_decompress ( DState* s ) +{ + UChar uc; + Int32 retVal; + Int32 minLen, maxLen; + bz_stream* strm = s->strm; + + /* stuff that needs to be saved/restored */ + Int32 i; + Int32 j; + Int32 t; + Int32 alphaSize; + Int32 nGroups; + Int32 nSelectors; + Int32 EOB; + Int32 groupNo; + Int32 groupPos; + Int32 nextSym; + Int32 nblockMAX; + Int32 nblock; + Int32 es; + Int32 N; + Int32 curr; + Int32 zt; + Int32 zn; + Int32 zvec; + Int32 zj; + Int32 gSel; + Int32 gMinlen; + Int32* gLimit; + Int32* gBase; + Int32* gPerm; + + if (s->state == BZ_X_MAGIC_1) { + /*initialise the save area*/ + s->save_i = 0; + s->save_j = 0; + s->save_t = 0; + s->save_alphaSize = 0; + s->save_nGroups = 0; + s->save_nSelectors = 0; + s->save_EOB = 0; + s->save_groupNo = 0; + s->save_groupPos = 0; + s->save_nextSym = 0; + s->save_nblockMAX = 0; + s->save_nblock = 0; + s->save_es = 0; + s->save_N = 0; + s->save_curr = 0; + s->save_zt = 0; + s->save_zn = 0; + s->save_zvec = 0; + s->save_zj = 0; + s->save_gSel = 0; + s->save_gMinlen = 0; + s->save_gLimit = NULL; + s->save_gBase = NULL; + s->save_gPerm = NULL; + } + + /*restore from the save area*/ + i = s->save_i; + j = s->save_j; + t = s->save_t; + alphaSize = s->save_alphaSize; + nGroups = s->save_nGroups; + nSelectors = s->save_nSelectors; + EOB = s->save_EOB; + groupNo = s->save_groupNo; + groupPos = s->save_groupPos; + nextSym = s->save_nextSym; + nblockMAX = s->save_nblockMAX; + nblock = s->save_nblock; + es = s->save_es; + N = s->save_N; + curr = s->save_curr; + zt = s->save_zt; + zn = s->save_zn; + zvec = s->save_zvec; + zj = s->save_zj; + gSel = s->save_gSel; + gMinlen = s->save_gMinlen; + gLimit = s->save_gLimit; + gBase = s->save_gBase; + gPerm = s->save_gPerm; + + retVal = BZ_OK; + + switch (s->state) { + + GET_UCHAR(BZ_X_MAGIC_1, uc); + if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_2, uc); + if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_3, uc) + if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) + if (s->blockSize100k < (BZ_HDR_0 + 1) || + s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); + s->blockSize100k -= BZ_HDR_0; + + if (s->smallDecompress) { + s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); + s->ll4 = BZALLOC( + ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) + ); + if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); + } else { + s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); + if (s->tt == NULL) RETURN(BZ_MEM_ERROR); + } + + GET_UCHAR(BZ_X_BLKHDR_1, uc); + + if (uc == 0x17) goto endhdr_2; + if (uc != 0x31) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_2, uc); + if (uc != 0x41) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_3, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_4, uc); + if (uc != 0x26) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_5, uc); + if (uc != 0x53) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_6, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + + s->currBlockNo++; + if (s->verbosity >= 2) + VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); + + s->storedBlockCRC = 0; + GET_UCHAR(BZ_X_BCRC_1, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_2, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_3, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_4, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + + GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); + + s->origPtr = 0; + GET_UCHAR(BZ_X_ORIGPTR_1, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_2, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_3, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + + if (s->origPtr < 0) + RETURN(BZ_DATA_ERROR); + if (s->origPtr > 10 + 100000*s->blockSize100k) + RETURN(BZ_DATA_ERROR); + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) { + GET_BIT(BZ_X_MAPPING_1, uc); + if (uc == 1) + s->inUse16[i] = True; else + s->inUse16[i] = False; + } + + for (i = 0; i < 256; i++) s->inUse[i] = False; + + for (i = 0; i < 16; i++) + if (s->inUse16[i]) + for (j = 0; j < 16; j++) { + GET_BIT(BZ_X_MAPPING_2, uc); + if (uc == 1) s->inUse[i * 16 + j] = True; + } + makeMaps_d ( s ); + if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); + alphaSize = s->nInUse+2; + + /*--- Now the selectors ---*/ + GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); + if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); + GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); + if (nSelectors < 1) RETURN(BZ_DATA_ERROR); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (True) { + GET_BIT(BZ_X_SELECTOR_3, uc); + if (uc == 0) break; + j++; + if (j >= nGroups) RETURN(BZ_DATA_ERROR); + } + s->selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = s->selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + s->selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + GET_BITS(BZ_X_CODING_1, curr, 5); + for (i = 0; i < alphaSize; i++) { + while (True) { + if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); + GET_BIT(BZ_X_CODING_2, uc); + if (uc == 0) break; + GET_BIT(BZ_X_CODING_3, uc); + if (uc == 0) curr++; else curr--; + } + s->len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + BZ2_hbCreateDecodeTables ( + &(s->limit[t][0]), + &(s->base[t][0]), + &(s->perm[t][0]), + &(s->len[t][0]), + minLen, maxLen, alphaSize + ); + s->minLens[t] = minLen; + } + + /*--- Now the MTF values ---*/ + + EOB = s->nInUse+1; + nblockMAX = 100000 * s->blockSize100k; + groupNo = -1; + groupPos = 0; + + for (i = 0; i <= 255; i++) s->unzftab[i] = 0; + + /*-- MTF init --*/ + { + Int32 ii, jj, kk; + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + /*-- end MTF init --*/ + + nblock = 0; + GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { + + es = -1; + N = 1; + do { + if (nextSym == BZ_RUNA) es = es + (0+1) * N; else + if (nextSym == BZ_RUNB) es = es + (1+1) * N; + N = N * 2; + GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); + } + while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); + + es++; + uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; + s->unzftab[uc] += es; + + if (s->smallDecompress) + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->ll16[nblock] = (UInt16)uc; + nblock++; + es--; + } + else + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->tt[nblock] = (UInt32)uc; + nblock++; + es--; + }; + + continue; + + } else { + + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + + /*-- uc = MTF ( nextSym-1 ) --*/ + { + Int32 ii, jj, kk, pp, lno, off; + UInt32 nn; + nn = (UInt32)(nextSym - 1); + + if (nn < MTFL_SIZE) { + /* avoid general-case expense */ + pp = s->mtfbase[0]; + uc = s->mtfa[pp+nn]; + while (nn > 3) { + Int32 z = pp+nn; + s->mtfa[(z) ] = s->mtfa[(z)-1]; + s->mtfa[(z)-1] = s->mtfa[(z)-2]; + s->mtfa[(z)-2] = s->mtfa[(z)-3]; + s->mtfa[(z)-3] = s->mtfa[(z)-4]; + nn -= 4; + } + while (nn > 0) { + s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; + }; + s->mtfa[pp] = uc; + } else { + /* general case */ + lno = nn / MTFL_SIZE; + off = nn % MTFL_SIZE; + pp = s->mtfbase[lno] + off; + uc = s->mtfa[pp]; + while (pp > s->mtfbase[lno]) { + s->mtfa[pp] = s->mtfa[pp-1]; pp--; + }; + s->mtfbase[lno]++; + while (lno > 0) { + s->mtfbase[lno]--; + s->mtfa[s->mtfbase[lno]] + = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; + lno--; + } + s->mtfbase[0]--; + s->mtfa[s->mtfbase[0]] = uc; + if (s->mtfbase[0] == 0) { + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + } + } + /*-- end uc = MTF ( nextSym-1 ) --*/ + + s->unzftab[s->seqToUnseq[uc]]++; + if (s->smallDecompress) + s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else + s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); + nblock++; + + GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); + continue; + } + } + + /* Now we know what nblock is, we can do a better sanity + check on s->origPtr. + */ + if (s->origPtr < 0 || s->origPtr >= nblock) + RETURN(BZ_DATA_ERROR); + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + s->cftab[0] = 0; + for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; + for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; + for (i = 0; i <= 256; i++) { + if (s->cftab[i] < 0 || s->cftab[i] > nblock) { + /* s->cftab[i] can legitimately be == nblock */ + RETURN(BZ_DATA_ERROR); + } + } + + s->state_out_len = 0; + s->state_out_ch = 0; + BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); + s->state = BZ_X_OUTPUT; + if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); + + if (s->smallDecompress) { + + /*-- Make a copy of cftab, used in generation of T --*/ + for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->ll16[i]); + SET_LL(i, s->cftabCopy[uc]); + s->cftabCopy[uc]++; + } + + /*-- Compute T^(-1) by pointer reversal on T --*/ + i = s->origPtr; + j = GET_LL(i); + do { + Int32 tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != s->origPtr); + + s->tPos = s->origPtr; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_SMALL(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } else { + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->tt[i] & 0xff); + s->tt[s->cftab[uc]] |= (i << 8); + s->cftab[uc]++; + } + + s->tPos = s->tt[s->origPtr] >> 8; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_FAST(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_FAST(s->k0); s->nblock_used++; + } + + } + + RETURN(BZ_OK); + + + + endhdr_2: + + GET_UCHAR(BZ_X_ENDHDR_2, uc); + if (uc != 0x72) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_3, uc); + if (uc != 0x45) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_4, uc); + if (uc != 0x38) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_5, uc); + if (uc != 0x50) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_6, uc); + if (uc != 0x90) RETURN(BZ_DATA_ERROR); + + s->storedCombinedCRC = 0; + GET_UCHAR(BZ_X_CCRC_1, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_2, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_3, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_4, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + + s->state = BZ_X_IDLE; + RETURN(BZ_STREAM_END); + + default: AssertH ( False, 4001 ); + } + + AssertH ( False, 4002 ); + + save_state_and_return: + + s->save_i = i; + s->save_j = j; + s->save_t = t; + s->save_alphaSize = alphaSize; + s->save_nGroups = nGroups; + s->save_nSelectors = nSelectors; + s->save_EOB = EOB; + s->save_groupNo = groupNo; + s->save_groupPos = groupPos; + s->save_nextSym = nextSym; + s->save_nblockMAX = nblockMAX; + s->save_nblock = nblock; + s->save_es = es; + s->save_N = N; + s->save_curr = curr; + s->save_zt = zt; + s->save_zn = zn; + s->save_zvec = zvec; + s->save_zj = zj; + s->save_gSel = gSel; + s->save_gMinlen = gMinlen; + s->save_gLimit = gLimit; + s->save_gBase = gBase; + s->save_gPerm = gPerm; + + return retVal; +} + + +/*-------------------------------------------------------------*/ +/*--- end decompress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/huffman.c b/plugins/CDVDiso/src/3rdparty/bzip2/huffman.c new file mode 100644 index 0000000000..00066bd0ab --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/bzip2/huffman.c @@ -0,0 +1,205 @@ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + Int32 zz, tmp; \ + zz = z; tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + +#define DOWNHEAP(z) \ +{ \ + Int32 zz, yy, tmp; \ + zz = z; tmp = heap[zz]; \ + while (True) { \ + yy = zz << 1; \ + if (yy > nHeap) break; \ + if (yy < nHeap && \ + weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + + +/*---------------------------------------------------*/ +void BZ2_hbMakeCodeLengths ( UChar *len, + Int32 *freq, + Int32 alphaSize, + Int32 maxLen ) +{ + /*-- + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + --*/ + Int32 nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; + Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; + Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (True) { + + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { k = parent[k]; j++; } + len[i-1] = j; + if (j > maxLen) tooLong = True; + } + + if (! tooLong) break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbAssignCodes ( Int32 *code, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) + if (length[i] == n) { code[i] = vec; vec++; }; + vec <<= 1; + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/bzip2/randtable.c b/plugins/CDVDiso/src/3rdparty/bzip2/randtable.c new file mode 100644 index 0000000000..87a2f05012 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/bzip2/randtable.c @@ -0,0 +1,84 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for randomising repetitive blocks ---*/ +/*--- randtable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.4 of 20 December 2006 + Copyright (C) 1996-2006 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------*/ +Int32 BZ2_rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +/*-------------------------------------------------------------*/ +/*--- end randtable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/ChangeLog b/plugins/CDVDiso/src/3rdparty/zlib/ChangeLog new file mode 100644 index 0000000000..7f6869d323 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/ChangeLog @@ -0,0 +1,855 @@ + + ChangeLog file for zlib + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Added zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] + +Changes in 1.2.2 (3 October 2004) +- Update zlib.h comments on gzip in-memory processing +- Set adler to 1 in inflateReset() to support Java test suite [Walles] +- Add contrib/dotzlib [Ravn] +- Update win32/DLL_FAQ.txt [Truta] +- Update contrib/minizip [Vollant] +- Move contrib/visual-basic.txt to old/ [Truta] +- Fix assembler builds in projects/visualc6/ [Truta] + +Changes in 1.2.1.2 (9 September 2004) +- Update INDEX file +- Fix trees.c to update strm->data_type (no one ever noticed!) +- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] +- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) +- Add limited multitasking protection to DYNAMIC_CRC_TABLE +- Add NO_vsnprintf for VMS in zutil.h [Mozilla] +- Don't declare strerror() under VMS [Mozilla] +- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize +- Update contrib/ada [Anisimkov] +- Update contrib/minizip [Vollant] +- Fix configure to not hardcode directories for Darwin [Peterson] +- Fix gzio.c to not return error on empty files [Brown] +- Fix indentation; update version in contrib/delphi/ZLib.pas and + contrib/pascal/zlibpas.pas [Truta] +- Update mkasm.bat in contrib/masmx86 [Truta] +- Update contrib/untgz [Truta] +- Add projects/README.projects [Truta] +- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] +- Remove an unnecessary assignment to curr in inftrees.c [Truta] +- Add OS/2 to exe builds in configure [Poltorak] +- Remove err dummy parameter in zlib.h [Kientzle] + +Changes in 1.2.1.1 (9 January 2004) +- Update email address in README +- Several FAQ updates +- Fix a big fat bug in inftrees.c that prevented decoding valid + dynamic blocks with only literals and no distance codes -- + Thanks to "Hot Emu" for the bug report and sample file +- Add a note to puff.c on no distance codes case. + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occurring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/plugins/CDVDiso/src/3rdparty/zlib/Makefile.am b/plugins/CDVDiso/src/3rdparty/zlib/Makefile.am new file mode 100644 index 0000000000..ff26496e22 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/Makefile.am @@ -0,0 +1,6 @@ +noinst_LIBRARIES = libpcsx2zlib.a + +libpcsx2zlib_a_SOURCES = \ +adler32.c crc32.c deflate.h inffast.c inflate.c inftrees.h trees.h zlib.h \ +crc32.h gzio.c inffast.h inflate.h uncompr.c zutil.c \ +compress.c deflate.c infback.c inffixed.h inftrees.c trees.c zconf.h zutil.h diff --git a/plugins/CDVDiso/src/3rdparty/zlib/README b/plugins/CDVDiso/src/3rdparty/zlib/README new file mode 100644 index 0000000000..758cc50020 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/README @@ -0,0 +1,125 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.3 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). These documents are also available in other +formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file example.c which also tests that the library +is working correctly. Another example is given in the file minigzip.c. The +compression library itself is composed of all source files except example.c and +minigzip.c. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile. In short "make test; make install" should work for most +machines. For Unix: "./configure; make test; make install". For MSDOS, use one +of the special makefiles such as Makefile.msc. For VMS, use make_vms.com. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem, +please check this site to verify that you have the latest version of zlib; +otherwise get the latest version and check whether the problem still exists or +not. + +PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking +for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available in +http://dogma.net/markn/articles/zlibtool/zlibtool.htm + +The changes made in version 1.2.3 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory "contrib". + +A Java implementation of zlib is available in the Java Development Kit +http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html +See the zlib home page http://www.zlib.org for details. + +A Perl interface to zlib written by Paul Marquess is in the +CPAN (Comprehensive Perl Archive Network) sites +http://www.cpan.org/modules/by-module/Compress/ + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://www.python.org/doc/lib/module-zlib.html + +A zlib binding for TCL written by Andreas Kupries is +availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + +- When building a shared, i.e. dynamic library on Mac OS X, the library must be + installed before testing (do "make install" before "make test"), since the + library location is specified in the library. + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate + and zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; + they are too numerous to cite here. + +Copyright notice: + + (C) 1995-2004 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 + +If you use the zlib library in a product, we would appreciate *not* +receiving lengthy legal documents to sign. The sources are provided +for free but without warranty of any kind. The library has been +entirely written by Jean-loup Gailly and Mark Adler; it does not +include third-party code. + +If you redistribute modified sources, we would appreciate that you include +in the file ChangeLog history information documenting your changes. Please +read the FAQ for more information on the distribution of modified source +versions. diff --git a/plugins/CDVDiso/src/3rdparty/zlib/adler32.c b/plugins/CDVDiso/src/3rdparty/zlib/adler32.c new file mode 100644 index 0000000000..f201d6701e --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/adler32.c @@ -0,0 +1,149 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* 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 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#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); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/compress.c b/plugins/CDVDiso/src/3rdparty/zlib/compress.c new file mode 100644 index 0000000000..d37e84f5e3 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + 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. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/crc32.c b/plugins/CDVDiso/src/3rdparty/zlib/crc32.c new file mode 100644 index 0000000000..32814c20c8 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/crc32.c @@ -0,0 +1,423 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/crc32.h b/plugins/CDVDiso/src/3rdparty/zlib/crc32.h new file mode 100644 index 0000000000..5de49bc978 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/plugins/CDVDiso/src/3rdparty/zlib/deflate.c b/plugins/CDVDiso/src/3rdparty/zlib/deflate.c new file mode 100644 index 0000000000..529f716b7a --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/deflate.c @@ -0,0 +1,1736 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + 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. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/plugins/CDVDiso/src/3rdparty/zlib/deflate.h b/plugins/CDVDiso/src/3rdparty/zlib/deflate.h new file mode 100644 index 0000000000..222c53e043 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * 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. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/gzio.c b/plugins/CDVDiso/src/3rdparty/zlib/gzio.c new file mode 100644 index 0000000000..2de9a36441 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/gzio.c @@ -0,0 +1,1026 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open 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). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_BEST_SPEED; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* 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. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + 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. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + 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. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + 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). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + 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 ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + 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. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + 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. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + 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. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/infback.c b/plugins/CDVDiso/src/3rdparty/zlib/infback.c new file mode 100644 index 0000000000..1e03e1bab0 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/infback.c @@ -0,0 +1,623 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inffast.c b/plugins/CDVDiso/src/3rdparty/zlib/inffast.c new file mode 100644 index 0000000000..fa31cad905 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/inffast.c @@ -0,0 +1,318 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inffast.h b/plugins/CDVDiso/src/3rdparty/zlib/inffast.h new file mode 100644 index 0000000000..614fa7877d --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 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. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inffixed.h b/plugins/CDVDiso/src/3rdparty/zlib/inffixed.h new file mode 100644 index 0000000000..423d5c5b50 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* 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 const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,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,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,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,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,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,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inflate.c b/plugins/CDVDiso/src/3rdparty/zlib/inflate.c new file mode 100644 index 0000000000..33ea902928 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/inflate.c @@ -0,0 +1,1368 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + 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 ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inflate.h b/plugins/CDVDiso/src/3rdparty/zlib/inflate.h new file mode 100644 index 0000000000..fbbc871432 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 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. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inftrees.c b/plugins/CDVDiso/src/3rdparty/zlib/inftrees.c new file mode 100644 index 0000000000..38ded81c36 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/inftrees.c @@ -0,0 +1,329 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 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. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 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}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 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, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/inftrees.h b/plugins/CDVDiso/src/3rdparty/zlib/inftrees.h new file mode 100644 index 0000000000..dc0fd567ea --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 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. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/plugins/CDVDiso/src/3rdparty/zlib/trees.c b/plugins/CDVDiso/src/3rdparty/zlib/trees.c new file mode 100644 index 0000000000..7a04802862 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/trees.c @@ -0,0 +1,1219 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {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}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {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}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/trees.h b/plugins/CDVDiso/src/3rdparty/zlib/trees.h new file mode 100644 index 0000000000..1ca868b848 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/plugins/CDVDiso/src/3rdparty/zlib/uncompr.c b/plugins/CDVDiso/src/3rdparty/zlib/uncompr.c new file mode 100644 index 0000000000..ad6db0a67c --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + 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. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/plugins/CDVDiso/src/3rdparty/zlib/zconf.h b/plugins/CDVDiso/src/3rdparty/zlib/zconf.h new file mode 100644 index 0000000000..e3b0c962e3 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/zconf.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* 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 */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#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 +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/zlib.h b/plugins/CDVDiso/src/3rdparty/zlib/zlib.h new file mode 100644 index 0000000000..62d0e4675b --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 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 http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + 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 compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + 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. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + 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 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() 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_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#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 */ + +ZEXTERN const char * ZEXPORT 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. + */ + +/* +ZEXTERN int ZEXPORT 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(). +*/ + + +ZEXTERN int ZEXPORT 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. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + 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 + 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). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + 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 + the value returned by deflateBound (see below). 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 far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). 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). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT 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). +*/ + + +/* +ZEXTERN int ZEXPORT 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.) +*/ + + +ZEXTERN int ZEXPORT 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 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. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + 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 approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (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 far (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() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + 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 check + value), 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. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT 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. +*/ + +/* +ZEXTERN int ZEXPORT 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. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + 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), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). 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. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + 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(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *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. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + 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.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + 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(). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT 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. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. 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. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + 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 null strm). 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.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *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 that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + 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(). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT inflateCopy 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 randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy 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. +*/ + +ZEXTERN int ZEXPORT 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). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* 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. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *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 the value returned + by compressBound(sourceLen). 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. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *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 the value returned by + compressBound(sourceLen). 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. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *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 or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT 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", or 'R' for run-length encoding + as in "wb1R". (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). */ + +ZEXTERN gzFile ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc 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). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + 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). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN char * ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t 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. +*/ + +ZEXTERN int ZEXPORT 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) +*/ + +ZEXTERN z_off_t ZEXPORT 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) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT 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). +*/ + +ZEXTERN const char * ZEXPORT 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. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *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(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + 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)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/zutil.c b/plugins/CDVDiso/src/3rdparty/zlib/zutil.c new file mode 100644 index 0000000000..0f4bd7871d --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/plugins/CDVDiso/src/3rdparty/zlib/zutil.h b/plugins/CDVDiso/src/3rdparty/zlib/zutil.h new file mode 100644 index 0000000000..0e3a9a0638 --- /dev/null +++ b/plugins/CDVDiso/src/3rdparty/zlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * 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. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const 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 9 +#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 */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* 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 */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/CDVDiso/src/CDVDiso.h b/plugins/CDVDiso/src/CDVDiso.h new file mode 100644 index 0000000000..61bd9886f9 --- /dev/null +++ b/plugins/CDVDiso/src/CDVDiso.h @@ -0,0 +1,130 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso Team + * + * 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 _MSC_VER +#pragma warning(disable:4018) +#endif + +#include "PS2Edefs.h" +#include "libiso.h" + +#ifdef __cplusplus + +#ifdef _MSC_VER +#define EXPORT_C(type) extern "C" __declspec(dllexport) type CALLBACK +#else +#define EXPORT_C(type) extern "C" type +#endif + +#else + +#ifdef _MSC_VER +#define EXPORT_C(type) __declspec(dllexport) type __stdcall +#else +#define EXPORT_C(type) type +#endif + +#endif + +EXPORT_C(u32) PS2EgetLibType(); +EXPORT_C(u32) PS2EgetLibVersion2(u32 type); +EXPORT_C(char*) PS2EgetLibName(); + + +EXPORT_C(s32) CDVDinit(); +EXPORT_C(s32) CDVDopen(const char* pTitleFilename); +EXPORT_C(void) CDVDclose(); +EXPORT_C(void) CDVDshutdown(); +EXPORT_C(s32) CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +EXPORT_C(u8*) CDVDgetBuffer(); + +EXPORT_C(s32) CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +EXPORT_C(s32) CDVDgetTN(cdvdTN *Buffer); //disk information +EXPORT_C(s32) CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +EXPORT_C(s32) CDVDgetTOC(void* toc); //gets ps2 style toc from disc +EXPORT_C(s32) CDVDgetDiskType(); //CDVD_TYPE_xxxx +EXPORT_C(s32) CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +EXPORT_C(s32) CDVDctrlTrayOpen(); //open disc tray +EXPORT_C(s32) CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +EXPORT_C(void) CDVDconfigure(); +EXPORT_C(void) CDVDabout(); +EXPORT_C(s32) CDVDtest(); +EXPORT_C(void) CDVDnewDiskCB(void (*callback)()); + +#define CDVD_LOG __Log +extern FILE *cdvdLog; + +void __Log(char *fmt, ...); + +#define VERBOSE 1 + +#define DEV_DEF "" +#define CDDEV_DEF "/dev/cdrom" + +typedef struct { + int slsn; + int elsn; +#ifdef _WINDOWS_ + HANDLE handle; +#else + FILE *handle; +#endif +} _cdIso; + +extern _cdIso cdIso[8]; + +#define CD_FRAMESIZE_RAW 2352 +#define DATA_SIZE (CD_FRAMESIZE_RAW-12) + +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ + +#define MSF2SECT(m,s,f) (((m)*60+(s)-2)*75+(f)) + +extern char IsoFile[256]; +extern char IsoCWD[256]; +extern char CdDev[256]; + +extern int BlockDump; +extern isoFile *fdump; +extern isoFile *iso; + +extern u8 cdbuffer[]; +extern u8 *pbuffer; +extern int cdblocksize; +extern int cdblockofs; +extern int cdoffset; +extern int cdtype; +extern int cdblocks; + +extern int Zmode; // 1 Z - 2 bz2 +extern int fmode; // 0 - file / 1 - Zfile +extern char *Ztable; + +extern char *methods[]; + +void UpdateZmode(); +void CfgOpenFile(); +void SysMessage(char *fmt, ...); + diff --git a/plugins/CDVDiso/src/CDVDisop.c b/plugins/CDVDiso/src/CDVDisop.c new file mode 100644 index 0000000000..14e2aac892 --- /dev/null +++ b/plugins/CDVDiso/src/CDVDisop.c @@ -0,0 +1,452 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CDVDiso.h" +#include "Config.h" + +#ifndef MAX_PATH +#define MAX_PATH 255 +#endif + +char IsoFile[256]; +char IsoCWD[256]; +char CdDev[256]; + +_cdIso cdIso[8]; +u8 *pbuffer; +int cdblocksize; +int cdblockofs; +int cdoffset; +int cdtype; +int cdblocks; + +int Zmode; // 1 Z - 2 bz2 +int fmode; // 0 - file / 1 - Zfile +char *Ztable; + +int BlockDump; +isoFile *fdump; +isoFile *iso; + +FILE *cdvdLog = NULL; + +// This var is used to detect resume-style behavior of the Pcsx2 emulator, +// and skip prompting the user for a new CD when it's likely they want to run the existing one. +static char cdvdCurrentIso[MAX_PATH]; + +char *methods[] = { + ".Z - compress faster", + ".BZ - compress better", + NULL +}; + +#ifdef _DEBUG +char *LibName = "Linuz/Pg Iso CDVD (Debug) "; +#else +char *LibName = "Linuz/Pg Iso CDVD "; +#endif + +const unsigned char version = PS2E_CDVD_VERSION; +const unsigned char revision = 0; +const unsigned char build = 8; + +unsigned char cdbuffer[CD_FRAMESIZE_RAW * 10] = {0}; + +s32 msf_to_lba(u8 m, u8 s, u8 f) { + u32 lsn; + lsn = f; + lsn+=(s - 2) * 75; + lsn+= m * 75 * 60; + return lsn; +} + +void lba_to_msf(s32 lba, u8* m, u8* s, u8* f) { + lba += 150; + *m = lba / (60*75); + *s = (lba / 75) % 60; + *f = lba % 75; +} + +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ + + +EXPORT_C(char*) PS2EgetLibName() { + return LibName; +} + +EXPORT_C(u32) PS2EgetLibType() { + return PS2E_LT_CDVD; +} + +EXPORT_C(u32) PS2EgetLibVersion2(u32 type) { + return (version << 16) | (revision << 8) | build; +} + +#ifdef _DEBUG +void __Log(char *fmt, ...) { + va_list list; + + if( cdvdLog == NULL ) + return; + + va_start(list, fmt); + vfprintf(cdvdLog, fmt, list); + va_end(list); +} +#else +#define __Log 0&& +#endif + + +EXPORT_C(s32) CDVDinit() { +#ifdef _DEBUG + cdvdLog = fopen("logs/cdvdLog.txt", "w"); + if (cdvdLog == NULL) { + cdvdLog = fopen("cdvdLog.txt", "w"); + if (cdvdLog == NULL) { + SysMessage("Can't create cdvdLog.txt"); return -1; + } + } + setvbuf(cdvdLog, NULL, _IONBF, 0); + CDVD_LOG("CDVDinit\n"); +#endif + + cdvdCurrentIso[0] = 0; + memset(cdIso, 0, sizeof(cdIso)); + return 0; +} + +EXPORT_C(void) CDVDshutdown() { + cdvdCurrentIso[0] = 0; +#ifdef CDVD_LOG + if( cdvdLog != NULL ) + fclose(cdvdLog); +#endif +} + +EXPORT_C(s32) CDVDopen(const char* pTitle) { + LoadConf(); + + if( pTitle != NULL ) strcpy(IsoFile, pTitle); + + if( *IsoFile == 0 ) strcpy( IsoFile, cdvdCurrentIso ); + + if (*IsoFile == 0) { + char temp[256]; + + CfgOpenFile(); + + LoadConf(); + strcpy(temp, IsoFile); + *IsoFile = 0; + SaveConf(); + strcpy(IsoFile, temp); + } + + iso = isoOpen(IsoFile); + if (iso == NULL) { + SysMessage("Error loading %s\n", IsoFile); + return -1; + } + + if (iso->type == ISOTYPE_DVD) { + cdtype = CDVD_TYPE_PS2DVD; + } else + if (iso->type == ISOTYPE_AUDIO) { + cdtype = CDVD_TYPE_CDDA; + } else { + cdtype = CDVD_TYPE_PS2CD; + } + + if (BlockDump) { + char fname_only[MAX_PATH]; + char* p, *plast; + +#ifdef _WIN32 + char fname[MAX_PATH],ext[MAX_PATH]; + _splitpath(IsoFile,NULL,NULL,fname,ext); + _makepath(fname_only,NULL,NULL,fname,NULL); +#else + plast = p = strchr(IsoFile, '/'); + while(p != NULL) { + plast = p; + p = strchr(p+1, '/'); + } + + if( plast != NULL ) strcpy(fname_only, plast+1); + else strcpy(fname_only, IsoFile); + + plast = p = strchr(fname_only, '.'); + while(p != NULL) { + plast = p; + p = strchr(p+1, '.'); + } + + if( plast != NULL ) *plast = 0; + +#endif + strcat(fname_only, ".dump"); + fdump = isoCreate(fname_only, ISOFLAGS_BLOCKDUMP); + if (fdump) { + isoSetFormat(fdump, iso->blockofs, iso->blocksize, iso->blocks); + } + } else { + fdump = NULL; + } + + return 0; +} + +EXPORT_C(void) CDVDclose() { + + strcpy( cdvdCurrentIso, IsoFile ); + + isoClose(iso); + if (fdump != NULL) { + isoClose(fdump); + } +} + +EXPORT_C(s32) CDVDreadSubQ(u32 lsn, cdvdSubQ* subq) { + // fake it + u8 min, sec, frm; + subq->ctrl = 4; + subq->mode = 1; + subq->trackNum = itob(1); + subq->trackIndex= itob(1); + + lba_to_msf(lsn, &min, &sec, &frm); + subq->trackM = itob(min); + subq->trackS = itob(sec); + subq->trackF = itob(frm); + + subq->pad = 0; + + lba_to_msf(lsn + (2*75), &min, &sec, &frm); + subq->discM = itob(min); + subq->discS = itob(sec); + subq->discF = itob(frm); + return 0; +} + +EXPORT_C(s32) CDVDgetTN(cdvdTN *Buffer) { + Buffer->strack = 1; + Buffer->etrack = 1; + + return 0; +} + +EXPORT_C(s32) CDVDgetTD(u8 Track, cdvdTD *Buffer) { + if (Track == 0) { + Buffer->lsn = iso->blocks; + } else { + Buffer->type = CDVD_MODE1_TRACK; + Buffer->lsn = 0; + } + + return 0; +} + +static int layer1start = -1; +EXPORT_C(s32) CDVDgetTOC(void* toc) { + u8 type = CDVDgetDiskType(); + u8* tocBuff = (u8*)toc; + + //__Log("CDVDgetTOC\n"); + + if( type == CDVD_TYPE_DVDV || type == CDVD_TYPE_PS2DVD) + { + int i; + + // get dvd structure format + // scsi command 0x43 + memset(tocBuff, 0, 2048); + + if( layer1start != -2 && iso->blocks >= 0x300000 ) { + int off = iso->blockofs; + u8* tempbuffer; + + // dual sided + tocBuff[ 0] = 0x24; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x41; + tocBuff[ 5] = 0x95; + + tocBuff[14] = 0x60; // dual sided, ptp + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + + // search for it + if( layer1start == -1 ) { + printf("CDVD: searching for layer1..."); + tempbuffer = (u8*)malloc(CD_FRAMESIZE_RAW * 10); + for(layer1start = (iso->blocks/2-0x10)&~0xf; layer1start < 0x200010; layer1start += 16) { + isoReadBlock(iso, tempbuffer, layer1start); + // CD001 + if( tempbuffer[off+1] == 0x43 && tempbuffer[off+2] == 0x44 && tempbuffer[off+3] == 0x30 && tempbuffer[off+4] == 0x30 && tempbuffer[off+5] == 0x31 ) { + break; + } + } + free(tempbuffer); + + if( layer1start == 0x200010 ) { + printf("Couldn't find second layer on dual layer... ignoring\n"); + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + layer1start = -2; + return 0; + } + + printf("found at 0x%8.8x\n", layer1start); + layer1start = layer1start+0x30000-1; + } + + tocBuff[20] = layer1start>>24; + tocBuff[21] = (layer1start>>16)&0xff; + tocBuff[22] = (layer1start>>8)&0xff; + tocBuff[23] = (layer1start>>0)&0xff; + } + else { + // fake it + tocBuff[ 0] = 0x04; + tocBuff[ 1] = 0x02; + tocBuff[ 2] = 0xF2; + tocBuff[ 3] = 0x00; + tocBuff[ 4] = 0x86; + tocBuff[ 5] = 0x72; + + tocBuff[16] = 0x00; + tocBuff[17] = 0x03; + tocBuff[18] = 0x00; + tocBuff[19] = 0x00; + } + } + else if(type == CDVD_TYPE_CDDA || + type == CDVD_TYPE_PS2CDDA || + type == CDVD_TYPE_PS2CD || + type == CDVD_TYPE_PSCDDA || + type == CDVD_TYPE_PSCD) + { + // cd toc + // (could be replaced by 1 command that reads the full toc) + u8 min, sec, frm; + s32 i, err; + cdvdTN diskInfo; + cdvdTD trackInfo; + memset(tocBuff, 0, 1024); + if (CDVDgetTN(&diskInfo) == -1) { diskInfo.etrack = 0;diskInfo.strack = 1; } + if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0; + + tocBuff[0] = 0x41; + tocBuff[1] = 0x00; + + //Number of FirstTrack + tocBuff[2] = 0xA0; + tocBuff[7] = itob(diskInfo.strack); + + //Number of LastTrack + tocBuff[12] = 0xA1; + tocBuff[17] = itob(diskInfo.etrack); + + //DiskLength + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[22] = 0xA2; + tocBuff[27] = itob(min); + tocBuff[28] = itob(sec); + + for (i=diskInfo.strack; i<=diskInfo.etrack; i++) + { + err = CDVDgetTD(i, &trackInfo); + lba_to_msf(trackInfo.lsn, &min, &sec, &frm); + tocBuff[i*10+30] = trackInfo.type; + tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number + tocBuff[i*10+37] = itob(min); + tocBuff[i*10+38] = itob(sec); + tocBuff[i*10+39] = itob(frm); + } + } + else + return -1; + + return 0; +} + +EXPORT_C(s32) CDVDreadTrack(u32 lsn, int mode) { + int _lsn = lsn; + + //__Log("CDVDreadTrack: %x %x\n", lsn, mode); + if (_lsn < 0) { +// lsn = 2097152 + (-_lsn); + lsn = iso->blocks - (-_lsn); + } +// printf ("CDRreadTrack %d\n", lsn); + + isoReadBlock(iso, cdbuffer, lsn); + if (fdump != NULL) { + isoWriteBlock(fdump, cdbuffer, lsn); + } + + pbuffer = cdbuffer; + switch (mode) { + case CDVD_MODE_2352: break; + case CDVD_MODE_2340: pbuffer+= 12; break; + case CDVD_MODE_2328: pbuffer+= 24; break; + case CDVD_MODE_2048: pbuffer+= 24; break; + } + + return 0; +} + +EXPORT_C(u8*) CDVDgetBuffer() { + return pbuffer; +} + +EXPORT_C(s32) CDVDgetDiskType() { + return cdtype; +} + +EXPORT_C(s32) CDVDgetTrayStatus() { + return CDVD_TRAY_CLOSE; +} + +EXPORT_C(s32) CDVDctrlTrayOpen() { + return 0; +} +EXPORT_C(s32) CDVDctrlTrayClose() { + return 0; +} + + +EXPORT_C(s32) CDVDtest() { + if (*IsoFile == 0) + return 0; + + iso = isoOpen(IsoFile); + if (iso == NULL) return -1; + isoClose(iso); + + return 0; +} + diff --git a/plugins/CDVDiso/src/Linux/CDVDiso.glade b/plugins/CDVDiso/src/Linux/CDVDiso.glade new file mode 100644 index 0000000000..53ab399360 --- /dev/null +++ b/plugins/CDVDiso/src/Linux/CDVDiso.glade @@ -0,0 +1,403 @@ + + + + + + + 5 + True + CDVD Config Dialog + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 5 + + + + True + False + 10 + + + + True + True + True + True + 0 + + True + * + False + + + 0 + True + True + + + + + + True + True + Select Iso + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + False + 10 + + + + True + GTK_PROGRESS_LEFT_TO_RIGHT + 0 + 0.10000000149 + PANGO_ELLIPSIZE_NONE + + + 0 + True + False + + + + + + True + True + Stop + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + GTK_PACK_END + + + + + 0 + False + False + + + + + + True + False + 5 + + + + True + Compression Method: + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + True + False + True + False + + + + True + True + True + True + 0 + + True + * + False + + + + + + True + GTK_SELECTION_BROWSE + + + + True + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + + + 0 + True + False + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Compress Iso + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Decompress Iso + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + True + False + 5 + + + + True + Cdrom Device: + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 0 + + True + * + False + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + Create Iso + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Create Compressed Iso + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + diff --git a/plugins/CDVDiso/src/Linux/Config.c b/plugins/CDVDiso/src/Linux/Config.c new file mode 100644 index 0000000000..c5eea547b5 --- /dev/null +++ b/plugins/CDVDiso/src/Linux/Config.c @@ -0,0 +1,59 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "CDVDiso.h" + +void LoadConf() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); + f = fopen(cfg, "r"); + if (f == NULL) { + strcpy(IsoFile, DEV_DEF); + strcpy(CdDev, CDDEV_DEF); + return; + } + fscanf(f, "IsoFile = %[^\n]\n", IsoFile); + fscanf(f, "CdDev = %[^\n]\n", CdDev); + if (!strncmp(IsoFile, "CdDev =", 9)) *IsoFile = 0; // quick fix + if (*CdDev == 0) strcpy(CdDev, CDDEV_DEF); + fclose(f); +} + +void SaveConf() { + FILE *f; + char cfg[256]; + + sprintf(cfg, "%s/.PS2E", getenv("HOME")); + mkdir(cfg, 0755); + sprintf(cfg, "%s/.PS2E/CDVDiso.cfg", getenv("HOME")); + f = fopen(cfg, "w"); + if (f == NULL) + return; + fprintf(f, "IsoFile = %s\n", IsoFile); + fprintf(f, "CdDev = %s\n", CdDev); + fclose(f); +} + diff --git a/plugins/CDVDiso/src/Linux/Config.h b/plugins/CDVDiso/src/Linux/Config.h new file mode 100644 index 0000000000..d1df0d3e72 --- /dev/null +++ b/plugins/CDVDiso/src/Linux/Config.h @@ -0,0 +1,20 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso Team + * + * 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 + */ + +void SaveConf(); +void LoadConf(); diff --git a/plugins/CDVDiso/src/Linux/Linux.c b/plugins/CDVDiso/src/Linux/Linux.c new file mode 100644 index 0000000000..70947b559f --- /dev/null +++ b/plugins/CDVDiso/src/Linux/Linux.c @@ -0,0 +1,76 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "Config.h" +#include "CDVDiso.h" + +void ExecCfg(char *arg) { + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgCDVDiso"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); return; + } + + strcpy(cfg, "./cfg/cfgCDVDiso"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); return; + } + + sprintf(cfg, "%s/cfgCDVDiso", getenv("HOME")); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); return; + } + + printf("cfgCDVDiso file not found!\n"); +} + +void CDVDconfigure() { + ExecCfg("configure"); +} + +void CDVDabout() { + ExecCfg("about"); +} + +void CfgOpenFile() { + ExecCfg("open"); +} + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[256]; + char cmd[256]; + + va_start(list, fmt); + vsprintf(tmp, fmt, list); + va_end(list); + + sprintf(cmd, "message \"%s\"", tmp); + ExecCfg(cmd); +} diff --git a/plugins/CDVDiso/src/Linux/Makefile b/plugins/CDVDiso/src/Linux/Makefile new file mode 100644 index 0000000000..921f6190c9 --- /dev/null +++ b/plugins/CDVDiso/src/Linux/Makefile @@ -0,0 +1,33 @@ + +CC = gcc + +PLUGIN = libCDVDiso.so +CFG = cfgCDVDiso +MKISO = mkiso +CFLAGS = -fPIC -Wall -g -I.. -I. -D__LINUX__ +OBJS = ../CDVDisop.o Config.o Linux.o ../libiso.o +CFGOBJS = conf.o interface.o support.o ${OBJS} +LIBS = -lz -lbz2 -lstdc++ +CFGLIBS = $(shell pkg-config --libs gtk+-2.0) ${LIBS} +CFLAGS += $(shell pkg-config --cflags gtk+-2.0) -I../common +DEPS:= $(OBJS:.o=.d) $(CFGOBJS:.o=.d) + +all: plugin cfg +install: all + +plugin: ${OBJS} + rm -f ${PLUGIN} + ${CC} -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + +cfg: ${CFGOBJS} + rm -f ${CFG} + ${CC} ${CFLAGS} ${CFGOBJS} -o ${CFG} ${CFGLIBS} + strip ${CFG} + +clean: + rm -f ${OBJS} ${DEPS} ${PLUGIN} ${CFGOBJS} ${CFG} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/CDVDiso/src/Linux/callbacks.c b/plugins/CDVDiso/src/Linux/callbacks.c new file mode 100644 index 0000000000..4c5340dc06 --- /dev/null +++ b/plugins/CDVDiso/src/Linux/callbacks.c @@ -0,0 +1,74 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnFileSel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnStop (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnCompress (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnDecompress (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnCreate (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnCreateZ (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnOk (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnCancel (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/CDVDiso/src/Linux/callbacks.h b/plugins/CDVDiso/src/Linux/callbacks.h new file mode 100644 index 0000000000..c3e5b8de3e --- /dev/null +++ b/plugins/CDVDiso/src/Linux/callbacks.h @@ -0,0 +1,34 @@ +#include + + +void +OnFileSel (GtkButton *button, + gpointer user_data); + +void +OnStop (GtkButton *button, + gpointer user_data); + +void +OnCompress (GtkButton *button, + gpointer user_data); + +void +OnDecompress (GtkButton *button, + gpointer user_data); + +void +OnCreate (GtkButton *button, + gpointer user_data); + +void +OnCreateZ (GtkButton *button, + gpointer user_data); + +void +OnOk (GtkButton *button, + gpointer user_data); + +void +OnCancel (GtkButton *button, + gpointer user_data); diff --git a/plugins/CDVDiso/src/Linux/conf.c b/plugins/CDVDiso/src/Linux/conf.c new file mode 100644 index 0000000000..9f2c132cea --- /dev/null +++ b/plugins/CDVDiso/src/Linux/conf.c @@ -0,0 +1,865 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "interface.h" +#include "support.h" +#include "CDVDiso.h" +#include "Config.h" + +unsigned char Zbuf[CD_FRAMESIZE_RAW * 10 * 2]; + +extern char *LibName; + +extern const unsigned char revision; +extern const unsigned char build; + +GtkWidget *FileSel; + +void OnFile_Ok() { + gchar *File; + + gtk_widget_hide(FileSel); + File = gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + strcpy(IsoFile, File); + gtk_main_quit(); +} + +void OnFile_Cancel() { + gtk_widget_hide(FileSel); + gtk_main_quit(); +} + +void _CDRopen() { + GtkWidget *Ok, *Cancel; + + FileSel = gtk_file_selection_new("Select Iso File"); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect(GTK_OBJECT(Ok), "clicked", + GTK_SIGNAL_FUNC(OnFile_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect(GTK_OBJECT(Cancel), "clicked", + GTK_SIGNAL_FUNC(OnFile_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); + + gtk_main(); + + SaveConf(); +} + +GtkWidget *MsgDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +static void SysMessageLoc(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + int w; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + w = strlen(msg) * 6 + 20; + + MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_usize(MsgDlg, w, 70); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "cdriso Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 0); + + Box = gtk_vbox_new(0, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +GtkWidget *ConfDlg; +GtkWidget *Edit, *CdEdit; +GtkWidget *FileSel; +GtkWidget *Progress; +GtkWidget *BtnCompress; +GtkWidget *BtnDecompress; +GtkWidget *BtnCreate; +GtkWidget *BtnCreateZ; +GtkWidget *Method; + +GList *methodlist; +extern char *methods[]; + +int stop; + +void OnOk(GtkMenuItem * menuitem, gpointer userdata) { + char *tmp; + + stop=1; + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + tmp = gtk_entry_get_text(GTK_ENTRY(CdEdit)); + strcpy(CdDev, tmp); + SaveConf(); + gtk_widget_destroy(ConfDlg); + gtk_main_quit(); +} + +void OnCancel(GtkMenuItem * menuitem, gpointer userdata) { + stop=1; + gtk_widget_destroy(ConfDlg); + gtk_main_quit(); +} + +void OnFileSel_Ok() { + gchar *File; + + File = gtk_file_selection_get_filename(GTK_FILE_SELECTION(FileSel)); + gtk_entry_set_text(GTK_ENTRY(Edit), File); + gtk_widget_destroy(FileSel); +} + +void OnFileSel_Cancel() { + gtk_widget_destroy(FileSel); +} + +void OnFileSel() { + GtkWidget *Ok,*Cancel; + + FileSel = gtk_file_selection_new("Select Psx Iso File"); + gtk_file_selection_set_filename(GTK_FILE_SELECTION(FileSel), IsoFile); + + Ok = GTK_FILE_SELECTION(FileSel)->ok_button; + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnFileSel_Ok), NULL); + gtk_widget_show(Ok); + + Cancel = GTK_FILE_SELECTION(FileSel)->cancel_button; + gtk_signal_connect (GTK_OBJECT(Cancel), "clicked", GTK_SIGNAL_FUNC(OnFileSel_Cancel), NULL); + gtk_widget_show(Cancel); + + gtk_widget_show(FileSel); + gdk_window_raise(FileSel->window); +} + +void OnStop() { + stop=1; +} + +void UpdZmode() { + char *tmp; + + tmp = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(Method)->entry)); + if (!strcmp(tmp, methods[0])) Zmode = 1; + else Zmode = 2; +} + +char buffer[2352 * 10]; + +void OnCompress() { + struct stat buf; + u32 lsn; + u8 cdbuff[10*2352]; + char Zfile[256]; + char *tmp; + int ret; + isoFile *src; + isoFile *dst; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + UpdZmode(); + + if (Zmode == 1) sprintf(Zfile, "%s.Z2", IsoFile); + if (Zmode == 2) sprintf(Zfile, "%s.BZ2", IsoFile); + + if (stat(Zfile, &buf) != -1) { + char str[256]; + return; +/* sprintf(str, "'%s' already exists, overwrite?", Zfile); + if (MessageBox(hDlg, str, "Question", MB_YESNO) != IDYES) { + return; + }*/ + } + + src = isoOpen(IsoFile); + if (src == NULL) return; + dst = isoCreate(Zfile, Zmode == 1 ? ISOFLAGS_Z2 : ISOFLAGS_BZ2); + if (dst == NULL) return; + + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + stop=0; + + for (lsn = 0; lsnblocks; lsn++) { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + + gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), (lsn * 100) / src->blocks); + while (gtk_events_pending()) gtk_main_iteration(); + if (stop) break; + } + isoClose(src); + isoClose(dst); + + if (!stop) gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) { + if (ret == -1) { + SysMessageLoc("Error compressing iso image"); + } else { + SysMessageLoc("Iso image compressed OK"); + } + } +} + +void OnDecompress() { +#if 0 + struct stat buf; + FILE *f; + unsigned long c=0, p=0, s; + char table[256]; + char *tmp; + int blocks; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + + if (strstr(IsoFile, ".Z") != NULL) Zmode = 1; + else Zmode = 2; + + strcpy(table, IsoFile); + if (Zmode == 1) strcat(table, ".table"); + else strcat(table, ".index"); + + if (stat(table, &buf) == -1) { + return; + } + if (Zmode == 1) c = s = buf.st_size / 6; + else c = s = (buf.st_size / 4) - 1; + f = fopen(table, "rb"); + Ztable = (char*)malloc(buf.st_size); + fread(Ztable, 1, buf.st_size, f); + fclose(f); + + cdHandle[0] = fopen(IsoFile, "rb"); + if (cdHandle[0] == NULL) { + return; + } + + if (Zmode == 1) IsoFile[strlen(IsoFile) - 2] = 0; + else IsoFile[strlen(IsoFile) - 3] = 0; + + f = fopen(IsoFile, "wb"); + if (f == NULL) { + return; + } + + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + stop=0; + + if (Zmode == 1) { + blocks = 1; + } else { + blocks = 10; + } + + while (c--) { + unsigned long size, pos, ssize; + float per; + + if (Zmode == 1) { + pos = *(unsigned long*)&Ztable[p * 6]; + fseek(cdHandle[0], pos, SEEK_SET); + + ssize = *(unsigned short*)&Ztable[p * 6 + 4]; + fread(Zbuf, 1, ssize, cdHandle[0]); + } else { + pos = *(unsigned long*)&Ztable[p * 4]; + fseek(cdHandle[0], pos, SEEK_SET); + + ssize = *(unsigned long*)&Ztable[p * 4 + 4] - pos; + fread(Zbuf, 1, ssize, cdHandle[0]); + } + + size = CD_FRAMESIZE_RAW * blocks; + if (Zmode == 1) uncompress(cdbuffer, &size, Zbuf, ssize); + else BZ2_bzBuffToBuffDecompress(cdbuffer, (unsigned int*)&size, Zbuf, ssize, 0, 0); + + fwrite(cdbuffer, 1, size, f); + + p++; + + per = ((float)p / s); + gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), per); + while (gtk_events_pending()) gtk_main_iteration(); + if (stop) break; + } + if (!stop) gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); + + fclose(f); + fclose(cdHandle[0]); cdHandle[0] = NULL; + free(Ztable); Ztable = NULL; + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) SysMessageLoc("Iso Image Decompressed OK"); +#endif +} + +#define CD_LEADOUT (0xaa) +unsigned char param[4]; +int cddev = -1; + +union { + struct cdrom_msf msf; + unsigned char buf[CD_FRAMESIZE_RAW]; +} cr; + +void incSector() { + param[2]++; + if (param[2] == 75) { + param[2] = 0; + param[1]++; + } + if (param[1] == 60) { + param[1] = 0; + param[0]++; + } +} + +long CDR_open(void) { + if (cddev != -1) + return 0; + cddev = open(CdDev, O_RDONLY); + if (cddev == -1) { + printf("CDR: Could not open %s\n", CdDev); + return -1; + } + + return 0; +} + +long CDR_close(void) { + if (cddev == -1) return 0; + close(cddev); + cddev = -1; + + return 0; +} + +// return Starting and Ending Track +// buffer: +// byte 0 - start track +// byte 1 - end track +long CDR_getTN(unsigned char *buffer) { + struct cdrom_tochdr toc; + + if (ioctl(cddev, CDROMREADTOCHDR, &toc) == -1) return -1; + + buffer[0] = toc.cdth_trk0; // start track + buffer[1] = toc.cdth_trk1; // end track + + return 0; +} + +// return Track Time +// buffer: +// byte 0 - frame +// byte 1 - second +// byte 2 - minute +long CDR_getTD(unsigned char track, unsigned char *buffer) { + struct cdrom_tocentry entry; + + if (track == 0) track = 0xaa; // total time + entry.cdte_track = track; + entry.cdte_format = CDROM_MSF; + + if (ioctl(cddev, CDROMREADTOCENTRY, &entry) == -1) return -1; + + buffer[0] = entry.cdte_addr.msf.minute; /* minute */ + buffer[1] = entry.cdte_addr.msf.second; /* second */ + buffer[2] = entry.cdte_addr.msf.frame; /* frame */ + + return 0; +} + +// read track +// time: +// byte 0 - minute +// byte 1 - second +// byte 2 - frame +char *CDR_readTrack(unsigned char *time) { + cr.msf.cdmsf_min0 = time[0]; + cr.msf.cdmsf_sec0 = time[1]; + cr.msf.cdmsf_frame0 = time[2]; + + if (ioctl(cddev, CDROMREADRAW, &cr) == -1) return NULL; + return cr.buf; +} + + +void OnCreate() { + FILE *f; + struct stat buf; + struct tm *Tm; + time_t Ttime; + unsigned long ftrack, ltrack; + unsigned long p=0,s; + unsigned char *buffer; + unsigned char bufferz[2352]; + unsigned char start[4], end[4]; + char *tmp; +#ifdef VERBOSE + unsigned long count = 0; + int i=0; +#endif + + memset(bufferz, 0, sizeof(bufferz)); + ftrack = 1; + ltrack = CD_LEADOUT; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + + if (stat(IsoFile, &buf) == 0) { + printf("File %s Already exists\n", IsoFile); + return; + } + + if (CDR_open() == -1) { + return; + } + + if (CDR_getTD(ftrack, start) == -1) { + printf("Error getting TD\n"); + + CDR_close(); + return; + } + if (CDR_getTD(ltrack, end) == -1) { + printf("Error getting TD\n"); + + CDR_close(); + return; + } + + f = fopen(IsoFile, "wb"); + if (f == NULL) { + CDR_close(); + printf("Error opening %s", IsoFile); + return; + } + + printf("Making Iso: from %2.2d:%2.2d:%2.2d to %2.2d:%2.2d:%2.2d\n", + start[0], start[1], start[2], end[0], end[1], end[2]); + + memcpy(param, start, 3); + + time(&Ttime); + + stop = 0; + s = MSF2SECT(end[0], end[1], end[2]); + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + + for (;;) { /* loop until end */ + float per; + + if ((param[0] == end[0]) & (param[1] == end[1]) & (param[2] == end[2])) + break; + buffer = CDR_readTrack(param); + if (buffer == NULL) { + int i; + + for (i=0; i<10; i++) { + buffer = CDR_readTrack(param); + if (buffer != NULL) break; + } + if (buffer == NULL) { + printf("Error Reading %2d:%2d:%2d\n", param[0], param[1], param[2]); + buffer = bufferz; + buffer[12] = param[0]; + buffer[13] = param[1]; + buffer[14] = param[2]; + buffer[15] = 0x2; + } + } + fwrite(buffer, 1, 2352, f); +#ifdef VERBOSE + count+= CD_FRAMESIZE_RAW; + + printf("reading %2d:%2d:%2d ", param[0], param[1], param[2]); + if ((time(NULL) - Ttime) != 0) { + i = (count / 1024) / (time(NULL) - Ttime); + printf("( %5dKbytes/s, %dX)", i, i / 150); + } + putchar(13); + fflush(stdout); +#endif + + incSector(); + + p++; + per = ((float)p / s); + gtk_progress_bar_update(GTK_PROGRESS_BAR(Progress), per); + while (gtk_events_pending()) gtk_main_iteration(); + if (stop) break; + } + + Ttime = time(NULL) - Ttime; + Tm = gmtime(&Ttime); + printf("\nTotal Time used: %d:%d:%d\n", Tm->tm_hour, Tm->tm_min, + Tm->tm_sec); + + CDR_close(); + fclose(f); + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) SysMessageLoc("Iso Image Created OK"); +} + +void OnCreateZ() { + FILE *f; + FILE *t; + struct stat buf; + struct tm *Tm; + time_t Ttime; + unsigned long ftrack, ltrack; + unsigned long p=0,s,c=0; + unsigned char *buffer; + unsigned char bufferz[2352]; + unsigned char start[4], end[4]; + char table[256]; + char *tmp; + int b, blocks; +#ifdef VERBOSE + unsigned long count = 0; + int i=0; +#endif + + memset(bufferz, 0, sizeof(bufferz)); + ftrack = 1; + ltrack = CD_LEADOUT; + + tmp = gtk_entry_get_text(GTK_ENTRY(Edit)); + strcpy(IsoFile, tmp); + + UpdZmode(); + + if (Zmode == 1) { + blocks = 1; + if (strstr(IsoFile, ".Z") == NULL) strcat(IsoFile, ".Z"); + } else { + blocks = 10; + if (strstr(IsoFile, ".bz") == NULL) strcat(IsoFile, ".bz"); + } + if (stat(IsoFile, &buf) == 0) { + printf("File %s Already exists\n", IsoFile); + return; + } + + strcpy(table, IsoFile); + if (Zmode == 1) strcat(table, ".table"); + else strcat(table, ".index"); + + t = fopen(table, "wb"); + if (t == NULL) { + return; + } + + if (CDR_open() == -1) { + return; + } + + if (CDR_getTD(ftrack, start) == -1) { + printf("Error getting TD\n"); + + CDR_close(); + return; + } + if (CDR_getTD(ltrack, end) == -1) { + printf("Error getting TD\n"); + + CDR_close(); + return; + } + + f = fopen(IsoFile, "wb"); + if (f == NULL) { + CDR_close(); + printf("Error opening %s", IsoFile); + return; + } + + printf("Making Iso: from %2.2d:%2.2d:%2.2d to %2.2d:%2.2d:%2.2d\n", + start[0], start[1], start[2], end[0], end[1], end[2]); + + memcpy(param, start, 3); + + time(&Ttime); + + stop = 0; + s = MSF2SECT(end[0], end[1], end[2]) / blocks; + gtk_widget_set_sensitive(BtnCompress, FALSE); + gtk_widget_set_sensitive(BtnDecompress, FALSE); + gtk_widget_set_sensitive(BtnCreate, FALSE); + gtk_widget_set_sensitive(BtnCreateZ, FALSE); + + for (;;) { /* loop until end */ + unsigned long size; + unsigned char Zbuf[CD_FRAMESIZE_RAW * 10 * 2]; + float per; + + for (b=0; btm_hour, Tm->tm_min, + Tm->tm_sec); + + CDR_close(); + fclose(f); + fclose(t); + + gtk_widget_set_sensitive(BtnCompress, TRUE); + gtk_widget_set_sensitive(BtnDecompress, TRUE); + gtk_widget_set_sensitive(BtnCreate, TRUE); + gtk_widget_set_sensitive(BtnCreateZ, TRUE); + + if (!stop) SysMessageLoc("Compressed Iso Image Created OK"); +} + +long CDRconfigure(void) { + int i; + + LoadConf(); + + ConfDlg = create_Config(); + + Edit = lookup_widget(ConfDlg, "GtkEntry_Iso"); + gtk_entry_set_text(GTK_ENTRY(Edit), IsoFile); + CdEdit = lookup_widget(ConfDlg, "GtkEntry_CdDev"); + gtk_entry_set_text(GTK_ENTRY(CdEdit), CdDev); + + Progress = lookup_widget(ConfDlg, "GtkProgressBar_Progress"); + + BtnCompress = lookup_widget(ConfDlg, "GtkButton_Compress"); + BtnDecompress = lookup_widget(ConfDlg, "GtkButton_Decompress"); + BtnCreate = lookup_widget(ConfDlg, "GtkButton_Create"); + BtnCreateZ = lookup_widget(ConfDlg, "GtkButton_CreateZ"); + + methodlist = NULL; + for (i=0; i<2; i++) + methodlist = g_list_append(methodlist, methods[i]); + Method = lookup_widget(ConfDlg, "GtkCombo_Method"); + gtk_combo_set_popdown_strings(GTK_COMBO(Method), methodlist); + if (strstr(IsoFile, ".Z") != NULL) + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(Method)->entry), methods[0]); + else gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(Method)->entry), methods[1]); + + gtk_widget_show_all(ConfDlg); + gtk_main(); + + return 0; +} + +GtkWidget *AboutDlg; + +void OnAboutOk(GtkMenuItem * menuitem, gpointer userdata) { + gtk_widget_hide(AboutDlg); + gtk_main_quit(); +} + +void CDRabout(void) { + GtkWidget *Label; + GtkWidget *Ok; + GtkWidget *Box, *BBox; + char AboutText[255]; + + sprintf(AboutText, "%s %d.%d\n", LibName, revision, build); + + AboutDlg = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_usize(AboutDlg, 260, 80); + gtk_window_set_title(GTK_WINDOW(AboutDlg), "CDVD About Dialog"); + gtk_window_set_position(GTK_WINDOW(AboutDlg), GTK_WIN_POS_CENTER); + gtk_container_set_border_width(GTK_CONTAINER(AboutDlg), 10); + + Box = gtk_vbox_new(0, 0); + gtk_container_add(GTK_CONTAINER(AboutDlg), Box); + gtk_widget_show(Box); + + Label = gtk_label_new(AboutText); + gtk_box_pack_start(GTK_BOX(Box), Label, FALSE, FALSE, 0); + gtk_widget_show(Label); + + BBox = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), BBox, FALSE, FALSE, 0); + gtk_widget_show(BBox); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect(GTK_OBJECT(Ok), "clicked", + GTK_SIGNAL_FUNC(OnAboutOk), NULL); + gtk_container_add(GTK_CONTAINER(BBox), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(AboutDlg); + gtk_main(); +} + +int main(int argc, char *argv[]) { + if (argc < 2) return 0; + + gtk_init(NULL, NULL); + + if (!strcmp(argv[1], "open")) { + _CDRopen(); + } else if (!strcmp(argv[1], "configure")) { + CDRconfigure(); + } else if (!strcmp(argv[1], "message")) { + if (argc > 2) SysMessageLoc(argv[2]); + } else { + CDRabout(); + } + + return 0; +} + + diff --git a/plugins/CDVDiso/src/Linux/interface.c b/plugins/CDVDiso/src/Linux/interface.c new file mode 100644 index 0000000000..102a70bb77 --- /dev/null +++ b/plugins/CDVDiso/src/Linux/interface.c @@ -0,0 +1,220 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ + g_object_set_data (G_OBJECT (component), name, widget) + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox1; + GtkWidget *hbox1; + GtkWidget *GtkEntry_Iso; + GtkWidget *button5; + GtkWidget *hbox2; + GtkWidget *GtkProgressBar_Progress; + GtkWidget *button6; + GtkWidget *hbox4; + GtkWidget *label2; + GtkWidget *GtkCombo_Method; + GList *GtkCombo_Method_items = NULL; + GtkWidget *combo_entry1; + GtkWidget *hbuttonbox2; + GtkWidget *GtkButton_Compress; + GtkWidget *GtkButton_Decompress; + GtkWidget *hbox3; + GtkWidget *label1; + GtkWidget *GtkEntry_CdDev; + GtkWidget *hbuttonbox3; + GtkWidget *GtkButton_Create; + GtkWidget *GtkButton_CreateZ; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), _("CDVD Config Dialog")); + + vbox1 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox1); + gtk_container_add (GTK_CONTAINER (Config), vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5); + + hbox1 = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0); + + GtkEntry_Iso = gtk_entry_new (); + gtk_widget_show (GtkEntry_Iso); + gtk_box_pack_start (GTK_BOX (hbox1), GtkEntry_Iso, TRUE, TRUE, 0); + + button5 = gtk_button_new_with_mnemonic (_("Select Iso")); + gtk_widget_show (button5); + gtk_box_pack_start (GTK_BOX (hbox1), button5, FALSE, FALSE, 0); + + hbox2 = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox1), hbox2, FALSE, FALSE, 0); + + GtkProgressBar_Progress = gtk_progress_bar_new (); + gtk_widget_show (GtkProgressBar_Progress); + gtk_box_pack_start (GTK_BOX (hbox2), GtkProgressBar_Progress, TRUE, FALSE, 0); + + button6 = gtk_button_new_with_mnemonic (_("Stop")); + gtk_widget_show (button6); + gtk_box_pack_end (GTK_BOX (hbox2), button6, FALSE, FALSE, 0); + + hbox4 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox4); + gtk_box_pack_start (GTK_BOX (vbox1), hbox4, TRUE, TRUE, 0); + + label2 = gtk_label_new (_("Compression Method:")); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (hbox4), label2, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_CENTER); + + GtkCombo_Method = gtk_combo_new (); + g_object_set_data (G_OBJECT (GTK_COMBO (GtkCombo_Method)->popwin), + "GladeParentKey", GtkCombo_Method); + gtk_widget_show (GtkCombo_Method); + gtk_box_pack_start (GTK_BOX (hbox4), GtkCombo_Method, TRUE, FALSE, 0); + GtkCombo_Method_items = g_list_append (GtkCombo_Method_items, (gpointer) ""); + gtk_combo_set_popdown_strings (GTK_COMBO (GtkCombo_Method), GtkCombo_Method_items); + g_list_free (GtkCombo_Method_items); + + combo_entry1 = GTK_COMBO (GtkCombo_Method)->entry; + gtk_widget_show (combo_entry1); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox2, TRUE, TRUE, 0); + + GtkButton_Compress = gtk_button_new_with_mnemonic (_("Compress Iso")); + gtk_widget_show (GtkButton_Compress); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), GtkButton_Compress); + GTK_WIDGET_SET_FLAGS (GtkButton_Compress, GTK_CAN_DEFAULT); + + GtkButton_Decompress = gtk_button_new_with_mnemonic (_("Decompress Iso")); + gtk_widget_show (GtkButton_Decompress); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), GtkButton_Decompress); + GTK_WIDGET_SET_FLAGS (GtkButton_Decompress, GTK_CAN_DEFAULT); + + hbox3 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox3); + gtk_box_pack_start (GTK_BOX (vbox1), hbox3, FALSE, FALSE, 0); + + label1 = gtk_label_new (_("Cdrom Device: ")); + gtk_widget_show (label1); + gtk_box_pack_start (GTK_BOX (hbox3), label1, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_CENTER); + + GtkEntry_CdDev = gtk_entry_new (); + gtk_widget_show (GtkEntry_CdDev); + gtk_box_pack_start (GTK_BOX (hbox3), GtkEntry_CdDev, TRUE, TRUE, 0); + + hbuttonbox3 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox3); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox3, TRUE, TRUE, 0); + + GtkButton_Create = gtk_button_new_with_mnemonic (_("Create Iso")); + gtk_widget_show (GtkButton_Create); + gtk_container_add (GTK_CONTAINER (hbuttonbox3), GtkButton_Create); + GTK_WIDGET_SET_FLAGS (GtkButton_Create, GTK_CAN_DEFAULT); + + GtkButton_CreateZ = gtk_button_new_with_mnemonic (_("Create Compressed Iso")); + gtk_widget_show (GtkButton_CreateZ); + gtk_container_add (GTK_CONTAINER (hbuttonbox3), GtkButton_CreateZ); + GTK_WIDGET_SET_FLAGS (GtkButton_CreateZ, GTK_CAN_DEFAULT); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, TRUE, TRUE, 0); + + button1 = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_from_stock ("gtk-cancel"); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button5, "clicked", + G_CALLBACK (OnFileSel), + NULL); + g_signal_connect ((gpointer) button6, "clicked", + G_CALLBACK (OnStop), + NULL); + g_signal_connect ((gpointer) GtkButton_Compress, "clicked", + G_CALLBACK (OnCompress), + NULL); + g_signal_connect ((gpointer) GtkButton_Decompress, "clicked", + G_CALLBACK (OnDecompress), + NULL); + g_signal_connect ((gpointer) GtkButton_Create, "clicked", + G_CALLBACK (OnCreate), + NULL); + g_signal_connect ((gpointer) GtkButton_CreateZ, "clicked", + G_CALLBACK (OnCreateZ), + NULL); + g_signal_connect ((gpointer) button1, "clicked", + G_CALLBACK (OnOk), + NULL); + g_signal_connect ((gpointer) button2, "clicked", + G_CALLBACK (OnCancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (Config, Config, "Config"); + GLADE_HOOKUP_OBJECT (Config, vbox1, "vbox1"); + GLADE_HOOKUP_OBJECT (Config, hbox1, "hbox1"); + GLADE_HOOKUP_OBJECT (Config, GtkEntry_Iso, "GtkEntry_Iso"); + GLADE_HOOKUP_OBJECT (Config, button5, "button5"); + GLADE_HOOKUP_OBJECT (Config, hbox2, "hbox2"); + GLADE_HOOKUP_OBJECT (Config, GtkProgressBar_Progress, "GtkProgressBar_Progress"); + GLADE_HOOKUP_OBJECT (Config, button6, "button6"); + GLADE_HOOKUP_OBJECT (Config, hbox4, "hbox4"); + GLADE_HOOKUP_OBJECT (Config, label2, "label2"); + GLADE_HOOKUP_OBJECT (Config, GtkCombo_Method, "GtkCombo_Method"); + GLADE_HOOKUP_OBJECT (Config, combo_entry1, "combo_entry1"); + GLADE_HOOKUP_OBJECT (Config, hbuttonbox2, "hbuttonbox2"); + GLADE_HOOKUP_OBJECT (Config, GtkButton_Compress, "GtkButton_Compress"); + GLADE_HOOKUP_OBJECT (Config, GtkButton_Decompress, "GtkButton_Decompress"); + GLADE_HOOKUP_OBJECT (Config, hbox3, "hbox3"); + GLADE_HOOKUP_OBJECT (Config, label1, "label1"); + GLADE_HOOKUP_OBJECT (Config, GtkEntry_CdDev, "GtkEntry_CdDev"); + GLADE_HOOKUP_OBJECT (Config, hbuttonbox3, "hbuttonbox3"); + GLADE_HOOKUP_OBJECT (Config, GtkButton_Create, "GtkButton_Create"); + GLADE_HOOKUP_OBJECT (Config, GtkButton_CreateZ, "GtkButton_CreateZ"); + GLADE_HOOKUP_OBJECT (Config, hbuttonbox1, "hbuttonbox1"); + GLADE_HOOKUP_OBJECT (Config, button1, "button1"); + GLADE_HOOKUP_OBJECT (Config, button2, "button2"); + + return Config; +} + diff --git a/plugins/CDVDiso/src/Linux/interface.h b/plugins/CDVDiso/src/Linux/interface.h new file mode 100644 index 0000000000..3f7353bb70 --- /dev/null +++ b/plugins/CDVDiso/src/Linux/interface.h @@ -0,0 +1,5 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); diff --git a/plugins/CDVDiso/src/Linux/support.c b/plugins/CDVDiso/src/Linux/support.c new file mode 100644 index 0000000000..8a9e2d9fb5 --- /dev/null +++ b/plugins/CDVDiso/src/Linux/support.c @@ -0,0 +1,144 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "support.h" + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (!parent) + parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to find pixmap files. */ +static gchar* +find_pixmap_file (const gchar *filename) +{ + GList *elem; + + /* We step through each of the pixmaps directory to find it. */ + elem = pixmaps_directories; + while (elem) + { + gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, + G_DIR_SEPARATOR_S, filename); + if (g_file_test (pathname, G_FILE_TEST_EXISTS)) + return pathname; + g_free (pathname); + elem = elem->next; + } + return NULL; +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *pathname = NULL; + GtkWidget *pixmap; + + if (!filename || !filename[0]) + return gtk_image_new (); + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return gtk_image_new (); + } + + pixmap = gtk_image_new_from_file (pathname); + g_free (pathname); + return pixmap; +} + +/* This is an internally used function to create pixmaps. */ +GdkPixbuf* +create_pixbuf (const gchar *filename) +{ + gchar *pathname = NULL; + GdkPixbuf *pixbuf; + GError *error = NULL; + + if (!filename || !filename[0]) + return NULL; + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return NULL; + } + + pixbuf = gdk_pixbuf_new_from_file (pathname, &error); + if (!pixbuf) + { + fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", + pathname, error->message); + g_error_free (error); + } + g_free (pathname); + return pixbuf; +} + +/* This is used to set ATK action descriptions. */ +void +glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description) +{ + gint n_actions, i; + + n_actions = atk_action_get_n_actions (action); + for (i = 0; i < n_actions; i++) + { + if (!strcmp (atk_action_get_name (action, i), action_name)) + atk_action_set_description (action, i, description); + } +} + diff --git a/plugins/CDVDiso/src/Linux/support.h b/plugins/CDVDiso/src/Linux/support.h new file mode 100644 index 0000000000..160bae001c --- /dev/null +++ b/plugins/CDVDiso/src/Linux/support.h @@ -0,0 +1,69 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# define Q_(String) g_strip_context ((String), gettext (String)) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define Q_(String) g_strip_context ((String), (String)) +# define N_(String) (String) +#endif + + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps used in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + +/* This is used to create the pixbufs used in the interface. */ +GdkPixbuf* create_pixbuf (const gchar *filename); + +/* This is used to set ATK action descriptions. */ +void glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description); + diff --git a/plugins/CDVDiso/src/Win32/CDVDiso.def b/plugins/CDVDiso/src/Win32/CDVDiso.def new file mode 100644 index 0000000000..23583e964a --- /dev/null +++ b/plugins/CDVDiso/src/Win32/CDVDiso.def @@ -0,0 +1,26 @@ +; CDVDiso.def : Declares the module parameters for the DLL. + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + CDVDinit @5 + CDVDshutdown @6 + CDVDopen @7 + CDVDclose @8 + CDVDreadTrack @9 + CDVDgetBuffer @10 + CDVDreadSubQ @11 + CDVDgetTN @12 + CDVDgetTD @13 + CDVDgetTOC @14 + CDVDgetDiskType @15 + CDVDgetTrayStatus @16 + CDVDctrlTrayOpen @17 + CDVDctrlTrayClose @18 + + CDVDconfigure @19 + CDVDtest @20 + CDVDabout @21 + diff --git a/plugins/CDVDiso/src/Win32/CDVDiso.rc b/plugins/CDVDiso/src/Win32/CDVDiso.rc new file mode 100644 index 0000000000..f43e8764fa --- /dev/null +++ b/plugins/CDVDiso/src/Win32/CDVDiso.rc @@ -0,0 +1,134 @@ +// 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 + +///////////////////////////////////////////////////////////////////////////// +// Spanish (Argentina) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESS) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_ARGENTINA +#pragma code_page(1252) +#endif //_WIN32 + +#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 + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 212, 161 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "CDVDconfigure" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,105,140,50,14 + EDITTEXT IDC_ISOFILE,10,10,145,14,ES_AUTOHSCROLL + PUSHBUTTON "Cancel",IDCANCEL,160,140,50,14 + PUSHBUTTON "Select Iso",IDC_SELECTISO,160,10,45,14 + PUSHBUTTON "Compress Iso",IDC_COMPRESSISO,33,75,65,14 + PUSHBUTTON "Decompress Iso",IDC_DECOMPRESSISO,113,75,65,14 + COMBOBOX IDC_METHOD,120,55,85,50,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",WS_BORDER | + 0x1,10,35,145,14 + LTEXT "Compression Method:",IDC_STATIC,29,57,69,8 + PUSHBUTTON "Stop",IDC_STOP,160,35,45,14 + GROUPBOX "",IDC_STATIC,5,0,205,95 + GROUPBOX "Options",IDC_STATIC,5,100,205,30 + CONTROL "Enable Block Dump => ""ISO name.dump""",IDC_BLOCKDUMP, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,115,148,10 +END + +IDD_ABOUT DIALOG 0, 0, 177, 106 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "CDVDabout" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,85,50,14 + LTEXT "CDVDiso Driver",IDC_NAME,70,10,50,8 + GROUPBOX "",IDC_STATIC,5,35,170,40 + LTEXT "Thanks to:\n mooby - coding hints and .bz support\n Brenden Conte - linux conf bugfix", + IDC_STATIC,10,45,160,25 + LTEXT "Author: linuzappz ",IDC_STATIC, + 20,20,141,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 154 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 170 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Spanish (Argentina) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/CDVDiso/src/Win32/CDVDiso_vs2008.vcproj b/plugins/CDVDiso/src/Win32/CDVDiso_vs2008.vcproj new file mode 100644 index 0000000000..07e51b05cf --- /dev/null +++ b/plugins/CDVDiso/src/Win32/CDVDiso_vs2008.vcproj @@ -0,0 +1,810 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/CDVDiso/src/Win32/Config.c b/plugins/CDVDiso/src/Win32/Config.c new file mode 100644 index 0000000000..3786568eba --- /dev/null +++ b/plugins/CDVDiso/src/Win32/Config.c @@ -0,0 +1,47 @@ +#include +#include + +#include "../CDVDiso.h" + +#define GetKeyV(name, var, s, t) \ + size = s; type = t; \ + RegQueryValueEx(myKey, name, 0, &type, (LPBYTE) var, &size); + +#define GetKeyVdw(name, var) \ + GetKeyV(name, var, 4, REG_DWORD); + +#define SetKeyV(name, var, s, t) \ + RegSetValueEx(myKey, name, 0, t, (LPBYTE) var, s); + +#define SetKeyVdw(name, var) \ + SetKeyV(name, var, 4, REG_DWORD); + +void SaveConf() { + HKEY myKey; + DWORD myDisp; + + RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\CDVD\\CDVDiso", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &myKey, &myDisp); + + SetKeyV("IsoFile", IsoFile, sizeof(IsoFile), REG_BINARY); + SetKeyV("CurrentWorkingFolder", IsoCWD, sizeof(IsoCWD), REG_BINARY); + SetKeyVdw("BlockDump", &BlockDump); + + RegCloseKey(myKey); +} + +void LoadConf() { + HKEY myKey; + DWORD type, size; + + memset(IsoFile, 0, sizeof(IsoFile)); + + if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\PS2Eplugin\\CDVD\\CDVDiso", 0, KEY_ALL_ACCESS, &myKey)!=ERROR_SUCCESS) { + SaveConf(); return; + } + + GetKeyV("IsoFile", IsoFile, sizeof(IsoFile), REG_BINARY); + GetKeyV("CurrentWorkingFolder", IsoCWD, sizeof(IsoCWD), REG_BINARY); + GetKeyVdw("BlockDump", &BlockDump); + + RegCloseKey(myKey); +} diff --git a/plugins/CDVDiso/src/Win32/Config.h b/plugins/CDVDiso/src/Win32/Config.h new file mode 100644 index 0000000000..0ce9be191d --- /dev/null +++ b/plugins/CDVDiso/src/Win32/Config.h @@ -0,0 +1,3 @@ +void SaveConf(); +void LoadConf(); + diff --git a/plugins/CDVDiso/src/Win32/Makefile b/plugins/CDVDiso/src/Win32/Makefile new file mode 100644 index 0000000000..483698ad3a --- /dev/null +++ b/plugins/CDVDiso/src/Win32/Makefile @@ -0,0 +1,57 @@ +# +# Makefile for MINGW32 +# + + +all: cdvdiso + +PLUGIN = CDVDiso.dll + +CC = gcc +NASM = nasmw +RM = rm -f +AR = ar +STRIP = strip +RC = windres + +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing +FLAGS = -D__WIN32__ -D__MINGW32__ # -DENABLE_NLS -DPACKAGE=\"pcsx2\" +RC1FLAGS = -d__MINGW32__ +LIBS = -L./ -lcomctl32 -lwsock32 -lwinmm -lgdi32 -lcomdlg32 #-lintl +RESOBJ = cdvdiso.o + +OBJS = ../CDVDiso.o ../libiso.o +OBJS+= Config.o Win32.o ${RESOBJ} +OBJS+= ../zlib/adler32.o ../zlib/compress.o ../zlib/crc32.o ../zlib/gzio.o ../zlib/uncompr.o ../zlib/deflate.o ../zlib/trees.o \ + ../zlib/zutil.o ../zlib/inflate.o ../zlib/infback.o ../zlib/inftrees.o ../zlib/inffast.o +OBJS+= ../bzip2/blocksort.o ../bzip2/bzlib.o \ + ../bzip2/compress.o ../bzip2/crctable.o \ + ../bzip2/decompress.o ../bzip2/huffman.o \ + ../bzip2/randtable.o + +DEPS:= $(OBJS:.o=.d) + +CFLAGS = -Wall ${OPTIMIZE} -I. -I.. -I/usr/local/include -I../zlib -I../bzip2 ${FLAGS} + +cdvdiso: ${OBJS} + dllwrap --def plugin.def -o ${PLUGIN} ${OBJS} ${LIBS} +# ${CC} -shared -Wl,--kill-at,--output-def,plugin.def ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} + ${STRIP} ${PLUGIN} + +.PHONY: clean cdvdiso + +clean: + ${RM} ${OBJS} ${DEPS} ${PCSX2} + +%.o: %.asm + ${NASM} ${ASMFLAGS} -o $@ $< + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +${RESOBJ}: CDVDiso.rc + ${RC} -D__MINGW32__ -I rc -O coff -o $@ -i $< + +-include ${DEPS} + + \ No newline at end of file diff --git a/plugins/CDVDiso/src/Win32/Win32.c b/plugins/CDVDiso/src/Win32/Win32.c new file mode 100644 index 0000000000..5e9d87441c --- /dev/null +++ b/plugins/CDVDiso/src/Win32/Win32.c @@ -0,0 +1,353 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zlib/zlib.h" + + +#include "Config.h" +#include "CDVDiso.h" +#include "resource.h" + +HINSTANCE hInst; +#define MAXFILENAME 256 + +u8 Zbuf[2352 * 10 * 2]; +HWND hDlg; +HWND hProgress; +HWND hIsoFile; +HWND hMethod; +HWND hBlockDump; +int stop; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "CDVDiso Msg", 0); +} + +int _GetFile(char *out) { + OPENFILENAME ofn; + char szFileName[MAXFILENAME]; + char szFileTitle[MAXFILENAME]; + + memset(&szFileName, 0, sizeof(szFileName)); + memset(&szFileTitle, 0, sizeof(szFileTitle)); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = GetActiveWindow(); + ofn.lpstrFilter = + "Supported Formats\0*.bin;*.iso;*.img;*.nrg;*.mdf;*.Z;*.Z2;*.BZ2;*.dump\0" + "Cd Iso Format (*.bin;*.iso;*.img;*.nrg;*.mdf)\0" + "*.bin;*.iso;*.img;*.nrg;*.mdf\0" + "Compressed Z Iso Format (*.Z;*.Z2)\0" + "*.Z;*.Z2\0Compressed BZ Iso Format (*.BZ2)\0" + "*.BZ2\0Block Dumps (*.dump)\0*.dump\0All Files\0*.*\0"; + + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = MAXFILENAME; + ofn.lpstrInitialDir = ( IsoCWD[0] == 0 ) ? NULL : IsoCWD; + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = MAXFILENAME; + ofn.lpstrTitle = NULL; + ofn.lpstrDefExt = NULL; + ofn.Flags = OFN_HIDEREADONLY; + + if(GetOpenFileName ((LPOPENFILENAME)&ofn)) + { + strcpy(out, szFileName); + return 1; + } + + return 0; +} + +int _OpenFile( int saveConf ) { + + int retval = 0; + + // for saving the pcsx2 current working directory; + char* cwd_pcsx2 = _getcwd( NULL, MAXFILENAME ); + + if( IsoCWD[0] != 0 ) + _chdir( IsoCWD ); + + if (_GetFile(IsoFile) == 1) + { + // Save the user's new cwd: + if( _getcwd( IsoCWD, MAXFILENAME ) == NULL ) + IsoCWD[0] = 0; + + if( saveConf ) + SaveConf(); + + retval = 1; + } + + // Restore Pcsx2's path. + if( cwd_pcsx2 != NULL ) + { + _chdir( cwd_pcsx2 ); + free( cwd_pcsx2 ); + cwd_pcsx2 = NULL; + } + return retval; +} + +void CfgOpenFile() { + _OpenFile( TRUE ); +} + +void UpdZmode() { + if (ComboBox_GetCurSel(hMethod) == 0) { + Zmode = 1; + } else { + Zmode = 2; + } +} + + +void SysUpdate() { + MSG msg; + + while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void OnCompress() { + u32 lsn; + u8 cdbuff[10*2352]; + char Zfile[256]; + int ret; + isoFile *src; + isoFile *dst; + + Edit_GetText(hIsoFile, IsoFile, 256); + UpdZmode(); + + if (Zmode == 1) { + sprintf(Zfile, "%s.Z2", IsoFile); + } else { + sprintf(Zfile, "%s.BZ2", IsoFile); + } + + src = isoOpen(IsoFile); + if (src == NULL) return; + if (Zmode == 1) { + dst = isoCreate(Zfile, ISOFLAGS_Z2); + } else { + dst = isoCreate(Zfile, ISOFLAGS_BZ2); + } + if (dst == NULL) return; + + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), FALSE); + stop=0; + + for (lsn = 0; lsnblocks; lsn++) { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + + SendMessage(hProgress, PBM_SETPOS, (lsn * 100) / src->blocks, 0); + SysUpdate(); + if (stop) break; + } + isoClose(src); + isoClose(dst); + + if (!stop) Edit_SetText(hIsoFile, Zfile); + + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), TRUE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), TRUE); + + if (!stop) { + if (ret == -1) { + SysMessage("Error compressing iso image"); + } else { + SysMessage("Iso image compressed OK"); + } + } +} + +void OnDecompress() { + char file[256]; + u8 cdbuff[10*2352]; + u32 lsn; + isoFile *src; + isoFile *dst; + int ret; + + Edit_GetText(hIsoFile, IsoFile, 256); + + src = isoOpen(IsoFile); + if (src == NULL) return; + + strcpy(file, IsoFile); + if (src->flags & ISOFLAGS_Z) { + file[strlen(file) - 2] = 0; + } else + if (src->flags & ISOFLAGS_Z2) { + file[strlen(file) - 3] = 0; + } else + if (src->flags & ISOFLAGS_BZ2) { + file[strlen(file) - 3] = 0; + } else { + SysMessage("%s is not a compressed image", IsoFile); + return; + } + + dst = isoCreate(file, 0); + if (dst == NULL) return; + + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), FALSE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), FALSE); + stop=0; + + for (lsn = 0; lsnblocks; lsn++) { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + + SendMessage(hProgress, PBM_SETPOS, (lsn * 100) / src->blocks, 0); + SysUpdate(); + if (stop) break; + } + if (!stop) Edit_SetText(hIsoFile, file); + + isoClose(src); + isoClose(dst); + + Button_Enable(GetDlgItem(hDlg, IDC_COMPRESSISO), TRUE); + Button_Enable(GetDlgItem(hDlg, IDC_DECOMPRESSISO), TRUE); + + if (!stop) { + if (ret == -1) { + SysMessage("Error decompressing iso image"); + } else { + SysMessage("Iso image decompressed OK"); + } + } +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + int i; + + switch(uMsg) { + case WM_INITDIALOG: + hDlg = hW; + LoadConf(); + + hProgress = GetDlgItem(hW, IDC_PROGRESS); + hIsoFile = GetDlgItem(hW, IDC_ISOFILE); + hMethod = GetDlgItem(hW, IDC_METHOD); + hBlockDump = GetDlgItem(hW, IDC_BLOCKDUMP); + + for (i=0; methods[i] != NULL; i++) { + ComboBox_AddString(hMethod, methods[i]); + } + + Edit_SetText(hIsoFile, IsoFile); + ComboBox_SetCurSel(hMethod, 0); +/* if (strstr(IsoFile, ".Z") != NULL) + ComboBox_SetCurSel(hMethod, 1); + else ComboBox_SetCurSel(hMethod, 0);*/ + Button_SetCheck(hBlockDump, BlockDump); + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDC_SELECTISO: + if( _OpenFile(FALSE) == 1 ) + Edit_SetText(hIsoFile, IsoFile); + return TRUE; + + case IDC_COMPRESSISO: + OnCompress(); + return TRUE; + + case IDC_DECOMPRESSISO: + OnDecompress(); + return TRUE; + + case IDC_STOP: + stop = 1; + return TRUE; + + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + + case IDOK: + Edit_GetText(hIsoFile, IsoFile, 256); + BlockDump = Button_GetCheck(hBlockDump); + + SaveConf(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +EXPORT_C(void) CDVDconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, TRUE); + return FALSE; + } + } + return FALSE; +} + +EXPORT_C(void) CDVDabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + diff --git a/plugins/CDVDiso/src/Win32/afxresmw.h b/plugins/CDVDiso/src/Win32/afxresmw.h new file mode 100644 index 0000000000..8a4b9df35b --- /dev/null +++ b/plugins/CDVDiso/src/Win32/afxresmw.h @@ -0,0 +1,5 @@ + +#include +#include + +#define IDC_STATIC (-1) diff --git a/plugins/CDVDiso/src/Win32/resource.h b/plugins/CDVDiso/src/Win32/resource.h new file mode 100644 index 0000000000..fe2358810f --- /dev/null +++ b/plugins/CDVDiso/src/Win32/resource.h @@ -0,0 +1,28 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by CDVDiso.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_ISOFILE 1000 +#define IDC_SELECTISO 1001 +#define IDC_COMPRESSISO 1002 +#define IDC_DECOMPRESSISO 1003 +#define IDC_METHOD 1004 +#define IDC_PROGRESS 1005 +#define IDC_STOP 1006 +#define IDC_BLOCKDUMP 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1008 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif + diff --git a/plugins/CDVDiso/src/Win32/vsprops/pcsx2_plugin_common.vsprops b/plugins/CDVDiso/src/Win32/vsprops/pcsx2_plugin_common.vsprops new file mode 100644 index 0000000000..086133a60a --- /dev/null +++ b/plugins/CDVDiso/src/Win32/vsprops/pcsx2_plugin_common.vsprops @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/plugins/CDVDiso/src/Win32/vsprops/postBuild.tmpl b/plugins/CDVDiso/src/Win32/vsprops/postBuild.tmpl new file mode 100644 index 0000000000..b0f9fb472f --- /dev/null +++ b/plugins/CDVDiso/src/Win32/vsprops/postBuild.tmpl @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%\%3-r$WCREV$$WCMODS?m:$%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/CDVDiso/src/Win32/vsprops/postBuild.unknown b/plugins/CDVDiso/src/Win32/vsprops/postBuild.unknown new file mode 100644 index 0000000000..360b05cad5 --- /dev/null +++ b/plugins/CDVDiso/src/Win32/vsprops/postBuild.unknown @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%%3%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/CDVDiso/src/Win32/vsprops/preBuild.cmd b/plugins/CDVDiso/src/Win32/vsprops/preBuild.cmd new file mode 100644 index 0000000000..fea16bd143 --- /dev/null +++ b/plugins/CDVDiso/src/Win32/vsprops/preBuild.cmd @@ -0,0 +1,20 @@ +@echo off + +rem Usage: preBuild.cmd ProjectSrcDir VspropsDir +rem +rem ProjectSrcDir - $(ProjectDir)\.. - Directory of project source code. +rem VspropsDir - $(PrjectDir)\vsprops - Directory of this script and its counterparts. + +SubWCRev.exe %1 %2\svnrev_template.h %1\svnrev.h +if not ERRORLEVEL 0 ( + echo Automatic revision update unavailable, using generic template instead. + echo You can safely ignore this message - see svnrev.h for details. + copy /Y %2\svnrev_unknown.h %1\svnrev.h + copy /Y %2\postBuild.unknown %2\postBuild.cmd +) else ( + SubWCRev.exe %1 %2\postBuild.tmpl %2\postBuild.cmd +) + +rem Clear the error level -- this allows compilation to continue if SubWCRev failed. + +set ERRORLEVEL=0 diff --git a/plugins/CDVDiso/src/Win32/vsprops/svnrev_template.h b/plugins/CDVDiso/src/Win32/vsprops/svnrev_template.h new file mode 100644 index 0000000000..afab6c4fd1 --- /dev/null +++ b/plugins/CDVDiso/src/Win32/vsprops/svnrev_template.h @@ -0,0 +1,18 @@ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ +#define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/CDVDiso/src/Win32/vsprops/svnrev_unknown.h b/plugins/CDVDiso/src/Win32/vsprops/svnrev_unknown.h new file mode 100644 index 0000000000..a2a3703186 --- /dev/null +++ b/plugins/CDVDiso/src/Win32/vsprops/svnrev_unknown.h @@ -0,0 +1,23 @@ +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 +#define SVN_MODS "" \ No newline at end of file diff --git a/plugins/CDVDiso/src/common/PS2Edefs.h b/plugins/CDVDiso/src/common/PS2Edefs.h new file mode 100644 index 0000000000..1f65fc02b9 --- /dev/null +++ b/plugins/CDVDiso/src/common/PS2Edefs.h @@ -0,0 +1,885 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/CDVDiso/src/common/PS2Etypes.h b/plugins/CDVDiso/src/common/PS2Etypes.h new file mode 100644 index 0000000000..59be1c3de4 --- /dev/null +++ b/plugins/CDVDiso/src/common/PS2Etypes.h @@ -0,0 +1,219 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/CDVDiso/src/libiso.c b/plugins/CDVDiso/src/libiso.c new file mode 100644 index 0000000000..627193451a --- /dev/null +++ b/plugins/CDVDiso/src/libiso.c @@ -0,0 +1,933 @@ +#define __USE_LARGEFILE64 +#define __USE_FILE_OFFSET64 +#define _FILE_OFFSET_BITS 64 + +#ifdef _WIN32 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include "3rdparty/zlib/zlib.h" +#include "3rdparty/bzip2/bzlib.h" + +#include "common/PS2Etypes.h" +#include "CDVDiso.h" +#include "libiso.h" + +/* some structs from libcdvd by Hiryu & Sjeep (C) 2002 */ + +#if defined(_WIN32) +#pragma pack(1) +#endif + +struct rootDirTocHeader +{ + u16 length; //+00 + u32 tocLBA; //+02 + u32 tocLBA_bigend; //+06 + u32 tocSize; //+0A + u32 tocSize_bigend; //+0E + u8 dateStamp[8]; //+12 + u8 reserved[6]; //+1A + u8 reserved2; //+20 + u8 reserved3; //+21 +#if defined(_WIN32) +}; //+22 +#else +} __attribute__((packed)); +#endif + +struct asciiDate +{ + char year[4]; + char month[2]; + char day[2]; + char hours[2]; + char minutes[2]; + char seconds[2]; + char hundreths[2]; + char terminator[1]; +#if defined(_WIN32) +}; +#else +} __attribute__((packed)); +#endif + +struct cdVolDesc +{ + u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL + u8 volID[5]; // "CD001" + u8 reserved2; + u8 reserved3; + u8 sysIdName[32]; + u8 volName[32]; // The ISO9660 Volume Name + u8 reserved5[8]; + u32 volSize; // Volume Size + u32 volSizeBig; // Volume Size Big-Endian + u8 reserved6[32]; + u32 unknown1; + u32 unknown1_bigend; + u16 volDescSize; //+80 + u16 volDescSize_bigend; //+82 + u32 unknown3; //+84 + u32 unknown3_bigend; //+88 + u32 priDirTableLBA; // LBA of Primary Dir Table //+8C + u32 reserved7; //+90 + u32 secDirTableLBA; // LBA of Secondary Dir Table //+94 + u32 reserved8; //+98 + struct rootDirTocHeader rootToc; + u8 volSetName[128]; + u8 publisherName[128]; + u8 preparerName[128]; + u8 applicationName[128]; + u8 copyrightFileName[37]; + u8 abstractFileName[37]; + u8 bibliographyFileName[37]; + struct asciiDate creationDate; + struct asciiDate modificationDate; + struct asciiDate effectiveDate; + struct asciiDate expirationDate; + u8 reserved10; + u8 reserved11[1166]; +#if defined(_WIN32) +}; +#else +} __attribute__((packed)); +#endif + + +#ifdef _WIN32 +void *_openfile(const char *filename, int flags) { + HANDLE handle; + +// printf("_openfile %s, %d\n", filename, flags & O_RDONLY); + if (flags & O_WRONLY) { + int _flags = CREATE_NEW; + if (flags & O_CREAT) _flags = CREATE_ALWAYS; + handle = CreateFile(filename, GENERIC_WRITE, 0, NULL, _flags, 0, NULL); + } else { + handle = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + } + + return handle == INVALID_HANDLE_VALUE ? NULL : handle; +} + +u64 _tellfile(void *handle) { + u64 ofs; + PLONG _ofs = (LONG*)&ofs; + _ofs[1] = 0; + _ofs[0] = SetFilePointer(handle, 0, &_ofs[1], FILE_CURRENT); + return ofs; +} + +int _seekfile(void *handle, u64 offset, int whence) { + u64 ofs = (u64)offset; + PLONG _ofs = (LONG*)&ofs; +// printf("_seekfile %p, %d_%d\n", handle, _ofs[1], _ofs[0]); + if (whence == SEEK_SET) { + SetFilePointer(handle, _ofs[0], &_ofs[1], FILE_BEGIN); + } else { + SetFilePointer(handle, _ofs[0], &_ofs[1], FILE_END); + } + return 0; +} + +int _readfile(void *handle, void *dst, int size) { + DWORD ret; + +// printf("_readfile %p %d\n", handle, size); + ReadFile(handle, dst, size, &ret, NULL); +// printf("_readfile ret %d; %d\n", ret, GetLastError()); + return ret; +} + +int _writefile(void *handle, void *src, int size) { + DWORD ret; + +// printf("_writefile %p, %d\n", handle, size); +// _seekfile(handle, _tellfile(handle)); + WriteFile(handle, src, size, &ret, NULL); +// printf("_writefile ret %d\n", ret); + return ret; +} + +void _closefile(void *handle) { + CloseHandle(handle); +} + +#else + +void *_openfile(const char *filename, int flags) { + printf("_openfile %s %x\n", filename, flags); + +#ifdef _WIN32 + if (flags & O_WRONLY) + return fopen64(filename, "wb"); + else return fopen64(filename, "rb"); +#else + if (flags & O_WRONLY) + return fopen64(filename, "wb"); + else return fopen64(filename, "rb"); +#endif +} + +#include + +u64 _tellfile(void *handle) { + u64 cursize = ftell(handle); + if(cursize == -1 ) { + // try 64bit + cursize = ftello64(handle); + if( cursize < -1 ) { + // zero top 32 bits + cursize &= 0xffffffff; + } + } + return cursize; +} + +int _seekfile(void *handle, u64 offset, int whence) { + int seekerr = fseeko64(handle, offset, whence); + if( seekerr == -1 ) + printf("failed to seek\n"); + return seekerr; +} + +int _readfile(void *handle, void *dst, int size) { + return fread(dst, 1, size, handle); +} + +int _writefile(void *handle, void *src, int size) { + return fwrite(src, 1, size, handle); +} + +void _closefile(void *handle) { + fclose(handle); +} + +#endif + +int detect(isoFile *iso) { + u8 buf[2448]; + struct cdVolDesc *volDesc; + + if (isoReadBlock(iso, buf, 16) == -1) return -1; + volDesc = (struct cdVolDesc *)(buf + 24); + if (strncmp((char*)volDesc->volID, "CD001", 5)) return 0; + + if (volDesc->rootToc.tocSize == 2048) { + iso->type = ISOTYPE_CD; + } else { + iso->type = ISOTYPE_DVD; + } + + return 1; +} + +int _isoReadZtable(isoFile *iso) { + void *handle; + char table[256]; + int size; + + sprintf(table, "%s.table", iso->filename); + handle = _openfile(table, O_RDONLY); + if (handle == NULL) { + printf("Error loading %s\n", table); + return -1; + } + + _seekfile(handle, 0, SEEK_END); + size = _tellfile(handle); + iso->Ztable = (char*)malloc(size); + if (iso->Ztable == NULL) { + return -1; + } + + _seekfile(handle, 0, SEEK_SET); + _readfile(handle, iso->Ztable, size); + _closefile(handle); + + iso->blocks = size / 6; + + return 0; +} + +int _isoReadZ2table(isoFile *iso) { + void *handle; + char table[256]; + u32 *Ztable; + int ofs; + int size; + int i; + + sprintf(table, "%s.table", iso->filename); + handle = _openfile(table, O_RDONLY); + if (handle == NULL) { + printf("Error loading %s\n", table); + return -1; + } + + _seekfile(handle, 0, SEEK_END); + size = _tellfile(handle); + Ztable = (u32*)malloc(size); + if (Ztable == NULL) { + return -1; + } + + _seekfile(handle, 0, SEEK_SET); + _readfile(handle, Ztable, size); + _closefile(handle); + + iso->Ztable = (char*)malloc(iso->blocks*8); + if (iso->Ztable == NULL) { + return -1; + } + + ofs=16; + for (i=0; iblocks; i++) { + *(u32*)&iso->Ztable[i*8+0] = ofs; + *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; + ofs+= Ztable[i]; + } + free(Ztable); + + return 0; +} + +int _isoReadBZ2table(isoFile *iso) { + void *handle; + char table[256]; + u32 *Ztable; + int ofs; + int size; + int i; + + sprintf(table, "%s.table", iso->filename); + handle = _openfile(table, O_RDONLY); + if (handle == NULL) { + printf("Error loading %s\n", table); + return -1; + } + + _seekfile(handle, 0, SEEK_END); + size = _tellfile(handle); + Ztable = (u32*)malloc(size); + if (Ztable == NULL) { + return -1; + } + + _seekfile(handle, 0, SEEK_SET); + _readfile(handle, Ztable, size); + _closefile(handle); + + iso->Ztable = (char*)malloc(iso->blocks*8); + if (iso->Ztable == NULL) { + return -1; + } + + ofs=16; + for (i=0; iblocks/16; i++) { + *(u32*)&iso->Ztable[i*8+0] = ofs; + *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; + ofs+= Ztable[i]; + } + if (iso->blocks & 0xf) { + *(u32*)&iso->Ztable[i*8+0] = ofs; + *(u32*)&iso->Ztable[i*8+4] = Ztable[i]; + ofs+= Ztable[i]; + } + free(Ztable); + + return 0; +} + +int _isoReadDtable(isoFile *iso) { + int ret; + int i; + + _seekfile(iso->handle, 0, SEEK_END); + iso->dtablesize = (_tellfile(iso->handle) - 16) / (iso->blocksize+4); + iso->dtable = (u32*)malloc(iso->dtablesize*4); + + for (i=0; idtablesize; i++) { + _seekfile(iso->handle, 16+(iso->blocksize+4)*i, SEEK_SET); + ret = _readfile(iso->handle, &iso->dtable[i], 4); + if (ret < 4) { + return -1; + } + } + + return 0; +} + +int isoDetect(isoFile *iso) { // based on florin's CDVDbin detection code :) + char buf[32]; + int len; + + iso->type = ISOTYPE_ILLEGAL; + + len = strlen(iso->filename); + if (len >= 2) { + if (!strncmp(iso->filename+(len-2), ".Z", 2)) { + iso->flags = ISOFLAGS_Z; + iso->blocksize = 2352; + _isoReadZtable(iso); + return detect(iso) == 1 ? 0 : -1; + } + } + + _seekfile(iso->handle, 0, SEEK_SET); + _readfile(iso->handle, buf, 4); + if (strncmp(buf, "BDV2", 4) == 0) { + iso->flags = ISOFLAGS_BLOCKDUMP; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + _isoReadDtable(iso); + return detect(iso) == 1 ? 0 : -1; + } else + if (strncmp(buf, "Z V2", 4) == 0) { + iso->flags = ISOFLAGS_Z2; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + _isoReadZ2table(iso); + return detect(iso) == 1 ? 0 : -1; + } else + if (strncmp(buf, "BZV2", 4) == 0) { + iso->flags = ISOFLAGS_BZ2; + _readfile(iso->handle, &iso->blocksize, 4); + _readfile(iso->handle, &iso->blocks, 4); + _readfile(iso->handle, &iso->blockofs, 4); + iso->buflsn = -1; + iso->buffer = (u8*)malloc(iso->blocksize*16); + if (iso->buffer == NULL) return -1; + _isoReadBZ2table(iso); + return detect(iso) == 1 ? 0 : -1; + } else { + iso->blocks = 16; + } + + // ISO 2048 + iso->blocksize = 2048; iso->offset = 0; iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // RAW 2336 + iso->blocksize = 2336; iso->offset = 0; iso->blockofs = 16; + if (detect(iso) == 1) return 0; + + // RAW 2352 + iso->blocksize = 2352; iso->offset = 0; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // RAWQ 2448 + iso->blocksize = 2448; iso->offset = 0; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // NERO ISO 2048 + iso->blocksize = 2048; iso->offset = 150*2048; iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // NERO RAW 2352 + iso->blocksize = 2352; iso->offset = 150*2048; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // NERO RAWQ 2448 + iso->blocksize = 2448; iso->offset = 150*2048; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // ISO 2048 + iso->blocksize = 2048; iso->offset = -8; iso->blockofs = 24; + if (detect(iso) == 1) return 0; + + // RAW 2352 + iso->blocksize = 2352; iso->offset = -8; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + // RAWQ 2448 + iso->blocksize = 2448; iso->offset = -8; iso->blockofs = 0; + if (detect(iso) == 1) return 0; + + iso->offset = 0; + iso->blocksize = 2352; + iso->type = ISOTYPE_AUDIO; + return 0; + + return -1; +} + +isoFile *isoOpen(const char *filename) { + isoFile *iso; + int i; + + iso = (isoFile*)malloc(sizeof(isoFile)); + if (iso == NULL) return NULL; + + memset(iso, 0, sizeof(isoFile)); + strcpy(iso->filename, filename); + + iso->handle = _openfile(iso->filename, O_RDONLY); + if (iso->handle == NULL) { + printf("Errorr loading %s\n", iso->filename); + return NULL; + } + + if (isoDetect(iso) == -1) return NULL; + + printf("detected blocksize = %d\n", iso->blocksize); + + if (strlen(iso->filename) > 3 && + strncmp(iso->filename + (strlen(iso->filename) - 3), "I00", 3) == 0) { + _closefile(iso->handle); + iso->flags|= ISOFLAGS_MULTI; + iso->blocks = 0; + for (i=0; i<8; i++) { + iso->filename[strlen(iso->filename) - 1] = '0' + i; + iso->multih[i].handle = _openfile(iso->filename, O_RDONLY); + if (iso->multih[i].handle == NULL) { + break; + } + iso->multih[i].slsn = iso->blocks; + _seekfile(iso->multih[i].handle, 0, SEEK_END); + iso->blocks+= (u32)((_tellfile(iso->multih[i].handle) - iso->offset) / + (iso->blocksize)); + iso->multih[i].elsn = iso->blocks-1; + } + + if (i == 0) { + return NULL; + } + } + + if (iso->flags == 0) { + _seekfile(iso->handle, 0, SEEK_END); + iso->blocks = (u32)((_tellfile(iso->handle) - iso->offset) / + (iso->blocksize)); + } + + + printf("isoOpen: %s ok\n", iso->filename); + printf("offset = %d\n", iso->offset); + printf("blockofs = %d\n", iso->blockofs); + printf("blocksize = %d\n", iso->blocksize); + printf("blocks = %d\n", iso->blocks); + printf("type = %d\n", iso->type); + + return iso; +} + +isoFile *isoCreate(const char *filename, int flags) { + isoFile *iso; + char Zfile[256]; + + iso = (isoFile*)malloc(sizeof(isoFile)); + if (iso == NULL) return NULL; + + memset(iso, 0, sizeof(isoFile)); + strcpy(iso->filename, filename); + iso->flags = flags; + iso->offset = 0; + iso->blockofs = 24; + iso->blocksize = CD_FRAMESIZE_RAW; + iso->blocksize = 2048; + + if (iso->flags & (ISOFLAGS_Z | ISOFLAGS_Z2 | ISOFLAGS_BZ2)) { + sprintf(Zfile, "%s.table", iso->filename); + iso->htable = _openfile(Zfile, O_WRONLY); + if (iso->htable == NULL) { + return NULL; + } + } + + iso->handle = _openfile(iso->filename, O_WRONLY | O_CREAT); + if (iso->handle == NULL) { + printf("Error loading %s\n", iso->filename); + return NULL; + } + printf("isoCreate: %s ok\n", iso->filename); + printf("offset = %d\n", iso->offset); + + return iso; +} + +int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks) { + iso->blocksize = blocksize; + iso->blocks = blocks; + iso->blockofs = blockofs; + printf("blockofs = %d\n", iso->blockofs); + printf("blocksize = %d\n", iso->blocksize); + printf("blocks = %d\n", iso->blocks); + if (iso->flags & ISOFLAGS_Z2) { + if (_writefile(iso->handle, "Z V2", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; + } + if (iso->flags & ISOFLAGS_BZ2) { + if (_writefile(iso->handle, "BZV2", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; + iso->buflsn = -1; + iso->buffer = (u8*)malloc(iso->blocksize*16); + if (iso->buffer == NULL) return -1; + } + if (iso->flags & ISOFLAGS_BLOCKDUMP) { + if (_writefile(iso->handle, "BDV2", 4) < 4) return -1; + if (_writefile(iso->handle, &blocksize, 4) < 4) return -1; + if (_writefile(iso->handle, &blocks, 4) < 4) return -1; + if (_writefile(iso->handle, &blockofs, 4) < 4) return -1; + } + + return 0; +} + +s32 MSFtoLSN(u8 *Time) { + u32 lsn; + + lsn = Time[2]; + lsn+=(Time[1] - 2) * 75; + lsn+= Time[0] * 75 * 60; + return lsn; +} + +void LSNtoMSF(u8 *Time, s32 lsn) { + u8 m, s, f; + + lsn += 150; + m = lsn / 4500; // minuten + lsn = lsn - m * 4500; // minuten rest + s = lsn / 75; // sekunden + f = lsn - (s * 75); // sekunden rest + Time[0] = itob(m); Time[1] = itob(s); Time[2] = itob(f); +} + +int _isoReadBlock(isoFile *iso, u8 *dst, int lsn) { + u64 ofs = (u64)lsn * iso->blocksize + iso->offset; + int ret; + +// printf("_isoReadBlock %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); + memset(dst, 0, iso->blockofs); + _seekfile(iso->handle, ofs, SEEK_SET); + ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); + if (ret < iso->blocksize) { + printf("read error %d\n", ret); + return -1; + } + + return 0; +} + +int _isoReadBlockZ(isoFile *iso, u8 *dst, int lsn) { + u32 pos, p; + uLongf size; + u8 Zbuf[CD_FRAMESIZE_RAW*2]; + int ret; + +// printf("_isoReadBlockZ %d, %d\n", lsn, iso->blocksize); + pos = *(unsigned long*)&iso->Ztable[lsn * 6]; + p = *(unsigned short*)&iso->Ztable[lsn * 6 + 4]; +// printf("%d, %d\n", pos, p); + _seekfile(iso->handle, pos, SEEK_SET); + ret = _readfile(iso->handle, Zbuf, p); + if (ret < p) { + printf("error reading block!!\n"); + return -1; + } + + size = CD_FRAMESIZE_RAW; + uncompress(dst, &size, Zbuf, p); + + return 0; +} + +int _isoReadBlockZ2(isoFile *iso, u8 *dst, int lsn) { + u32 pos, p; + uLongf size; + u8 Zbuf[16*1024]; + int ret; + +// printf("_isoReadBlockZ2 %d, %d\n", lsn, iso->blocksize); + pos = *(u32*)&iso->Ztable[lsn*8]; + p = *(u32*)&iso->Ztable[lsn*8+4]; +// printf("%d, %d\n", pos, p); + _seekfile(iso->handle, pos, SEEK_SET); + ret = _readfile(iso->handle, Zbuf, p); + if (ret < p) { + printf("error reading block!!\n"); + return -1; + } + + size = iso->blocksize; + uncompress(dst + iso->blockofs, &size, Zbuf, p); + + return 0; +} + +int _isoReadBlockBZ2(isoFile *iso, u8 *dst, int lsn) { + u32 pos, p; + u32 size; + u8 Zbuf[64*1024]; + int ret; + + if ((lsn/16) == iso->buflsn) { + memset(dst, 0, iso->blockofs); + memcpy(dst + iso->blockofs, iso->buffer+(iso->blocksize*(lsn&0xf)), iso->blocksize); + return 0; + } + + iso->buflsn = lsn/16; +// printf("_isoReadBlockBZ2 %d, %d\n", lsn, iso->blocksize); + pos = *(u32*)&iso->Ztable[(lsn/16)*8]; + p = *(u32*)&iso->Ztable[(lsn/16)*8+4]; +// printf("%d, %d\n", pos, p); + _seekfile(iso->handle, pos, SEEK_SET); + ret = _readfile(iso->handle, Zbuf, p); + if (ret < p) { + printf("error reading block!!\n"); + return -1; + } + + size = iso->blocksize*64; + ret = BZ2_bzBuffToBuffDecompress((s8*)iso->buffer, &size, (s8*)Zbuf, p, 0, 0); + if (ret != BZ_OK) { + printf("_isoReadBlockBZ2 %d, %d\n", lsn, iso->blocksize); + printf("%d, %d\n", pos, p); + printf("error on BZ2: %d\n", ret); + } + + memset(dst, 0, iso->blockofs); + memcpy(dst + iso->blockofs, iso->buffer+(iso->blocksize*(lsn&0xf)), iso->blocksize); + + return 0; +} + +int _isoReadBlockD(isoFile *iso, u8 *dst, int lsn) { + int ret; + int i; + +// printf("_isoReadBlockD %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); + memset(dst, 0, iso->blockofs); + for (i=0; idtablesize;i++) { + if (iso->dtable[i] != lsn) continue; + + _seekfile(iso->handle, 16+i*(iso->blocksize+4)+4, SEEK_SET); + ret = _readfile(iso->handle, dst + iso->blockofs, iso->blocksize); + if (ret < iso->blocksize) return -1; + + return 0; + } + printf("block %d not found in dump\n", lsn); + + return -1; +} + +int _isoReadBlockM(isoFile *iso, u8 *dst, int lsn) { + u64 ofs; + int ret; + int i; + + for (i=0; i<8; i++) { + if (lsn >= iso->multih[i].slsn && + lsn <= iso->multih[i].elsn) { + break; + } + } + if (i==8) return -1; + + ofs = (u64)(lsn-iso->multih[i].slsn) * iso->blocksize + iso->offset; +// printf("_isoReadBlock %d, blocksize=%d, blockofs=%d\n", lsn, iso->blocksize, iso->blockofs); + memset(dst, 0, iso->blockofs); + _seekfile(iso->multih[i].handle, ofs, SEEK_SET); + ret = _readfile(iso->multih[i].handle, dst + iso->blockofs, iso->blocksize); + if (ret < iso->blocksize) { + printf("read error %d\n", ret); + return -1; + } + + return 0; +} + +int isoReadBlock(isoFile *iso, u8 *dst, int lsn) { + int ret; + + if (lsn > iso->blocks) { + printf("isoReadBlock: %d > %d\n", lsn, iso->blocks); + return -1; + } + if (iso->flags & ISOFLAGS_Z) { + ret = _isoReadBlockZ(iso, dst, lsn); + } else + if (iso->flags & ISOFLAGS_Z2) { + ret = _isoReadBlockZ2(iso, dst, lsn); + } else + if (iso->flags & ISOFLAGS_BLOCKDUMP) { + ret = _isoReadBlockD(iso, dst, lsn); + } else + if (iso->flags & ISOFLAGS_MULTI) { + ret = _isoReadBlockM(iso, dst, lsn); + } else + if (iso->flags & ISOFLAGS_BZ2) { + ret = _isoReadBlockBZ2(iso, dst, lsn); + } else + ret = _isoReadBlock(iso, dst, lsn); + if (ret == -1) return ret; + + if (iso->type == ISOTYPE_CD) { + LSNtoMSF(dst+12, lsn); + dst[15] = 2; + } + + return 0; +} + + +int _isoWriteBlock(isoFile *iso, u8 *src, int lsn) { + u64 ofs = (u64)lsn * iso->blocksize + iso->offset; + int ret; + +// printf("_isoWriteBlock %d (ofs=%d)\n", iso->blocksize, ofs); + _seekfile(iso->handle, ofs, SEEK_SET); + ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlock %d\n", ret); + if (ret < iso->blocksize) return -1; + + return 0; +} + +int _isoWriteBlockZ(isoFile *iso, u8 *src, int lsn) { + u32 pos; + uLongf size; + u8 Zbuf[CD_FRAMESIZE_RAW]; + int ret; + +// printf("_isoWriteBlockZ %d\n", iso->blocksize); + size = 2352; + compress(Zbuf, &size, src, 2352); +// printf("_isoWriteBlockZ %d\n", size); + + pos = (u32)_tellfile(iso->handle); + ret = _writefile(iso->htable, &pos, 4); + if (ret < 4) return -1; + ret = _writefile(iso->htable, &size, 2); + if (ret < 2) return -1; + + ret = _writefile(iso->handle, Zbuf, size); +// printf("_isoWriteBlockZ %d\n", ret); + if (ret < size) { + printf("error writing block!!\n"); + return -1; + } + + return 0; +} + +int _isoWriteBlockZ2(isoFile *iso, u8 *src, int lsn) { + uLongf size; + u8 Zbuf[1024*16]; + int ret; + +// printf("_isoWriteBlockZ %d\n", iso->blocksize); + size = 1024*16; + compress(Zbuf, &size, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlockZ %d\n", size); + + ret = _writefile(iso->htable, (u8*)&size, 4); + if (ret < 4) return -1; + ret = _writefile(iso->handle, Zbuf, size); +// printf("_isoWriteBlockZ %d\n", ret); + if (ret < size) { + printf("error writing block!!\n"); + return -1; + } + + return 0; +} + +int _isoWriteBlockD(isoFile *iso, u8 *src, int lsn) { + int ret; + +// printf("_isoWriteBlock %d (ofs=%d)\n", iso->blocksize, ofs); + ret = _writefile(iso->handle, &lsn, 4); + if (ret < 4) return -1; + ret = _writefile(iso->handle, src + iso->blockofs, iso->blocksize); +// printf("_isoWriteBlock %d\n", ret); + if (ret < iso->blocksize) return -1; + + return 0; +} + +int _isoWriteBlockBZ2(isoFile *iso, u8 *src, int lsn) { + u32 size; + u8 Zbuf[64*1024]; + int blocks; + int ret; + + memcpy(iso->buffer+(iso->blocksize*(lsn&0xf)), src + iso->blockofs, iso->blocksize); + + if (lsn == (iso->blocks-1)) { + blocks = (lsn & 0xf)+1; + } else { + blocks = 16; + if ((lsn & 0xf) != 0xf) return 0; + } + +// printf("_isoWriteBlockBZ2 %d\n", iso->blocksize); + size = 64*1024; + ret = BZ2_bzBuffToBuffCompress((s8*)Zbuf, (u32*)&size, (s8*)iso->buffer, iso->blocksize*blocks, 9, 0, 30); + if (ret != BZ_OK) { + printf("error on BZ2: %d\n", ret); + } +// printf("_isoWriteBlockBZ2 %d\n", size); + + ret = _writefile(iso->htable, (u8*)&size, 4); + if (ret < 4) return -1; + ret = _writefile(iso->handle, Zbuf, size); +// printf("_isoWriteBlockZ %d\n", ret); + if (ret < size) { + printf("error writing block!!\n"); + return -1; + } + + return 0; +} + +int isoWriteBlock(isoFile *iso, u8 *src, int lsn) { + int ret; + + if (iso->flags & ISOFLAGS_Z) { + ret = _isoWriteBlockZ(iso, src, lsn); + } else + if (iso->flags & ISOFLAGS_Z2) { + ret = _isoWriteBlockZ2(iso, src, lsn); + } else + if (iso->flags & ISOFLAGS_BLOCKDUMP) { + ret = _isoWriteBlockD(iso, src, lsn); + } else + if (iso->flags & ISOFLAGS_BZ2) { + ret = _isoWriteBlockBZ2(iso, src, lsn); + } else + ret = _isoWriteBlock(iso, src, lsn); + if (ret == -1) return ret; + + return 0; +} + +void isoClose(isoFile *iso) { + if (iso->handle) { + _closefile(iso->handle); + } + if (iso->htable) { + _closefile(iso->htable); + } + if (iso->buffer) { + free(iso->buffer); + } + free(iso); +} + diff --git a/plugins/CDVDiso/src/libiso.h b/plugins/CDVDiso/src/libiso.h new file mode 100644 index 0000000000..7cd3650738 --- /dev/null +++ b/plugins/CDVDiso/src/libiso.h @@ -0,0 +1,65 @@ +#ifndef __LIBISO_H__ +#define __LIBISO_H__ + +#ifdef _MSC_VER +#pragma warning(disable:4018) +#endif + +#define ISOTYPE_ILLEGAL 0 +#define ISOTYPE_CD 1 +#define ISOTYPE_DVD 2 +#define ISOTYPE_AUDIO 3 + +#define ISOFLAGS_Z 0x0001 +#define ISOFLAGS_Z2 0x0002 +#define ISOFLAGS_BLOCKDUMP 0x0004 +#define ISOFLAGS_MULTI 0x0008 +#define ISOFLAGS_BZ2 0x0010 + +#define CD_FRAMESIZE_RAW 2352 +#define DATA_SIZE (CD_FRAMESIZE_RAW-12) + +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ + +typedef struct { + u32 slsn; + u32 elsn; + void *handle; +} _multih; + +typedef struct { + char filename[256]; + u32 type; + u32 flags; + u32 offset; + u32 blockofs; + u32 blocksize; + u32 blocks; + void *handle; + void *htable; + char *Ztable; + u32 *dtable; + int dtablesize; + _multih multih[8]; + int buflsn; + u8 *buffer; +} isoFile; + + +isoFile *isoOpen(const char *filename); +isoFile *isoCreate(const char *filename, int mode); +int isoSetFormat(isoFile *iso, int blockofs, int blocksize, int blocks); +int isoDetect(isoFile *iso); +int isoReadBlock(isoFile *iso, u8 *dst, int lsn); +int isoWriteBlock(isoFile *iso, u8 *src, int lsn); +void isoClose(isoFile *iso); + +void *_openfile(const char *filename, int flags); +u64 _tellfile(void *handle); +int _seekfile(void *handle, u64 offset, int whence); +int _readfile(void *handle, void *dst, int size); +int _writefile(void *handle, void *src, int size); +void _closefile(void *handle); + +#endif /* __LIBISO_H__ */ diff --git a/plugins/CDVDiso/src/mkiso/Makefile b/plugins/CDVDiso/src/mkiso/Makefile new file mode 100644 index 0000000000..0954b9e918 --- /dev/null +++ b/plugins/CDVDiso/src/mkiso/Makefile @@ -0,0 +1,27 @@ + +CC = gcc + +MKISO = mkiso +CFLAGS = -fPIC -Wall -O2 -fomit-frame-pointer -I.. -I. -D__LINUX__ -I../3rdparty/zlib +OBJS = mkiso.o ../libiso.o +LIBS = +OBJS+= ../3rdparty/zlib/adler32.o ../3rdparty/zlib/compress.o ../3rdparty/zlib/crc32.o ../3rdparty/zlib/gzio.o ../3rdparty/zlib/uncompr.o \ +../3rdparty/zlib/deflate.o ../3rdparty/zlib/trees.o ../3rdparty/zlib/zutil.o ../3rdparty/zlib/inflate.o ../3rdparty/zlib/infback.o ../3rdparty/zlib/inftrees.o \ +../3rdparty/zlib/inffast.o + +DEPS:= $(OBJS:.o=.d) + +all: mkiso + +mkiso: ${OBJS} + rm -f ${MKISO} + ${CC} ${CFLAGS} ${OBJS} -o ${MKISO} ${LIBS} + strip ${MKISO} + +clean: + rm -f ${OBJS} ${DEPS} ${MKISO} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/CDVDiso/src/mkiso/Makefile.mingw b/plugins/CDVDiso/src/mkiso/Makefile.mingw new file mode 100644 index 0000000000..c85439923e --- /dev/null +++ b/plugins/CDVDiso/src/mkiso/Makefile.mingw @@ -0,0 +1,31 @@ + +CC = gcc + +MKISO = mkiso.exe +OPTIMIZE = -O2 -fomit-frame-pointer -finline-functions -ffast-math -fno-strict-aliasing +CFLAGS = -Wall ${OPTIMIZE} -I.. -I. -D__WIN32__ -I../zlib -I../bzip2 +OBJS = mkiso.o ../libiso.o +LIBS = +OBJS+= ../zlib/adler32.o ../zlib/compress.o ../zlib/crc32.o ../zlib/gzio.o ../zlib/uncompr.o ../zlib/deflate.o ../zlib/trees.o \ + ../zlib/zutil.o ../zlib/inflate.o ../zlib/infback.o ../zlib/inftrees.o ../zlib/inffast.o +OBJS+= ../bzip2/blocksort.o ../bzip2/huffman.o \ + ../bzip2/crctable.o ../bzip2/randtable.o \ + ../bzip2/compress.o ../bzip2/decompress.o \ + ../bzip2/bzlib.o + +DEPS:= $(OBJS:.o=.d) + +all: mkiso + +mkiso: ${OBJS} + rm -f ${MKISO} + ${CC} ${CFLAGS} ${OBJS} -o ${MKISO} ${LIBS} + strip ${MKISO} + +clean: + rm -f ${OBJS} ${DEPS} ${MKISO} + +%.o: %.c + ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) + +-include ${DEPS} diff --git a/plugins/CDVDiso/src/mkiso/mkiso.c b/plugins/CDVDiso/src/mkiso/mkiso.c new file mode 100644 index 0000000000..70e6da7fa7 --- /dev/null +++ b/plugins/CDVDiso/src/mkiso/mkiso.c @@ -0,0 +1,153 @@ +/* CDVDiso + * Copyright (C) 2002-2004 CDVDiso Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "CDVDiso.h" + + +void Compress(char *filename, int mode) { + struct stat buf; + u32 lsn; + u8 cdbuff[1024*16]; + char Zfile[256]; + int ret=0; + isoFile *src; + isoFile *dst; + + if (mode == 1) { + sprintf(Zfile, "%s.Z2", filename); + } else { + sprintf(Zfile, "%s.BZ2", filename); + } + + if (stat(Zfile, &buf) != -1) { + printf("'%s' already exists\n", Zfile); + return; +/* sprintf(str, "'%s' already exists, overwrite?", Zfile); + if (MessageBox(hDlg, str, "Question", MB_YESNO) != IDYES) { + return; + }*/ + } + + printf("src %s; dst %s\n", filename, Zfile); + src = isoOpen(filename); + if (src == NULL) return; + + if (mode == 1) { + dst = isoCreate(Zfile, ISOFLAGS_Z2); + } else { + dst = isoCreate(Zfile, ISOFLAGS_BZ2); + } + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + if (dst == NULL) return; + + for (lsn = 0; lsnblocks; lsn++) { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + } + isoClose(src); + isoClose(dst); + + if (ret == -1) { + printf("Error compressing iso image\n"); + } else { + printf("Iso image compressed OK\n"); + } +} + +void Decompress(char *filename) { + struct stat buf; + char file[256]; + u8 cdbuff[10*2352]; + u32 lsn; + isoFile *src; + isoFile *dst; + int ret=0; + + src = isoOpen(filename); + if (src == NULL) return; + + strcpy(file, filename); + if (src->flags & ISOFLAGS_Z) { + file[strlen(file) - 2] = 0; + } else + if (src->flags & ISOFLAGS_Z2) { + file[strlen(file) - 3] = 0; + } else + if (src->flags & ISOFLAGS_BZ2) { + file[strlen(file) - 3] = 0; + } else { + printf("%s is not a compressed image\n", filename); + return; + } + if (stat(file, &buf) != -1) { + char str[256]; + sprintf(str, "'%s' already exists", file); + isoClose(src); + return; + } + + dst = isoCreate(file, 0); + if (dst == NULL) return; + isoSetFormat(dst, src->blockofs, src->blocksize, src->blocks); + + for (lsn = 0; lsnblocks; lsn++) { + printf("block %d ", lsn); + putchar(13); + fflush(stdout); + ret = isoReadBlock(src, cdbuff, lsn); + if (ret == -1) break; + ret = isoWriteBlock(dst, cdbuff, lsn); + if (ret == -1) break; + } + + isoClose(src); + isoClose(dst); + + if (ret == -1) { + printf("Error decompressing iso image\n"); + } else { + printf("Iso image decompressed OK\n"); + } +} + + +int main(int argc, char *argv[]) { + if (argc < 3) return 0; + + if (argv[1][0] == 'c') { + Compress(argv[2], 1); + } else + if (argv[1][0] == 'C') { + Compress(argv[2], 2); + } else + if (argv[1][0] == 'd') { + Decompress(argv[2]); + } + + return 0; +} diff --git a/plugins/CDVDiso/src/mkiso/mkiso.dsp b/plugins/CDVDiso/src/mkiso/mkiso.dsp new file mode 100644 index 0000000000..85e41361e0 --- /dev/null +++ b/plugins/CDVDiso/src/mkiso/mkiso.dsp @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Project File - Name="mkiso" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=mkiso - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mkiso.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mkiso.mak" CFG="mkiso - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mkiso - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "mkiso - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mkiso - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "__WIN32__" /D "__MSCW32__" /YX /FD /c +# ADD BASE RSC /l 0x2c0a /d "NDEBUG" +# ADD RSC /l 0x2c0a /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "mkiso - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "./" /I "../" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "__WIN32__" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x2c0a /d "_DEBUG" +# ADD RSC /l 0x2c0a /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib zlib.lib libbz2.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "mkiso - Win32 Release" +# Name "mkiso - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\libiso.c +# End Source File +# Begin Source File + +SOURCE=.\mkiso.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "zlib" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\zlib\adler32.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\compress.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\crc32.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\crc32.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\deflate.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\deflate.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\gvmat32c.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\gzio.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\infback.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\inffas8664.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\inffast.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\inffast.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\inffixed.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\inflate.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\inflate.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\inftrees.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\inftrees.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\trees.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\trees.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\uncompr.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\zconf.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\zlib.h +# End Source File +# Begin Source File + +SOURCE=..\zlib\zutil.c +# End Source File +# Begin Source File + +SOURCE=..\zlib\zutil.h +# End Source File +# End Group +# End Target +# End Project diff --git a/plugins/CDVDiso/src/mkiso/mkiso.dsw b/plugins/CDVDiso/src/mkiso/mkiso.dsw new file mode 100644 index 0000000000..81430b0e7e --- /dev/null +++ b/plugins/CDVDiso/src/mkiso/mkiso.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "mkiso"=.\mkiso.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/plugins/CDVDiso_vs2008.sln b/plugins/CDVDiso_vs2008.sln new file mode 100644 index 0000000000..085eee1823 --- /dev/null +++ b/plugins/CDVDiso_vs2008.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CDVDiso_vs2008", "CDVDiso\src\Win32\CDVDiso_vs2008.vcproj", "{5F78E90B-BD22-47B1-9CA5-7A80F4DF5EF3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5F78E90B-BD22-47B1-9CA5-7A80F4DF5EF3}.Debug|Win32.ActiveCfg = Debug|Win32 + {5F78E90B-BD22-47B1-9CA5-7A80F4DF5EF3}.Debug|Win32.Build.0 = Debug|Win32 + {5F78E90B-BD22-47B1-9CA5-7A80F4DF5EF3}.Release|Win32.ActiveCfg = Release|Win32 + {5F78E90B-BD22-47B1-9CA5-7A80F4DF5EF3}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/SPU2ghz_vs2008.sln b/plugins/SPU2ghz_vs2008.sln new file mode 100644 index 0000000000..d698fe1d05 --- /dev/null +++ b/plugins/SPU2ghz_vs2008.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPU2ghz-Pg", "spu2ghz\src\Win32\SPU2ghz_vs2008.vcproj", "{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + DebugStrict|Win32 = DebugStrict|Win32 + Devel|Win32 = Devel|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|Win32.ActiveCfg = Debug|Win32 + {5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|Win32.Build.0 = Debug|Win32 + {5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.DebugStrict|Win32.ActiveCfg = DebugStrict|Win32 + {5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.DebugStrict|Win32.Build.0 = DebugStrict|Win32 + {5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Devel|Win32.ActiveCfg = Devel|Win32 + {5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Devel|Win32.Build.0 = Devel|Win32 + {5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.ActiveCfg = Release|Win32 + {5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/ZeroPAD_2008.sln b/plugins/ZeroPAD_2008.sln new file mode 100644 index 0000000000..db5d098538 --- /dev/null +++ b/plugins/ZeroPAD_2008.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroPAD", "zeropad\Windows\ZeroPAD_2008.vcproj", "{CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Debug|Win32.ActiveCfg = Debug|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Debug|Win32.Build.0 = Debug|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release|Win32.ActiveCfg = Release|Win32 + {CDD9DB83-3BD9-4ED8-BB83-399A2F65F022}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/ZeroSPU2_2008.sln b/plugins/ZeroSPU2_2008.sln new file mode 100644 index 0000000000..16a6c1c277 --- /dev/null +++ b/plugins/ZeroSPU2_2008.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroSPU2", "zerospu2\Win32\ZeroSPU2_2008.vcproj", "{7F059854-568D-4E08-9D00-1E78E203E4DC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|Win32.ActiveCfg = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Debug|Win32.Build.0 = Debug|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|Win32.ActiveCfg = Release|Win32 + {7F059854-568D-4E08-9D00-1E78E203E4DC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/build.sh b/plugins/build.sh index bb2ab17500..bf591ab847 100644 --- a/plugins/build.sh +++ b/plugins/build.sh @@ -2,58 +2,20 @@ curdir=`pwd` -cd ${curdir}/gs -sh build.sh $@ +function buildplugin { +cd ${curdir}/$1 +sh build.sh $2 if [ $? -ne 0 ] then exit 1 fi +} -cd ${curdir}/cdvd -sh build.sh $@ - -if [ $? -ne 0 ] -then -exit 1 -fi - -cd ${curdir}/dev9 -sh build.sh $@ - -if [ $? -ne 0 ] -then -exit 1 -fi - -cd ${curdir}/fw -sh build.sh $@ - -if [ $? -ne 0 ] -then -exit 1 -fi - -cd ${curdir}/pad -sh build.sh $@ - -if [ $? -ne 0 ] -then -exit 1 -fi - -cd ${curdir}/spu2 -sh build.sh $@ - -if [ $? -ne 0 ] -then -exit 1 -fi - -cd ${curdir}/usb -sh build.sh $@ - -if [ $? -ne 0 ] -then -exit 1 -fi +buildplugin gs $@ +buildplugin cdvd $@ +buildplugin dev9 $@ +buildplugin fw $@ +buildplugin pad $@ +buildplugin spu2 $@ +buildplugin usb $@ diff --git a/plugins/fetch.sh b/plugins/fetch.sh new file mode 100644 index 0000000000..28cd554add --- /dev/null +++ b/plugins/fetch.sh @@ -0,0 +1,94 @@ +#!/bin/sh +# Convenience script for obtaining plugins, +# Use at your own risk. Assumes that it is being run in the plugins directory. + +#Running this script should do the following: +#1) Check to see if the 6 needed plugin folders exist in the current directory. +#2) If they aren't. create a temp directory, download the plugins to it from +# the official pcsx2 svn, move them into the plugin directory, and then delete +# the temp directory. + +#3) Check for copies of certain plugins in the current directory, and copy them to +# the right place if they exist, assuming that they are modified copies of those plugins. + +curdir=`pwd` +PLUGINDIRS="gs cdvd dev9 fw pad spu2 usb" + +if [ -d "gs" ] & [ -d "cdvd" ] & [ -d "dev9" ] & [ -d "fw" ] & [ -d "pad" ] & [ -d "spu2" ] & [ -d "usb" ] +then +echo "Plugin directories already present." +else +echo "Checking plugins out from official Pcsx2 svn..." +mkdir "temp" + +if [ -d "temp" ] +then +cd "temp" +svn checkout http://pcsx2.googlecode.com/svn/trunk/plugins ./ -r 405 + +echo "Copying..." +for i in $PLUGINDIRS; do + mv $i ../ + done +cd .. +rm -rf ./temp/ +fi +fi + +# Copy the common directory in each individual subfolder so that +# you can compile the plugins both individually *and* from the +# normal subdirectories. +for i in $PLUGINDIRS; do + rm -rf $i/common + cp -r common/ $i/ + done + +if [ -d zerogs ] +then +echo "Importing local copy of zerogs..." +rm -rf ./gs/zerogs +cp -r zerogs ./gs/ +fi + +if [ -d zerospu2 ] +then +echo "Importing local copy of zerospu2..." +rm -rf ./spu2/zerospu2 +cp -r zerospu2 ./spu2/ +fi + +if [ -d zeropad ] +then +echo "Importing local copy of zeropad..." +rm -rf ./pad/zeropad +cp -r zeropad ./pad/ +fi + +if [ -d CDVDiso ] +then +echo "Importing local copy of CDVDiso.." +rm -rf ./cdvd/CDVDiso +cp -r CDVDiso ./cdvd/ +fi + +if [ -d CDVDlinuz ] +then +echo "Importing local copy of CDVDlinuz.." +rm -rf ./cdvd/CDVDlinuz +cp -r CDVDlinuz ./cdvd/ +fi + +if [ -d CDVDisoEFP ] +then +echo "Importing local copy of CDVDisoEFP.." +rm -rf ./cdvd/CDVDisoEFP +cp -r CDVDisoEFP ./cdvd/ +fi + +if [ -d PeopsSPU2 ] +then +echo "Importing local copy of PeopsSPU2.." +rm -rf ./spu2/PeopsSPU2 +cp -r PeopsSPU2 ./spu2/ +fi + diff --git a/plugins/spu2ghz/CHANGELOG.TXT b/plugins/spu2ghz/CHANGELOG.TXT new file mode 100644 index 0000000000..7ca8964e9e --- /dev/null +++ b/plugins/spu2ghz/CHANGELOG.TXT @@ -0,0 +1,154 @@ +# +# CHANGELOG +# +# [+] Added Feature +# [*] Modified Feature +# [-] Removed Feature +# [!] Other +# +# Dates are in D/M/Y format + +26/05/2008 - v0.1.9 + [+] Added Timestretching feature. Added part of the SoundTouch library files. + [+] Added Winamp DSP plugin support. + [+] Added Limiter toggle key (defaults to [Numpad -] + [*] Completely replaced the sound buffering system in the output modules with a centralized one. + [*] Fixed a few bugs in the savestates: Now the savestats can be used (and seem to work). + [*] Some changes to the mixer. + [-] Removed FMod output. Didn't give any improvement over DSound or XAudio2 and added lad. + [*] Updated config dialog to reflect some of the previous changes. + [!] Updated the copyright notices in each file. + +26/05/2008 - v0.1.8 + [*] Improved the mixer (gives better volumes in many games) + [*] Coded a working volume fading emulation + [*] Somewhat better AC3 code, which still doesn't work yet anyway. + [*] Improved DPL2 dematrixing. + [*] Many other changes I don't really remember. + [!] It might be a good idea to reset the settings (delete the .ini). + +09/01/2008 - v0.1.7 + [-] SPU2replay disabled until I add options for it. + [+] Improved the limiter handling to reduce lag (in dsound stereo and 5.1 only). + [+] Initial AC3 decoding - does NOT work yet! + [+] Experimental 24/32bit audio input. This allows the CDDA player in the bios to work! + [+] Added a button on the config to configure the output modules. + NOTE: None of the modules have a config dialog yet. + [*] Simplified redundant code in the mixer. + [*] New experimental register handling method. Might slightly improve the processing speed. + + +09/01/2008 - SPU2replay alpha 1 + [+] Added SPU2replay feature. + How does it work: + 1. Play a game using the plugin (it doesn't matter what output mode or audio settings you use). + The plugin will dump ALL the write events in the game, until the emulator is closed. + This is a alpha version and doesn't come with option to start or stop the dumping, it always dumps. + 2. In a cmd window, navigate to the pcsx2 folder and run: + + rundll32 plugins\spu2ghz.dll,SPU2replay replay_dump.s2r + + Alternatively, you can set .s2r files to open with "rundll32 plugins\spu2ghz.dll,SPU2replay %1" + + 3. Wait for it to finish. + This alpha version doesn't have a dialog for it yet, so there is no way to stop the replay until it finishes. + + NOTE: The replay feature saves the events as they happened in the specific session it was run, + it's recommended to avoid playing a replay file with a different version of the plugin, + in case something changed. + +02/01/2008 - v0.1.6 + [*] Converted all the output modules into C++ classes, this way it's easier to manage them. + [*] Cleaned up some parts of the code. + [*] Modified the DPLII decoding code to try to improve the quality. + [+] Added an option to change the LFE lowpass crossover frequency. + [+] Added "delayed" Irq calls so they are only called once in each T. + [*] Restored the older decoding function, and partially rewrote it. + The newer decoder function was breaking some games. + +01/01/2008 - WIP2 + [+] Updated the 5.1 module to include experimental ProLogic II decoding (it should give better surround). + [*] Changed the buffer sizing so that the configured buffer size applies to whole samples. + This means now settings 1024 as the buffer size will make it 2048 on stereo output, and 6144 on 5.1 output. + +31/12/2007 - WIP + [+] Added a highly experimental Dolby ProLogic decoding (upmixes stereo output into 5.1) output module. + +30/12/2007 - v0.1.5 + [*] Changed the way the ATTR register is handled. Should fix a lot of games, but it's experimental. + [*] Changed the thread priority of the output modules to TIME_CRITICAL, so that they have the highest possible priority. + [*] Updated to latest and final version of FMod 3. + [*] Changed some parts of register-based (PIO) memory writes to speed up audio streaming writes in RotTK games. + [+] Added DirectSound output module. It seems to work better than all the other modules so I set it as the new default. + [+] Added setting of IRQ reason flags. I didn't even know that register existed! + [+] Added a new ADPCM decoder based on the old one, but with full-block decoding to try to make it a bit faster. + [-] If running with an older emulator build, the CoreReset feature is executed immediately, without a delay. + This fixes booting problems in bios and many games that were broken since this feature was introduced. + +30/12/2007 - v0.1.4 + [-] completely removed the remains of the "async mixer" mode. It was meaningless without threading, and didn't work. + [*] Fixed the waveOut output module. + [*] Fixed a bug where the ASIO output system was using the defaulf ASIO device sample rate, + regardless of the config value. + [*] Changed the min. buffer size allowed in the config dialog to 512 isntead of 2400. + NOTE 1: Sizes too small can increase the CPU usage and might cause audio problems. + NOTE 2: FMOD and waveOut have this limit increased to 2048. + [*] Changed some code handling voice looping. I don't know if it will fix or break anything. + [+] Added partial support for log levels to the register logging system, to remove the basic + channel attributes from the log files (makes logs more readable and less bloated). + [+] Added experimental XAudio2 output module. Seems to sound well. + [+] Added a hidden option to change the AutoDMA sample rate for each core. + Useful only in some games where the FMVs hang. + [+] Added a check to the Effects processor to avoid crashes when the effects start address is + after the effects end address. + [+] Added /delayload:fmod.dll switch to the linker, so the fmod dll is only needed while + using the fmod output module. + +28/12/2007 - v0.1.3 + [*] Fixed the sync in pre-svn265 pcsx2 builds. Might help with some games. + +27/12/2007 - v0.1.2 + [*] Fixed the speed limit dialog setting (it wasn't being handled correctly). + [*] Changed the way I handle AutoDMA transfers: + For some reason the data for core 1 was being replaced with 0s, + so I added a separate temporary buffer to store the data chunks. + This fixes many FMVs with stuttering audio. + [-] Commented out some lines that were changing the ATTR register. + I don't know if this will break anything, but none of the games I tried worked worse. + [-] Removed a BAD hack that was breaking thigns instead of fixing. + +26/12/2007 - v0.1.1 + [*] Increased the volume shift for the AutoDMA'd audio by 2 (makes the FMVs louder). + [+] Experimental implementation of "core reset" handling. + [+] Added a setting to the config dialog to enable/disable the limiter. + [+] Added a setting to the config dialog to enable/disable all console prints at once. + [+] Uncommented the AutoDMA transfer message prints as they can now be toggled from the config dialog. + [+] Added "Public Release" build option that automatically creates the release package. + +25/12/2007 - v0.1.0 + [!] First Public release + [!] Too many changes to remember. + I promise to list the changes for every release from now on. + +30/04/2007 + [+] New feature: Added configuration option "Speed_Limit_Mode" to change the speed limiting algorithm. + + Values: + 0. No limiter + 1. Soft limiter -- less cpu-intensive, but can cause problems + 2. Hard limiter -- more cpu-intensive while limiting, but should give better (constant) speeds + + NOTE: Only implemented in the FMOD output module. + +29/04/2007 + [-] Hack: Removed a hack where I was ignoring any KeyOn with ADSR values set to 0. + [-] Hack: Removed a hack in the ADMA detection code. This could break some games. + [*] Bugfix: ENDX wasn't being set/cleared correctly. Thanks pSXAuthor for telling me the way it actually works. + [*] Bugfix: Fixed a bug in the adpcm streaming where I was overwriting the active (playing) block with new data. + This caused clicks in the audio, and desyncs. + [!] Any other changes I forgot. + +before 29/04/2007 + [!] I wiped the two old changes in the changelog, dated back from 2003. + I will try to update this a bit more. + There have been way too many changes in the last 4 years to remember everything. \ No newline at end of file diff --git a/plugins/spu2ghz/LGPL.txt b/plugins/spu2ghz/LGPL.txt new file mode 100644 index 0000000000..ebb7aa9340 --- /dev/null +++ b/plugins/spu2ghz/LGPL.txt @@ -0,0 +1,503 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/plugins/spu2ghz/License.txt b/plugins/spu2ghz/License.txt new file mode 100644 index 0000000000..be8e2a2099 --- /dev/null +++ b/plugins/spu2ghz/License.txt @@ -0,0 +1,17 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/3dnow_win.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/3dnow_win.cpp new file mode 100644 index 0000000000..2e369904ec --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/3dnow_win.cpp @@ -0,0 +1,350 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the AMD 3DNow! optimized routines for AMD K6-2/Athlon +/// processors. All 3DNow! optimized functions have been gathered into this +/// single source code file, regardless to their class or original source code +/// file, in order to ease porting the library to other compiler and processor +/// platforms. +/// +/// By the way; the performance gain depends heavily on the CPU generation: On +/// K6-2 these routines provided speed-up of even 2.4 times, while on Athlon the +/// difference to the original routines stayed at unremarkable 8%! Such a small +/// improvement on Athlon is due to 3DNow can perform only two operations in +/// parallel, and obviously also the Athlon FPU is doing a very good job with +/// the standard C floating point routines! Here these routines are anyway, +/// although it might not be worth the effort to convert these to GCC platform, +/// for Athlon CPU at least. The situation is different regarding the SSE +/// optimizations though, thanks to the four parallel operations of SSE that +/// already make a difference. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see '3dnow_gcc.cpp' for the gcc compiler version for all +/// GNU platforms (if file supplied). +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support 3DNow! instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: 3dnow_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +#ifndef _WIN32 +#error "wrong platform - this source code file is exclusively for Win32 platform" +#endif + +using namespace soundtouch; + +#ifdef ALLOW_3DNOW +// 3DNow! routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'TDStretch3DNow' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// these are declared in 'TDStretch.cpp' +extern int scanOffsets[4][24]; + + +// Calculates cross correlation of two buffers +double TDStretch3DNow::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint overlapLengthLocal = overlapLength; + float corr; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + /* + c-pseudocode: + + corr = 0; + for (i = 0; i < overlapLength / 4; i ++) + { + corr += pV1[0] * pV2[0]; + pV1[1] * pV2[1]; + pV1[2] * pV2[2]; + pV1[3] * pV2[3]; + pV1[4] * pV2[4]; + pV1[5] * pV2[5]; + pV1[6] * pV2[6]; + pV1[7] * pV2[7]; + + pV1 += 8; + pV2 += 8; + } + */ + + _asm + { + // give prefetch hints to CPU of what data are to be needed soonish. + // give more aggressive hints on pV1 as that changes more between different calls + // while pV2 stays the same. + prefetch [pV1] + prefetch [pV2] + prefetch [pV1 + 32] + + mov eax, dword ptr pV2 + mov ebx, dword ptr pV1 + + pxor mm0, mm0 + + mov ecx, overlapLengthLocal + shr ecx, 2 // div by four + + loop1: + movq mm1, [eax] + prefetch [eax + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm1, [ebx] + prefetch [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movq mm2, [eax + 8] + pfadd mm0, mm1 + pfmul mm2, [ebx + 8] + + movq mm3, [eax + 16] + pfadd mm0, mm2 + pfmul mm3, [ebx + 16] + + movq mm4, [eax + 24] + pfadd mm0, mm3 + pfmul mm4, [ebx + 24] + + add eax, 32 + pfadd mm0, mm4 + add ebx, 32 + + dec ecx + jnz loop1 + + // add halfs of mm0 together and return the result. + // note: mm1 is used as a dummy parameter only, we actually don't care about it's value + pfacc mm0, mm1 + movd corr, mm0 + femms + } + + return corr; +} + + + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilter3DNow::FIRFilter3DNow() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilter3DNow::~FIRFilter3DNow() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for 3DNow! routine +void FIRFilter3DNow::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + +// 3DNow!-optimized version of the filter routine for stereo sound +uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, const uint numSamples) const +{ + float *filterCoeffsLocal = filterCoeffsAlign; + uint count = (numSamples - length) & -2; + uint lengthLocal = length / 4; + + assert(length != 0); + assert(count % 2 == 0); + + /* original code: + + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + filterCoeffsLocal = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * filterCoeffsLocal[0] + + ptr[2] * filterCoeffsLocal[2] + + ptr[4] * filterCoeffsLocal[4] + + ptr[6] * filterCoeffsLocal[6]; + + sumr1 += ptr[1] * filterCoeffsLocal[1] + + ptr[3] * filterCoeffsLocal[3] + + ptr[5] * filterCoeffsLocal[5] + + ptr[7] * filterCoeffsLocal[7]; + + suml2 += ptr[8] * filterCoeffsLocal[0] + + ptr[10] * filterCoeffsLocal[2] + + ptr[12] * filterCoeffsLocal[4] + + ptr[14] * filterCoeffsLocal[6]; + + sumr2 += ptr[9] * filterCoeffsLocal[1] + + ptr[11] * filterCoeffsLocal[3] + + ptr[13] * filterCoeffsLocal[5] + + ptr[15] * filterCoeffsLocal[7]; + + ptr += 16; + filterCoeffsLocal += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + + */ + _asm + { + mov eax, dword ptr dest + mov ebx, dword ptr src + mov edx, count + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + prefetch [ebx] // give a prefetch hint to CPU what data are to be needed soonish + prefetch [filterCoeffsLocal] // give a prefetch hint to CPU what data are to be needed soonish + + mov esi, ebx + mov edi, filterCoeffsLocal + pxor mm0, mm0 + pxor mm1, mm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round four FIR filter taps are evaluated for 2*2 output samples + movq mm2, [edi] + movq mm3, mm2 + prefetch [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm2, [esi] + prefetch [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm3, [esi + 8] + + movq mm4, [edi + 8] + movq mm5, mm4 + pfadd mm0, mm2 + pfmul mm4, [esi + 8] + pfadd mm1, mm3 + pfmul mm5, [esi + 16] + + movq mm2, [edi + 16] + movq mm6, mm2 + pfadd mm0, mm4 + pfmul mm2, [esi + 16] + pfadd mm1, mm5 + pfmul mm6, [esi + 24] + + movq mm3, [edi + 24] + movq mm7, mm3 + pfadd mm0, mm2 + pfmul mm3, [esi + 24] + pfadd mm1, mm6 + pfmul mm7, [esi + 32] + add esi, 32 + pfadd mm0, mm3 + add edi, 32 + pfadd mm1, mm7 + + dec ecx + jnz loop2 + + movq [eax], mm0 + add ebx, 16 + movq [eax + 8], mm1 + add eax, 16 + + dec edx + jnz loop1 + + femms + } + + return count; +} + + +#endif // ALLOW_3DNOW diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.cpp new file mode 100644 index 0000000000..9a5cf539c0 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.cpp @@ -0,0 +1,184 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// FIR low-pass (anti-alias) filter with filter coefficient design routine and +/// MMX optimization. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "AAFilter.h" +#include "FIRFilter.h" + +using namespace soundtouch; + +#define PI 3.141592655357989 +#define TWOPI (2 * PI) + +/***************************************************************************** + * + * Implementation of the class 'AAFilter' + * + *****************************************************************************/ + +AAFilter::AAFilter(const uint length) +{ + pFIR = FIRFilter::newInstance(); + cutoffFreq = 0.5; + setLength(length); +} + + + +AAFilter::~AAFilter() +{ + delete pFIR; +} + + + +// Sets new anti-alias filter cut-off edge frequency, scaled to +// sampling frequency (nyquist frequency = 0.5). +// The filter will cut frequencies higher than the given frequency. +void AAFilter::setCutoffFreq(const double newCutoffFreq) +{ + cutoffFreq = newCutoffFreq; + calculateCoeffs(); +} + + + +// Sets number of FIR filter taps +void AAFilter::setLength(const uint newLength) +{ + length = newLength; + calculateCoeffs(); +} + + + +// Calculates coefficients for a low-pass FIR filter using Hamming window +void AAFilter::calculateCoeffs() +{ + uint i; + double cntTemp, temp, tempCoeff,h, w; + double fc2, wc; + double scaleCoeff, sum; + double *work; + SAMPLETYPE *coeffs; + + assert(length > 0); + assert(length % 4 == 0); + assert(cutoffFreq >= 0); + assert(cutoffFreq <= 0.5); + + work = new double[length]; + coeffs = new SAMPLETYPE[length]; + + fc2 = 2.0 * cutoffFreq; + wc = PI * fc2; + tempCoeff = TWOPI / (double)length; + + sum = 0; + for (i = 0; i < length; i ++) + { + cntTemp = (double)i - (double)(length / 2); + + temp = cntTemp * wc; + if (temp != 0) + { + h = fc2 * sin(temp) / temp; // sinc function + } + else + { + h = 1.0; + } + w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window + + temp = w * h; + work[i] = temp; + + // calc net sum of coefficients + sum += temp; + } + + // ensure the sum of coefficients is larger than zero + assert(sum > 0); + + // ensure we've really designed a lowpass filter... + assert(work[length/2] > 0); + assert(work[length/2 + 1] > -1e-6); + assert(work[length/2 - 1] > -1e-6); + + // Calculate a scaling coefficient in such a way that the result can be + // divided by 16384 + scaleCoeff = 16384.0f / sum; + + for (i = 0; i < length; i ++) + { + // scale & round to nearest integer + temp = work[i] * scaleCoeff; + temp += (temp >= 0) ? 0.5 : -0.5; + // ensure no overfloods + assert(temp >= -32768 && temp <= 32767); + coeffs[i] = (SAMPLETYPE)temp; + } + + // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 + pFIR->setCoefficients(coeffs, length, 14); + + delete[] work; + delete[] coeffs; +} + + +// Applies the filter to the given sequence of samples. +// Note : The amount of outputted samples is by value of 'filter length' +// smaller than the amount of input samples. +uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const +{ + return pFIR->evaluate(dest, src, numSamples, numChannels); +} + + +uint AAFilter::getLength() const +{ + return pFIR->getLength(); +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.h new file mode 100644 index 0000000000..4c85dcdbe7 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/AAFilter.h @@ -0,0 +1,91 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef AAFilter_H +#define AAFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class AAFilter +{ +protected: + class FIRFilter *pFIR; + + /// Low-pass filter cut-off frequency, negative = invalid + double cutoffFreq; + + /// num of filter taps + uint length; + + /// Calculate the FIR coefficients realizing the given cutoff-frequency + void calculateCoeffs(); +public: + AAFilter(uint length); + + ~AAFilter(); + + /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling + /// frequency (nyquist frequency = 0.5). The filter will cut off the + /// frequencies than that. + void setCutoffFreq(double newCutoffFreq); + + /// Sets number of FIR filter taps, i.e. ~filter complexity + void setLength(uint newLength); + + uint getLength() const; + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter length' + /// smaller than the amount of input samples. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; +}; + +} + +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/BPMDetect.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/BPMDetect.h new file mode 100644 index 0000000000..ac616e7e2b --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/BPMDetect.h @@ -0,0 +1,159 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Beats-per-minute (BPM) detection routine. +/// +/// The beat detection algorithm works as follows: +/// - Use function 'inputSamples' to input a chunks of samples to the class for +/// analysis. It's a good idea to enter a large sound file or stream in smallish +/// chunks of around few kilosamples in order not to extinguish too much RAM memory. +/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, +/// which is basically ok as low (bass) frequencies mostly determine the beat rate. +/// Simple averaging is used for anti-alias filtering because the resulting signal +/// quality isn't of that high importance. +/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by +/// taking absolute value that's smoothed by sliding average. Signal levels that +/// are below a couple of times the general RMS amplitude level are cut away to +/// leave only notable peaks there. +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// autocorrelation function of the enveloped signal. +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// function, calculates it's precise location and converts this reading to bpm's. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.5 $ +// +// $Id: BPMDetect.h,v 1.5 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _BPMDetect_H_ +#define _BPMDetect_H_ + +#include "STTypes.h" +#include "FIFOSampleBuffer.h" + +/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. +#define MIN_BPM 45 + +/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. +#define MAX_BPM 230 + + +/// Class for calculating BPM rate for audio data. +class BPMDetect +{ +protected: + /// Auto-correlation accumulator bins. + float *xcorr; + + /// Amplitude envelope sliding average approximation level accumulator + float envelopeAccu; + + /// RMS volume sliding average approximation level accumulator + float RMSVolumeAccu; + + /// Sample average counter. + int decimateCount; + + /// Sample average accumulator for FIFO-like decimation. + soundtouch::LONG_SAMPLETYPE decimateSum; + + /// Decimate sound by this coefficient to reach approx. 500 Hz. + int decimateBy; + + /// Auto-correlation window length + int windowLen; + + /// Number of channels (1 = mono, 2 = stereo) + int channels; + + /// sample rate + int sampleRate; + + /// Beginning of auto-correlation window: Autocorrelation isn't being updated for + /// the first these many correlation bins. + int windowStart; + + /// FIFO-buffer for decimated processing samples. + soundtouch::FIFOSampleBuffer *buffer; + + /// Initialize the class for processing. + void init(int numChannels, int sampleRate); + + /// Updates auto-correlation function for given number of decimated samples that + /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe + /// though). + void updateXCorr(int process_samples /// How many samples are processed. + ); + + /// Decimates samples to approx. 500 Hz. + /// + /// \return Number of output samples. + int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer + const soundtouch::SAMPLETYPE *src, ///< Source sample buffer + int numsamples ///< Number of source samples. + ); + + /// Calculates amplitude envelope for the buffer of samples. + /// Result is output to 'samples'. + void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer + int numsamples ///< Number of samples in buffer + ); + +public: + /// Constructor. + BPMDetect(int numChannels, ///< Number of channels in sample data. + int sampleRate ///< Sample rate in Hz. + ); + + /// Destructor. + virtual ~BPMDetect(); + + /// Inputs a block of samples for analyzing: Envelopes the samples and then + /// updates the autocorrelation estimation. When whole song data has been input + /// in smaller blocks using this function, read the resulting bpm with 'getBpm' + /// function. + /// + /// Notice that data in 'samples' array can be disrupted in processing. + void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer + int numSamples ///< Number of samples in buffer + ); + + + /// Analyzes the results and returns the BPM rate. Use this function to read result + /// after whole song data has been input to the class by consecutive calls of + /// 'inputSamples' function. + /// + /// \return Beats-per-minute rate, or zero if detection failed. + float getBpm(); +}; + +#endif // _BPMDetect_H_ diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.cpp new file mode 100644 index 0000000000..2bf965b763 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.cpp @@ -0,0 +1,252 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// outputted samples from the buffer, as well as grows the buffer size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.11 $ +// +// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include "FIFOSampleBuffer.h" + +using namespace soundtouch; + +// Constructor +FIFOSampleBuffer::FIFOSampleBuffer(uint numChannels) +{ + sizeInBytes = 0; // reasonable initial value + buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)]; + bufferUnaligned = NULL; + samplesInBuffer = 0; + bufferPos = 0; + channels = numChannels; +} + + +// destructor +FIFOSampleBuffer::~FIFOSampleBuffer() +{ + delete[] bufferUnaligned; +} + + +// Sets number of channels, 1 = mono, 2 = stereo +void FIFOSampleBuffer::setChannels(const uint numChannels) +{ + uint usedBytes; + + usedBytes = channels * samplesInBuffer; + channels = numChannels; + samplesInBuffer = usedBytes / channels; +} + + +// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and +// zeroes this pointer by copying samples from the 'bufferPos' pointer +// location on to the beginning of the buffer. +void FIFOSampleBuffer::rewind() +{ + if (bufferPos) + { + memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); + bufferPos = 0; + } +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position to +// the sample buffer. +void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + memcpy(ptrEnd(numSamples), samples, sizeof(SAMPLETYPE) * numSamples * channels); + samplesInBuffer += numSamples; +} + + +// Increases the number of samples in the buffer without copying any actual +// samples. +// +// This function is used to update the number of samples in the sample buffer +// when accessing the buffer directly with 'ptrEnd' function. Please be +// careful though! +void FIFOSampleBuffer::putSamples(uint numSamples) +{ + uint req; + + req = samplesInBuffer + numSamples; + ensureCapacity(req); + samplesInBuffer += numSamples; +} + + +// Returns a pointer to the end of the used part of the sample buffer (i.e. +// where the new samples are to be inserted). This function may be used for +// inserting new samples into the sample buffer directly. Please be careful! +// +// Parameter 'slackCapacity' tells the function how much free capacity (in +// terms of samples) there _at least_ should be, in order to the caller to +// succesfully insert all the required samples to the buffer. When necessary, +// the function grows the buffer size to comply with this requirement. +// +// When using this function as means for inserting new samples, also remember +// to increase the sample count afterwards, by calling the +// 'putSamples(numSamples)' function. +SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) +{ + ensureCapacity(samplesInBuffer + slackCapacity); + return buffer + samplesInBuffer * channels; +} + + +// Returns a pointer to the beginning of the currently non-outputted samples. +// This function is provided for accessing the output samples directly. +// Please be careful! +// +// When using this function to output samples, also remember to 'remove' the +// outputted samples from the buffer by calling the +// 'receiveSamples(numSamples)' function +SAMPLETYPE *FIFOSampleBuffer::ptrBegin() const +{ + return buffer + bufferPos * channels; +} + + +// Ensures that the buffer has enought capacity, i.e. space for _at least_ +// 'capacityRequirement' number of samples. The buffer is grown in steps of +// 4 kilobytes to eliminate the need for frequently growing up the buffer, +// as well as to round the buffer size up to the virtual memory page size. +void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) +{ + SAMPLETYPE *tempUnaligned, *temp; + + if (capacityRequirement > getCapacity()) + { + // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) + sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096; + assert(sizeInBytes % 2 == 0); + tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; + if (tempUnaligned == NULL) + { + throw std::runtime_error("Couldn't allocate memory!\n"); + } + temp = (SAMPLETYPE *)(((ulongptr)tempUnaligned + 15) & -16); + memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); + delete[] bufferUnaligned; + buffer = temp; + bufferUnaligned = tempUnaligned; + bufferPos = 0; + } + else + { + // simply rewind the buffer (if necessary) + rewind(); + } +} + + +// Returns the current buffer capacity in terms of samples +uint FIFOSampleBuffer::getCapacity() const +{ + return sizeInBytes / (channels * sizeof(SAMPLETYPE)); +} + + +// Returns the number of samples currently in the buffer +uint FIFOSampleBuffer::numSamples() const +{ + return samplesInBuffer; +} + + +// Output samples from beginning of the sample buffer. Copies demanded number +// of samples to output and removes them from the sample buffer. If there +// are less than 'numsample' samples in the buffer, returns all available. +// +// Returns number of samples copied. +uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) +{ + uint num; + + num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; + + memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); + return receiveSamples(num); +} + + +// Removes samples from the beginning of the sample buffer without copying them +// anywhere. Used to reduce the number of samples in the buffer, when accessing +// the sample buffer with the 'ptrBegin' function. +uint FIFOSampleBuffer::receiveSamples(uint maxSamples) +{ + if (maxSamples >= samplesInBuffer) + { + uint temp; + + temp = samplesInBuffer; + samplesInBuffer = 0; + return temp; + } + + samplesInBuffer -= maxSamples; + bufferPos += maxSamples; + + return maxSamples; +} + + +// Returns nonzero if the sample buffer is empty +int FIFOSampleBuffer::isEmpty() const +{ + return (samplesInBuffer == 0) ? 1 : 0; +} + + +// Clears the sample buffer +void FIFOSampleBuffer::clear() +{ + samplesInBuffer = 0; + bufferPos = 0; +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.h new file mode 100644 index 0000000000..09f74c9a65 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSampleBuffer.h @@ -0,0 +1,174 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// output samples from the buffer as well as grows the storage size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSampleBuffer_H +#define FIFOSampleBuffer_H + +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes +/// care of storage size adjustment and data moving during input/output operations. +/// +/// Notice that in case of stereo audio, one sample is considered to consist of +/// both channel data. +class FIFOSampleBuffer : public FIFOSamplePipe +{ +private: + /// Sample buffer. + SAMPLETYPE *buffer; + + // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first + // 16-byte aligned location of this buffer + SAMPLETYPE *bufferUnaligned; + + /// Sample buffer size in bytes + uint sizeInBytes; + + /// How many samples are currently in buffer. + uint samplesInBuffer; + + /// Channels, 1=mono, 2=stereo. + uint channels; + + /// Current position pointer to the buffer. This pointer is increased when samples are + /// removed from the pipe so that it's necessary to actually rewind buffer (move data) + /// only new data when is put to the pipe. + uint bufferPos; + + /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real + /// beginning of the buffer. + void rewind(); + + /// Ensures that the buffer has capacity for at least this many samples. + void ensureCapacity(const uint capacityRequirement); + + /// Returns current capacity. + uint getCapacity() const; + +public: + + /// Constructor + FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. + ///< Default is stereo. + ); + + /// destructor + ~FIFOSampleBuffer(); + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const; + + /// Returns a pointer to the end of the used part of the sample buffer (i.e. + /// where the new samples are to be inserted). This function may be used for + /// inserting new samples into the sample buffer directly. Please be careful + /// not corrupt the book-keeping! + /// + /// When using this function as means for inserting new samples, also remember + /// to increase the sample count afterwards, by calling the + /// 'putSamples(numSamples)' function. + SAMPLETYPE *ptrEnd( + uint slackCapacity ///< How much free capacity (in samples) there _at least_ + ///< should be so that the caller can succesfully insert the + ///< desired samples to the buffer. If necessary, the function + ///< grows the buffer size to comply with this requirement. + ); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ); + + /// Adjusts the book-keeping to increase number of samples in the buffer without + /// copying any actual samples. + /// + /// This function is used to update the number of samples in the sample buffer + /// when accessing the buffer directly with 'ptrEnd' function. Please be + /// careful though! + virtual void putSamples(uint numSamples ///< Number of samples been inserted. + ); + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ); + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ); + + /// Returns number of samples currently available. + virtual uint numSamples() const; + + /// Sets number of channels, 1 = mono, 2 = stereo. + void setChannels(uint numChannels); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const; + + /// Clears all the samples. + virtual void clear(); +}; + +} + +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSamplePipe.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSamplePipe.h new file mode 100644 index 0000000000..33e33c7e36 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIFOSamplePipe.h @@ -0,0 +1,217 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound +/// samples by operating like a first-in-first-out pipe: New samples are fed +/// into one end of the pipe with the 'putSamples' function, and the processed +/// samples are received from the other end with the 'receiveSamples' function. +/// +/// 'FIFOProcessor' : A base class for classes the do signal processing with +/// the samples while operating like a first-in-first-out pipe. When samples +/// are input with the 'putSamples' function, the class processes them +/// and moves the processed samples to the given 'output' pipe object, which +/// may be either another processing stage, or a fifo sample buffer object. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.8 $ +// +// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSamplePipe_H +#define FIFOSamplePipe_H + +#include +#include +#include "STTypes.h" + +namespace soundtouch +{ + +/// Abstract base class for FIFO (first-in-first-out) sample processing classes. +class FIFOSamplePipe +{ +public: + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const = 0; + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ) = 0; + + + // Moves samples from the 'other' pipe instance to this instance. + void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. + ) + { + int oNumSamples = other.numSamples(); + + putSamples(other.ptrBegin(), oNumSamples); + other.receiveSamples(oNumSamples); + }; + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) = 0; + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) = 0; + + /// Returns number of samples currently available. + virtual uint numSamples() const = 0; + + // Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const = 0; + + /// Clears all the samples. + virtual void clear() = 0; +}; + + + +/// Base-class for sound processing routines working in FIFO principle. With this base +/// class it's easy to implement sound processing stages that can be chained together, +/// so that samples that are fed into beginning of the pipe automatically go through +/// all the processing stages. +/// +/// When samples are input to this class, they're first processed and then put to +/// the FIFO pipe that's defined as output of this class. This output pipe can be +/// either other processing stage or a FIFO sample buffer. +class FIFOProcessor :public FIFOSamplePipe +{ +protected: + /// Internal pipe where processed samples are put. + FIFOSamplePipe *output; + + /// Sets output pipe. + void setOutPipe(FIFOSamplePipe *pOutput) + { + assert(output == NULL); + assert(pOutput != NULL); + output = pOutput; + } + + + /// Constructor. Doesn't define output pipe; it has to be set be + /// 'setOutPipe' function. + FIFOProcessor() + { + output = NULL; + } + + + /// Constructor. Configures output pipe. + FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. + ) + { + output = pOutput; + } + + + /// Destructor. + virtual ~FIFOProcessor() + { + } + + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const + { + return output->ptrBegin(); + } + +public: + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) + { + return output->receiveSamples(outBuffer, maxSamples); + } + + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) + { + return output->receiveSamples(maxSamples); + } + + + /// Returns number of samples currently available. + virtual uint numSamples() const + { + return output->numSamples(); + } + + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const + { + return output->isEmpty(); + } +}; + +} + +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.cpp new file mode 100644 index 0000000000..ac57335a18 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.cpp @@ -0,0 +1,272 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "FIRFilter.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/***************************************************************************** + * + * Implementation of the class 'FIRFilter' + * + *****************************************************************************/ + +FIRFilter::FIRFilter() +{ + resultDivFactor = 0; + length = 0; + lengthDiv8 = 0; + filterCoeffs = NULL; +} + + +FIRFilter::~FIRFilter() +{ + delete[] filterCoeffs; +} + +// Usual C-version of the filter routine for stereo sound +uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE suml, sumr; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + assert(length != 0); + + end = 2 * (numSamples - length); + + for (j = 0; j < end; j += 2) + { + const SAMPLETYPE *ptr; + + suml = sumr = 0; + ptr = src + j; + + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + + ptr[2 * i + 2] * filterCoeffs[i + 1] + + ptr[2 * i + 4] * filterCoeffs[i + 2] + + ptr[2 * i + 6] * filterCoeffs[i + 3]; + sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + + ptr[2 * i + 3] * filterCoeffs[i + 1] + + ptr[2 * i + 5] * filterCoeffs[i + 2] + + ptr[2 * i + 7] * filterCoeffs[i + 3]; + } + +#ifdef INTEGER_SAMPLES + suml >>= resultDivFactor; + sumr >>= resultDivFactor; + // saturate to 16 bit integer limits + suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; + // saturate to 16 bit integer limits + sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; +#else + suml *= dScaler; + sumr *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)suml; + dest[j + 1] = (SAMPLETYPE)sumr; + } + return numSamples - length; +} + + + + +// Usual C-version of the filter routine for mono sound +uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE sum; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + + assert(length != 0); + + end = numSamples - length; + for (j = 0; j < end; j ++) + { + sum = 0; + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + sum += src[i + 0] * filterCoeffs[i + 0] + + src[i + 1] * filterCoeffs[i + 1] + + src[i + 2] * filterCoeffs[i + 2] + + src[i + 3] * filterCoeffs[i + 3]; + } +#ifdef INTEGER_SAMPLES + sum >>= resultDivFactor; + // saturate to 16 bit integer limits + sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; +#else + sum *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)sum; + src ++; + } + return end; +} + + +// Set filter coeffiecients and length. +// +// Throws an exception if filter length isn't divisible by 8 +void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) +{ + assert(newLength > 0); + if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8"); + + lengthDiv8 = newLength / 8; + length = lengthDiv8 * 8; + assert(length == newLength); + + resultDivFactor = uResultDivFactor; +#ifdef INTEGER_SAMPLES + resultDivider = (SAMPLETYPE)(1< 0); + assert(lengthDiv8 * 8 == length); + if (numSamples < length) return 0; + assert(resultDivFactor >= 0); + if (numChannels == 2) + { + return evaluateFilterStereo(dest, src, numSamples); + } else { + return evaluateFilterMono(dest, src, numSamples); + } +} + + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX-capable CPU available or not. +void * FIRFilter::operator new(size_t s) +{ + // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! + throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!"); + return NULL; +} + + +FIRFilter * FIRFilter::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new FIRFilterMMX; + } + else +#endif // ALLOW_MMX + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new FIRFilterSSE; + } + else +#endif // ALLOW_SSE + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new FIRFilter3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new FIRFilter; + } +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.h new file mode 100644 index 0000000000..be5cdd2943 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/FIRFilter.h @@ -0,0 +1,163 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.17 $ +// +// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIRFilter_H +#define FIRFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class FIRFilter +{ +protected: + // Number of FIR filter taps + uint length; + // Number of FIR filter taps divided by 8 + uint lengthDiv8; + + // Result divider factor in 2^k format + uint resultDivFactor; + + // Result divider value. + SAMPLETYPE resultDivider; + + // Memory for filter coefficients + SAMPLETYPE *filterCoeffs; + + virtual uint evaluateFilterStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + virtual uint evaluateFilterMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + +public: + FIRFilter(); + virtual ~FIRFilter(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX-capable CPU available or not. + void * operator new(size_t s); + + static FIRFilter *newInstance(); + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter_length' + /// smaller than the amount of input samples. + /// + /// \return Number of samples copied to 'dest'. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; + + uint getLength() const; + + virtual void setCoefficients(const SAMPLETYPE *coeffs, + uint newLength, + uint uResultDivFactor); +}; + + +// Optional subclasses that implement CPU-specific optimizations: + +#ifdef ALLOW_MMX + + /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. + class FIRFilterMMX : public FIRFilter + { + protected: + short *filterCoeffsUnalign; + short *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; + public: + FIRFilterMMX(); + ~FIRFilterMMX(); + + virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_MMX + + +#ifdef ALLOW_3DNOW + + /// Class that implements 3DNow! optimized functions exclusive for floating point samples type. + class FIRFilter3DNow : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilter3DNow(); + ~FIRFilter3DNow(); + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized functions exclusive for floating point samples type. + class FIRFilterSSE : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilterSSE(); + ~FIRFilterSSE(); + + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_SSE + +} + +#endif // FIRFilter_H diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/Makefile.am b/plugins/spu2ghz/src/3rdparty/SoundTouch/Makefile.am new file mode 100644 index 0000000000..a09ae5f081 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/Makefile.am @@ -0,0 +1,46 @@ +## Process this file with automake to create Makefile.in +## +## $Id: Makefile.am,v 1.3 2006/02/05 18:33:34 Olli Exp $ +## +## Copyright (C) 2003 - David W. Durham +## +## This file is part of SoundTouch, an audio processing library for pitch/time adjustments +## +## SoundTouch 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. +## +## SoundTouch 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 + +AUTOMAKE_OPTIONS = foreign + +noinst_HEADERS=AAFilter.h cpu_detect.h FIRFilter.h RateTransposer.h TDStretch.h cpu_detect_x86_gcc.cpp +noinst_LIBRARIES = libSoundTouch.a + +if X86_64 +libSoundTouch_a_CXXFLAGS = -fPIC +libSoundTouch_a_CFLAGS = -fPIC +else +libSoundTouch_a_CXXFLAGS = -msse -mmmx +libSoundTouch_a_CFLAGS = -msse -mmmx +endif + +#lib_LTLIBRARIES=libSoundTouch.la +# the mmx_gcc.cpp and cpu_detect_x86_gcc.cpp may need to be conditionally included here from things discovered in configure.ac +libSoundTouch_a_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp mmx_optimized.cpp sse_optimized.cpp \ +RateTransposer.cpp SoundTouch.cpp TDStretch.cpp WavFile.cpp cpu_detect_x86_gcc.cpp + +# ??? test for -fcheck-new in configure.ac +# other compiler flags to add +AM_CXXFLAGS=-O3 -msse -fcheck-new -I../../include + +# other linking flags to add +#libSoundTouch_la_LIBADD= + diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.cpp new file mode 100644 index 0000000000..b7414b90a6 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.cpp @@ -0,0 +1,626 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application) +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/03/19 10:05:49 $ +// File revision : $Revision: 1.13 $ +// +// $Id: RateTransposer.cpp,v 1.13 2006/03/19 10:05:49 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "RateTransposer.h" +#include "AAFilter.h" + +using namespace soundtouch; + + +/// A linear samplerate transposer class that uses integer arithmetics. +/// for the transposing. +class RateTransposerInteger : public RateTransposer +{ +protected: + int iSlopeCount; + uint uRate; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerInteger(); + virtual ~RateTransposerInteger(); + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + +}; + + +/// A linear samplerate transposer class that uses floating point arithmetics +/// for the transposing. +class RateTransposerFloat : public RateTransposer +{ +protected: + float fSlopeCount; + float fRateStep; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerFloat(); + virtual ~RateTransposerFloat(); +}; + + + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * RateTransposer::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +RateTransposer *RateTransposer::newInstance() +{ +#ifdef INTEGER_SAMPLES + return ::new RateTransposerInteger; +#else + return ::new RateTransposerFloat; +#endif +} + + +// Constructor +RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) +{ + uChannels = 2; + bUseAAFilter = TRUE; + + // Instantiates the anti-alias filter with default tap length + // of 32 + pAAFilter = new AAFilter(32); +} + + + +RateTransposer::~RateTransposer() +{ + delete pAAFilter; +} + + + +/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable +void RateTransposer::enableAAFilter(const BOOL newMode) +{ + bUseAAFilter = newMode; +} + + +/// Returns nonzero if anti-alias filter is enabled. +BOOL RateTransposer::isAAFilterEnabled() const +{ + return bUseAAFilter; +} + + +AAFilter *RateTransposer::getAAFilter() const +{ + return pAAFilter; +} + + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposer::setRate(float newRate) +{ + float fCutoff; + + fRate = newRate; + + // design a new anti-alias filter + if (newRate > 1.0f) + { + fCutoff = 0.5f / newRate; + } + else + { + fCutoff = 0.5f * newRate; + } + pAAFilter->setCutoffFreq(fCutoff); +} + + +// Outputs as many samples of the 'outputBuffer' as possible, and if there's +// any room left, outputs also as many of the incoming samples as possible. +// The goal is to drive the outputBuffer empty. +// +// It's allowed for 'output' and 'input' parameters to point to the same +// memory position. +void RateTransposer::flushStoreBuffer() +{ + if (storeBuffer.isEmpty()) return; + + outputBuffer.moveSamples(storeBuffer); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void RateTransposer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + processSamples(samples, numSamples); +} + + + +// Transposes up the sample rate, causing the observed playback 'rate' of the +// sound to decrease +void RateTransposer::upsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp, num; + + // If the parameter 'uRate' value is smaller than 'SCALE', first transpose + // the samples and then apply the anti-alias filter to remove aliasing. + + // First check that there's enough room in 'storeBuffer' + // (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + + // Transpose the samples, store the result into the end of "storeBuffer" + count = transpose(storeBuffer.ptrEnd(sizeTemp), src, numSamples); + storeBuffer.putSamples(count); + + // Apply the anti-alias filter to samples in "store output", output the + // result to "dest" + num = storeBuffer.numSamples(); + count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), + storeBuffer.ptrBegin(), num, uChannels); + outputBuffer.putSamples(count); + + // Remove the processed samples from "storeBuffer" + storeBuffer.receiveSamples(count); +} + + +// Transposes down the sample rate, causing the observed playback 'rate' of the +// sound to increase +void RateTransposer::downsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp; + + // If the parameter 'uRate' value is larger than 'SCALE', first apply the + // anti-alias filter to remove high frequencies (prevent them from folding + // over the lover frequencies), then transpose. */ + + // Add the new samples to the end of the storeBuffer */ + storeBuffer.putSamples(src, numSamples); + + // Anti-alias filter the samples to prevent folding and output the filtered + // data to tempBuffer. Note : because of the FIR filter length, the + // filtering routine takes in 'filter_length' more samples than it outputs. + assert(tempBuffer.isEmpty()); + sizeTemp = storeBuffer.numSamples(); + + count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp), + storeBuffer.ptrBegin(), sizeTemp, uChannels); + + // Remove the filtered samples from 'storeBuffer' + storeBuffer.receiveSamples(count); + + // Transpose the samples (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count); + outputBuffer.putSamples(count); +} + + +// Transposes sample rate by applying anti-alias filter to prevent folding. +// Returns amount of samples returned in the "dest" buffer. +// The maximum amount of samples that can be returned at a time is set by +// the 'set_returnBuffer_size' function. +void RateTransposer::processSamples(const SAMPLETYPE *src, uint numSamples) +{ + uint count; + uint sizeReq; + + if (numSamples == 0) return; + assert(pAAFilter); + + // If anti-alias filter is turned off, simply transpose without applying + // the filter + if (bUseAAFilter == FALSE) + { + sizeReq = (int)((float)numSamples / fRate + 1.0f); + count = transpose(outputBuffer.ptrEnd(sizeReq), src, numSamples); + outputBuffer.putSamples(count); + return; + } + + // Transpose with anti-alias filter + if (fRate < 1.0f) + { + upsample(src, numSamples); + } + else + { + downsample(src, numSamples); + } +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// Returns the number of samples returned in the "dest" buffer +inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + if (uChannels == 2) + { + return transposeStereo(dest, src, numSamples); + } + else + { + return transposeMono(dest, src, numSamples); + } +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void RateTransposer::setChannels(const uint numchannels) +{ + if (uChannels == numchannels) return; + + assert(numchannels == 1 || numchannels == 2); + uChannels = numchannels; + + storeBuffer.setChannels(uChannels); + tempBuffer.setChannels(uChannels); + outputBuffer.setChannels(uChannels); + + // Inits the linear interpolation registers + resetRegisters(); +} + + +// Clears all the samples in the object +void RateTransposer::clear() +{ + outputBuffer.clear(); + storeBuffer.clear(); +} + + +// Returns nonzero if there aren't any samples available for outputting. +uint RateTransposer::isEmpty() +{ + int res; + + res = FIFOProcessor::isEmpty(); + if (res == 0) return 0; + return storeBuffer.isEmpty(); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerInteger - integer arithmetic implementation +// + +/// fixed-point interpolation routine precision +#define SCALE 65536 + +// Constructor +RateTransposerInteger::RateTransposerInteger() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerInteger::~RateTransposerInteger() +{ +} + + +void RateTransposerInteger::resetRegisters() +{ + iSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + LONG_SAMPLETYPE temp, vol1; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[used] * vol1 + iSlopeCount * src[used + 1]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Stereo' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + LONG_SAMPLETYPE temp, vol1; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = vol1 * sPrevSampleR + iSlopeCount * src[1]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposerInteger::setRate(float newRate) +{ + uRate = (int)(newRate * SCALE + 0.5f); + RateTransposer::setRate(newRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerFloat - floating point arithmetic implementation +// +////////////////////////////////////////////////////////////////////////////// + +// Constructor +RateTransposerFloat::RateTransposerFloat() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerFloat::~RateTransposerFloat() +{ +} + + +void RateTransposerFloat::resetRegisters() +{ + fSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (fSlopeCount <= 1.0f) + { + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + i++; + fSlopeCount += fRate; + } + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]); + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (fSlopeCount <= 1.0f) + { + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]); + i++; + fSlopeCount += fRate; + } + // now always (iSlopeCount > 1.0f) + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos] + + fSlopeCount * src[srcPos + 2]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1] + + fSlopeCount * src[srcPos + 3]); + + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.h new file mode 100644 index 0000000000..f73978e639 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/RateTransposer.h @@ -0,0 +1,162 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application). +/// +/// Use either of the derived classes of 'RateTransposerInteger' or +/// 'RateTransposerFloat' for corresponding integer/floating point tranposing +/// algorithm implementation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: RateTransposer.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef RateTransposer_H +#define RateTransposer_H + +#include "AAFilter.h" +#include "FIFOSamplePipe.h" +#include "FIFOSampleBuffer.h" + +#include "STTypes.h" + +namespace soundtouch +{ + +/// A common linear samplerate transposer class. +/// +/// Note: Use function "RateTransposer::newInstance()" to create a new class +/// instance instead of the "new" operator; that function automatically +/// chooses a correct implementation depending on if integer or floating +/// arithmetics are to be used. +class RateTransposer : public FIFOProcessor +{ +protected: + /// Anti-alias filter object + AAFilter *pAAFilter; + + float fRate; + + uint uChannels; + + /// Buffer for collecting samples to feed the anti-alias filter between + /// two batches + FIFOSampleBuffer storeBuffer; + + /// Buffer for keeping samples between transposing & anti-alias filter + FIFOSampleBuffer tempBuffer; + + /// Output sample buffer + FIFOSampleBuffer outputBuffer; + + BOOL bUseAAFilter; + + void init(); + + virtual void resetRegisters() = 0; + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + uint transpose(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + + void flushStoreBuffer(); + + void downsample(const SAMPLETYPE *src, + uint numSamples); + void upsample(const SAMPLETYPE *src, + uint numSamples); + + /// Transposes sample rate by applying anti-alias filter to prevent folding. + /// Returns amount of samples returned in the "dest" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(const SAMPLETYPE *src, + uint numSamples); + + +public: + RateTransposer(); + virtual ~RateTransposer(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we're to use integer or floating point arithmetics. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct implementation, depending on if + /// integer ot floating point arithmetics are to be used. + static RateTransposer *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the store buffer object + FIFOSamplePipe *getStore() { return &storeBuffer; }; + + /// Return anti-alias filter object + AAFilter *getAAFilter() const; + + /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable + void enableAAFilter(BOOL newMode); + + /// Returns nonzero if anti-alias filter is enabled. + BOOL isAAFilterEnabled() const; + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint channels); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + void putSamples(const SAMPLETYPE *samples, uint numSamples); + + /// Clears all the samples in the object + void clear(); + + /// Returns nonzero if there aren't any samples available for outputting. + uint isEmpty(); +}; + +} + +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/STTypes.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/STTypes.h new file mode 100644 index 0000000000..f3a6a5d5c0 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/STTypes.h @@ -0,0 +1,202 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Common type definitions for SoundTouch audio processing library. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: STTypes.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef STTypes_H +#define STTypes_H + +//#define INTEGER_SAMPLES 1 + +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifdef __x86_64__ +typedef unsigned long long ulongptr; +#else +typedef unsigned long ulongptr; +#endif + + +#ifdef __GNUC__ + // In GCC, include soundtouch_config.h made by config scritps +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Use Integer as Sample type */ +//#define INTEGER_SAMPLES 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +#endif + +#ifndef _WINDEF_ + // if these aren't defined already by Windows headers, define now + + typedef int BOOL; + +#ifndef FALSE + #define FALSE 0 +#endif + +#ifndef TRUE + #define TRUE 1 +#endif + +#endif // _WINDEF_ + + +namespace soundtouch +{ +/// Activate these undef's to overrule the possible sampletype +/// setting inherited from some other header file: +//#undef INTEGER_SAMPLES +//#undef FLOAT_SAMPLES + +#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) + + /// Choose either 32bit floating point or 16bit integer sampletype + /// by choosing one of the following defines, unless this selection + /// has already been done in some other file. + //// + /// Notes: + /// - In Windows environment, choose the sample format with the + /// following defines. + /// - In GNU environment, the floating point samples are used by + /// default, but integer samples can be chosen by giving the + /// following switch to the configure script: + /// ./configure --enable-integer-samples + /// However, if you still prefer to select the sample format here + /// also in GNU environment, then please #undef the INTEGER_SAMPLE + /// and FLOAT_SAMPLE defines first as in comments above. + //#define INTEGER_SAMPLES 1 //< 16bit integer samples + #define FLOAT_SAMPLES 1 //< 32bit float samples + + #endif + + /// Define this to allow CPU-specific assembler optimizations. Notice that + /// having this enabled on non-x86 platforms doesn't matter; the compiler can + /// drop unsupported extensions on different platforms automatically. + /// However, if you're having difficulties getting the optimized routines + /// compiled with your compler (e.g. some gcc compiler versions may be picky), + /// you may wish to disable the optimizations to make the library compile. + #if !defined(_MSC_VER) || !defined(__x86_64__) + #define ALLOW_OPTIMIZATIONS 1 + #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 + #endif + + + // If defined, allows the SIMD-optimized routines to take minor shortcuts + // for improved performance. Undefine to require faithfully similar SIMD + // calculations as in normal C implementation. + + + + #ifdef INTEGER_SAMPLES + // 16bit integer sample type + typedef short SAMPLETYPE; + // data type for sample accumulation: Use 32bit integer to prevent overflows + typedef long LONG_SAMPLETYPE; + + #ifdef FLOAT_SAMPLES + // check that only one sample type is defined + #error "conflicting sample types defined" + #endif // FLOAT_SAMPLES + + #ifdef ALLOW_OPTIMIZATIONS + #if (_WIN32 || __i386__ || __x86_64__) + // Allow MMX optimizations + #define ALLOW_MMX 1 + #endif + #endif + + #else + + // floating point samples + typedef float SAMPLETYPE; + // data type for sample accumulation: Use double to utilize full precision. + typedef double LONG_SAMPLETYPE; + + #ifdef ALLOW_OPTIMIZATIONS + // Allow 3DNow! and SSE optimizations + #if _WIN32 + // #define ALLOW_3DNOW 1 + #endif + + #if (_WIN32 || __i386__ || __x86_64__) + #define ALLOW_SSE 1 + #endif + #endif + + #endif // INTEGER_SAMPLES +}; + +#endif \ No newline at end of file diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.cpp new file mode 100644 index 0000000000..d20fd326ba --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.cpp @@ -0,0 +1,474 @@ +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.13 $ +// +// $Id: SoundTouch.cpp,v 1.13 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "SoundTouch.h" +#include "TDStretch.h" +#include "RateTransposer.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/// Print library version string +extern "C" void soundtouch_ac_test() +{ + printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); +} + + +SoundTouch::SoundTouch() +{ + // Initialize rate transposer and tempo changer instances + + pRateTransposer = RateTransposer::newInstance(); + pTDStretch = TDStretch::newInstance(); + + setOutPipe(pTDStretch); + + rate = tempo = 0; + + virtualPitch = + virtualRate = + virtualTempo = 1.0; + + calcEffectiveRateAndTempo(); + + channels = 0; + bSrateSet = FALSE; +} + + + +SoundTouch::~SoundTouch() +{ + delete pRateTransposer; + delete pTDStretch; +} + + + +/// Get SoundTouch library version string +const char *SoundTouch::getVersionString() +{ + static const char *_version = SOUNDTOUCH_VERSION; + + return _version; +} + + +/// Get SoundTouch library version Id +uint SoundTouch::getVersionId() +{ + return SOUNDTOUCH_VERSION_ID; +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void SoundTouch::setChannels(uint numChannels) +{ + if (numChannels != 1 && numChannels != 2) + { + throw std::runtime_error("Illegal number of channels"); + } + channels = numChannels; + pRateTransposer->setChannels(numChannels); + pTDStretch->setChannels(numChannels); +} + + + +// Sets new rate control value. Normal rate = 1.0, smaller values +// represent slower rate, larger faster rates. +void SoundTouch::setRate(float newRate) +{ + virtualRate = newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new rate control value as a difference in percents compared +// to the original rate (-50 .. +100 %) +void SoundTouch::setRateChange(float newRate) +{ + virtualRate = 1.0f + 0.01f * newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value. Normal tempo = 1.0, smaller values +// represent slower tempo, larger faster tempo. +void SoundTouch::setTempo(float newTempo) +{ + virtualTempo = newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value as a difference in percents compared +// to the original tempo (-50 .. +100 %) +void SoundTouch::setTempoChange(float newTempo) +{ + virtualTempo = 1.0f + 0.01f * newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new pitch control value. Original pitch = 1.0, smaller values +// represent lower pitches, larger values higher pitch. +void SoundTouch::setPitch(float newPitch) +{ + virtualPitch = newPitch; + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in octaves compared to the original pitch +// (-1.00 .. +1.00) +void SoundTouch::setPitchOctaves(float newPitch) +{ + virtualPitch = (float)exp(0.69314718056f * newPitch); + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in semi-tones compared to the original pitch +// (-12 .. +12) +void SoundTouch::setPitchSemiTones(int newPitch) +{ + setPitchOctaves((float)newPitch / 12.0f); +} + + + +void SoundTouch::setPitchSemiTones(float newPitch) +{ + setPitchOctaves(newPitch / 12.0f); +} + + +// Calculates 'effective' rate and tempo values from the +// nominal control values. +void SoundTouch::calcEffectiveRateAndTempo() +{ + float oldTempo = tempo; + float oldRate = rate; + + tempo = virtualTempo / virtualPitch; + rate = virtualPitch * virtualRate; + + if (rate != oldRate) pRateTransposer->setRate(rate); + if (tempo != oldTempo) pTDStretch->setTempo(tempo); + + if (rate > 1.0f) + { + if (output != pRateTransposer) + { + FIFOSamplePipe *transOut; + + assert(output == pTDStretch); + // move samples in the current output buffer to the output of pRateTransposer + transOut = pRateTransposer->getOutput(); + transOut->moveSamples(*output); + // move samples in tempo changer's input to pitch transposer's input + pRateTransposer->moveSamples(*pTDStretch->getInput()); + + output = pRateTransposer; + } + } + else + { + if (output != pTDStretch) + { + FIFOSamplePipe *tempoOut; + + assert(output == pRateTransposer); + // move samples in the current output buffer to the output of pTDStretch + tempoOut = pTDStretch->getOutput(); + tempoOut->moveSamples(*output); + // move samples in pitch transposer's store buffer to tempo changer's input + pTDStretch->moveSamples(*pRateTransposer->getStore()); + + output = pTDStretch; + + } + } +} + + +// Sets sample rate. +void SoundTouch::setSampleRate(uint srate) +{ + bSrateSet = TRUE; + // set sample rate, leave other tempo changer parameters as they are. + pTDStretch->setParameters(srate); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + if (bSrateSet == FALSE) + { + throw std::runtime_error("SoundTouch : Sample rate not defined"); + } + else if (channels == 0) + { + throw std::runtime_error("SoundTouch : Number of channels not defined"); + } + + // Transpose the rate of the new samples if necessary + /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... + if (rate == 1.0f) + { + // The rate value is same as the original, simply evaluate the tempo changer. + assert(output == pTDStretch); + if (pRateTransposer->isEmpty() == 0) + { + // yet flush the last samples in the pitch transposer buffer + // (may happen if 'rate' changes from a non-zero value to zero) + pTDStretch->moveSamples(*pRateTransposer); + } + pTDStretch->putSamples(samples, numSamples); + } + */ + else if (rate <= 1.0f) + { + // transpose the rate down, output the transposed sound to tempo changer buffer + assert(output == pTDStretch); + pRateTransposer->putSamples(samples, numSamples); + pTDStretch->moveSamples(*pRateTransposer); + } + else + { + assert(rate > 1.0f); + // evaluate the tempo changer, then transpose the rate up, + assert(output == pRateTransposer); + pTDStretch->putSamples(samples, numSamples); + pRateTransposer->moveSamples(*pTDStretch); + } +} + + +// Flushes the last samples from the processing pipeline to the output. +// Clears also the internal processing buffers. +// +// Note: This function is meant for extracting the last samples of a sound +// stream. This function may introduce additional blank samples in the end +// of the sound stream, and thus it's not recommended to call this function +// in the middle of a sound stream. +void SoundTouch::flush() +{ + int i; + uint nOut; + SAMPLETYPE buff[128]; + + nOut = numSamples(); + + memset(buff, 0, 128 * sizeof(SAMPLETYPE)); + // "Push" the last active samples out from the processing pipeline by + // feeding blank samples into the processing pipeline until new, + // processed samples appear in the output (not however, more than + // 8ksamples in any case) + for (i = 0; i < 128; i ++) + { + putSamples(buff, 64); + if (numSamples() != nOut) break; // new samples have appeared in the output! + } + + // Clear working buffers + pRateTransposer->clear(); + pTDStretch->clearInput(); + // yet leave the 'tempoChanger' output intouched as that's where the + // flushed samples are! +} + + +// Changes a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +BOOL SoundTouch::setSetting(uint settingId, uint value) +{ + uint sampleRate, sequenceMs, seekWindowMs, overlapMs; + + // read current tdstretch routine parameters + pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + // enables / disabless anti-alias filter + pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_AA_FILTER_LENGTH : + // sets anti-alias filter length + pRateTransposer->getAAFilter()->setLength(value); + return TRUE; + + case SETTING_USE_QUICKSEEK : + // enables / disables tempo routine quick seeking algorithm + pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_SEQUENCE_MS: + // change time-stretch sequence duration parameter + pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); + return TRUE; + + case SETTING_SEEKWINDOW_MS: + // change time-stretch seek window length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); + return TRUE; + + case SETTING_OVERLAP_MS: + // change time-stretch overlap length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); + return TRUE; + + default : + return FALSE; + } +} + + +// Reads a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +// +// Returns the setting value. +uint SoundTouch::getSetting(uint settingId) const +{ + uint temp; + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + return pRateTransposer->isAAFilterEnabled(); + + case SETTING_AA_FILTER_LENGTH : + return pRateTransposer->getAAFilter()->getLength(); + + case SETTING_USE_QUICKSEEK : + return pTDStretch->isQuickSeekEnabled(); + + case SETTING_SEQUENCE_MS: + pTDStretch->getParameters(NULL, &temp, NULL, NULL); + return temp; + + case SETTING_SEEKWINDOW_MS: + pTDStretch->getParameters(NULL, NULL, &temp, NULL); + return temp; + + case SETTING_OVERLAP_MS: + pTDStretch->getParameters(NULL, NULL, NULL, &temp); + return temp; + + default : + return 0; + } +} + + +// Clears all the samples in the object's output and internal processing +// buffers. +void SoundTouch::clear() +{ + pRateTransposer->clear(); + pTDStretch->clear(); +} + + + +/// Returns number of samples currently unprocessed. +uint SoundTouch::numUnprocessedSamples() const +{ + FIFOSamplePipe * psp; + if (pTDStretch) + { + psp = pTDStretch->getInput(); + if (psp) + { + return psp->numSamples(); + } + } + return 0; +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.h new file mode 100644 index 0000000000..fab3bb9845 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/SoundTouch.h @@ -0,0 +1,252 @@ +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.14 $ +// +// $Id: SoundTouch.h,v 1.14 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef SoundTouch_H +#define SoundTouch_H + +#include "FIFOSamplePipe.h" +#include "STTypes.h" + +namespace soundtouch +{ + +/// Soundtouch library version string +#define SOUNDTOUCH_VERSION "1.3.1" + +/// SoundTouch library version id +#define SOUNDTOUCH_VERSION_ID 010301 + +// +// Available setting IDs for the 'setSetting' & 'get_setting' functions: + +/// Enable/disable anti-alias filter in pitch transposer (0 = disable) +#define SETTING_USE_AA_FILTER 0 + +/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) +#define SETTING_AA_FILTER_LENGTH 1 + +/// Enable/disable quick seeking algorithm in tempo changer routine +/// (enabling quick seeking lowers CPU utilization but causes a minor sound +/// quality compromising) +#define SETTING_USE_QUICKSEEK 2 + +/// Time-stretch algorithm single processing sequence length in milliseconds. This determines +/// to how long sequences the original sound is chopped in the time-stretch algorithm. +/// See "STTypes.h" or README for more information. +#define SETTING_SEQUENCE_MS 3 + +/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the +/// best possible overlapping location. This determines from how wide window the algorithm +/// may look for an optimal joining location when mixing the sound sequences back together. +/// See "STTypes.h" or README for more information. +#define SETTING_SEEKWINDOW_MS 4 + +/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences +/// are mixed back together, to form a continuous sound stream, this parameter defines over +/// how long period the two consecutive sequences are let to overlap each other. +/// See "STTypes.h" or README for more information. +#define SETTING_OVERLAP_MS 5 + + +class SoundTouch : public FIFOProcessor +{ +private: + /// Rate transposer class instance + class RateTransposer *pRateTransposer; + + /// Time-stretch class instance + class TDStretch *pTDStretch; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualRate; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualTempo; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualPitch; + + /// Flag: Has sample rate been set? + BOOL bSrateSet; + + /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and + /// 'virtualPitch' parameters. + void calcEffectiveRateAndTempo(); + +protected : + /// Number of channels + uint channels; + + /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float rate; + + /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float tempo; + +public: + SoundTouch(); + virtual ~SoundTouch(); + + /// Get SoundTouch library version string + static const char *getVersionString(); + + /// Get SoundTouch library version Id + static uint getVersionId(); + + /// Sets new rate control value. Normal rate = 1.0, smaller values + /// represent slower rate, larger faster rates. + void setRate(float newRate); + + /// Sets new tempo control value. Normal tempo = 1.0, smaller values + /// represent slower tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Sets new rate control value as a difference in percents compared + /// to the original rate (-50 .. +100 %) + void setRateChange(float newRate); + + /// Sets new tempo control value as a difference in percents compared + /// to the original tempo (-50 .. +100 %) + void setTempoChange(float newTempo); + + /// Sets new pitch control value. Original pitch = 1.0, smaller values + /// represent lower pitches, larger values higher pitch. + void setPitch(float newPitch); + + /// Sets pitch change in octaves compared to the original pitch + /// (-1.00 .. +1.00) + void setPitchOctaves(float newPitch); + + /// Sets pitch change in semi-tones compared to the original pitch + /// (-12 .. +12) + void setPitchSemiTones(int newPitch); + void setPitchSemiTones(float newPitch); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Sets sample rate. + void setSampleRate(uint srate); + + /// Flushes the last samples from the processing pipeline to the output. + /// Clears also the internal processing buffers. + // + /// Note: This function is meant for extracting the last samples of a sound + /// stream. This function may introduce additional blank samples in the end + /// of the sound stream, and thus it's not recommended to call this function + /// in the middle of a sound stream. + void flush(); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. Notice that sample rate _has_to_ be set before + /// calling this function, otherwise throws a runtime_error exception. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Pointer to sample buffer. + uint numSamples ///< Number of samples in buffer. Notice + ///< that in case of stereo-sound a single sample + ///< contains data for both channels. + ); + + /// Clears all the samples in the object's output and internal processing + /// buffers. + virtual void clear(); + + /// Changes a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return 'TRUE' if the setting was succesfully changed + BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines. + uint value ///< New setting value. + ); + + /// Reads a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return the setting value. + uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines. + ) const; + + /// Returns number of samples currently unprocessed. + virtual uint numUnprocessedSamples() const; + + + /// Other handy functions that are implemented in the ancestor classes (see + /// classes 'FIFOProcessor' and 'FIFOSamplePipe') + /// + /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. + /// - numSamples() : Get number of 'ready' samples that can be received with + /// function 'receiveSamples()' + /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. + /// - clear() : Clears all samples from ready/processing buffers. +}; + +} +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.cpp new file mode 100644 index 0000000000..d809623689 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.cpp @@ -0,0 +1,940 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like +/// method with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific +/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.24 $ +// +// $Id: TDStretch.cpp,v 1.24 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "STTypes.h" +#include "cpu_detect.h" +#include "TDStretch.h" + +using namespace soundtouch; + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + + +/***************************************************************************** + * + * Constant definitions + * + *****************************************************************************/ + + +// Table for the hierarchical mixing position seeking algorithm +int scanOffsets[4][24]={ + { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, + 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0}, + {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/***************************************************************************** + * + * Implementation of the class 'TDStretch' + * + *****************************************************************************/ + + +TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) +{ + bQuickseek = FALSE; + channels = 2; + bMidBufferDirty = FALSE; + + pMidBuffer = NULL; + pRefMidBufferUnaligned = NULL; + overlapLength = 0; + + setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); + + setTempo(1.0f); +} + + + + +TDStretch::~TDStretch() +{ + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; +} + + + +// Calculates the x having the closest 2^x value for the given value +static int _getClosest2Power(double value) +{ + return (int)(log(value) / log(2.0) + 0.5); +} + + + +// Sets routine control parameters. These control are certain time constants +// defining how the sound is stretched to the desired duration. +// +// 'sampleRate' = sample rate of the sound +// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) +// 'seekwindowMS' = seeking window length for scanning the best overlapping +// position (default = 28 ms) +// 'overlapMS' = overlapping length (default = 12 ms) + +void TDStretch::setParameters(uint aSampleRate, uint aSequenceMS, + uint aSeekWindowMS, uint aOverlapMS) +{ + this->sampleRate = aSampleRate; + this->sequenceMs = aSequenceMS; + this->seekWindowMs = aSeekWindowMS; + this->overlapMs = aOverlapMS; + + seekLength = (sampleRate * seekWindowMs) / 1000; + seekWindowLength = (sampleRate * sequenceMs) / 1000; + + maxOffset = seekLength; + + calculateOverlapLength(overlapMs); + + // set tempo to recalculate 'sampleReq' + setTempo(tempo); + +} + + + +/// Get routine control parameters, see setParameters() function. +/// Any of the parameters to this function can be NULL, in such case corresponding parameter +/// value isn't returned. +void TDStretch::getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs) +{ + if (pSampleRate) + { + *pSampleRate = sampleRate; + } + + if (pSequenceMs) + { + *pSequenceMs = sequenceMs; + } + + if (pSeekWindowMs) + { + *pSeekWindowMs = seekWindowMs; + } + + if (pOverlapMs) + { + *pOverlapMs = overlapMs; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input' +void TDStretch::overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const +{ + int i, itemp; + + for (i = 0; i < (int)overlapLength ; i ++) + { + itemp = overlapLength - i; + output[i] = (input[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits; + } +} + + + +void TDStretch::clearMidBuffer() +{ + if (bMidBufferDirty) + { + memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = FALSE; + } +} + + +void TDStretch::clearInput() +{ + inputBuffer.clear(); + clearMidBuffer(); +} + + +// Clears the sample buffers +void TDStretch::clear() +{ + outputBuffer.clear(); + inputBuffer.clear(); + clearMidBuffer(); +} + + + +// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero +// to enable +void TDStretch::enableQuickSeek(BOOL enable) +{ + bQuickseek = enable; +} + + +// Returns nonzero if the quick seeking algorithm is enabled. +BOOL TDStretch::isQuickSeekEnabled() const +{ + return bQuickseek; +} + + +// Seeks for the optimal overlap-mixing position. +uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) +{ + if (channels == 2) + { + // stereo sound + if (bQuickseek) + { + return seekBestOverlapPositionStereoQuick(refPos); + } + else + { + return seekBestOverlapPositionStereo(refPos); + } + } + else + { + // mono sound + if (bQuickseek) + { + return seekBestOverlapPositionMonoQuick(refPos); + } + else + { + return seekBestOverlapPositionMono(refPos); + } + } +} + + + + +// Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position +// of 'ovlPos'. +inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const +{ + if (channels == 2) + { + // stereo sound + overlapStereo(output, input + 2 * ovlPos); + } else { + // mono sound. + overlapMono(output, input + ovlPos); + } +} + + + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint i; + + // Slopes the amplitudes of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (i = 0; i < seekLength; i ++) + { + // Calculates correlation value for the mixing position corresponding + // to 'i' + corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = i; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint tempOffset; + const SAMPLETYPE *compare; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (tempOffset = 0; tempOffset < seekLength; tempOffset ++) + { + compare = refPos + tempOffset; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(pRefMidBuffer, compare); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +/// clear cross correlation routine state if necessary +void TDStretch::clearCrossCorrState() +{ + // default implementation is empty. +} + + +// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower +// tempo, larger faster tempo. +void TDStretch::setTempo(float newTempo) +{ + uint intskip; + + tempo = newTempo; + + // Calculate ideal skip length (according to tempo value) + nominalSkip = tempo * (seekWindowLength - overlapLength); + skipFract = 0; + intskip = (int)(nominalSkip + 0.5f); + + // Calculate how many samples are needed in the 'inputBuffer' to + // process another batch of samples + sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset; +} + + + +// Sets the number of channels, 1 = mono, 2 = stereo +void TDStretch::setChannels(uint numChannels) +{ + if (channels == numChannels) return; + assert(numChannels == 1 || numChannels == 2); + + channels = numChannels; + inputBuffer.setChannels(channels); + outputBuffer.setChannels(channels); +} + + +// nominal tempo, no need for processing, just pass the samples through +// to outputBuffer +void TDStretch::processNominalTempo() +{ + assert(tempo == 1.0f); + + if (bMidBufferDirty) + { + // If there are samples in pMidBuffer waiting for overlapping, + // do a single sliding overlapping with them in order to prevent a + // clicking distortion in the output sound + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength input samples + return; + } + // Mix the samples in the beginning of 'inputBuffer' with the + // samples in 'midBuffer' using sliding overlapping + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); + outputBuffer.putSamples(overlapLength); + inputBuffer.receiveSamples(overlapLength); + clearMidBuffer(); + // now we've caught the nominal sample flow and may switch to + // bypass mode + } + + // Simply bypass samples from input to output + outputBuffer.moveSamples(inputBuffer); +} + + +// Processes as many processing frames of the samples 'inputBuffer', store +// the result into 'outputBuffer' +void TDStretch::processSamples() +{ + uint ovlSkip, offset; + int temp; + + /* Removed this small optimization - can introduce a click to sound when tempo setting + crosses the nominal value + if (tempo == 1.0f) + { + // tempo not changed from the original, so bypass the processing + processNominalTempo(); + return; + } + */ + + if (bMidBufferDirty == FALSE) + { + // if midBuffer is empty, move the first samples of the input stream + // into it + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength samples + return; + } + memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE)); + inputBuffer.receiveSamples(overlapLength); + bMidBufferDirty = TRUE; + } + + // Process samples as long as there are enough samples in 'inputBuffer' + // to form a processing frame. + while (inputBuffer.numSamples() >= sampleReq) + { + // If tempo differs from the normal ('SCALE'), scan for the best overlapping + // position + offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); + + // Mix the samples in the 'inputBuffer' at position of 'offset' with the + // samples in 'midBuffer' using sliding overlapping + // ... first partially overlap with the end of the previous sequence + // (that's in 'midBuffer') + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset); + outputBuffer.putSamples(overlapLength); + + // ... then copy sequence samples from 'inputBuffer' to output + temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe; + if (temp > 0) + { + outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp); + } + + // Copies the end of the current sequence from 'inputBuffer' to + // 'midBuffer' for being mixed with the beginning of the next + // processing sequence and so on + assert(offset + seekWindowLength <= inputBuffer.numSamples()); + memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength), + channels * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = TRUE; + + // Remove the processed samples from the input buffer. Update + // the difference between integer & nominal skip step to 'skipFract' + // in order to prevent the error from accumulating over time. + skipFract += nominalSkip; // real skip size + ovlSkip = (int)skipFract; // rounded to integer skip + skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip + inputBuffer.receiveSamples(ovlSkip); + } +} + + +// Adds 'numsamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + // Add the samples into the input buffer + inputBuffer.putSamples(samples, numSamples); + // Process the samples in input buffer + processSamples(); +} + + + +/// Set new overlap length parameter & reallocate RefMidBuffer if necessary. +void TDStretch::acceptNewOverlapLength(uint newOverlapLength) +{ + uint prevOvl; + + prevOvl = overlapLength; + overlapLength = newOverlapLength; + + if (overlapLength > prevOvl) + { + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; + + pMidBuffer = new SAMPLETYPE[overlapLength * 2]; + bMidBufferDirty = TRUE; + clearMidBuffer(); + + pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)]; + // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency + pRefMidBuffer = (SAMPLETYPE *)((((ulongptr)pRefMidBufferUnaligned) + 15) & -16); + } +} + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * TDStretch::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +TDStretch * TDStretch::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new TDStretchMMX; + } + else +#endif // ALLOW_MMX + + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new TDStretchSSE; + } + else +#endif // ALLOW_SSE + + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new TDStretch3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new TDStretch; + } +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Integer arithmetics specific algorithm implementations. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef INTEGER_SAMPLES + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + int temp, temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + cnt2 = i * 2; + + temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider; + pRefMidBuffer[cnt2] = (short)(temp2); + temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider; + pRefMidBuffer[cnt2 + 1] = (short)(temp2); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + long temp; + long temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + temp2 = (pMidBuffer[i] * temp) / slopingDivider; + pRefMidBuffer[i] = (short)temp2; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' +// version of the routine. +void TDStretch::overlapStereo(short *output, const short *input) const +{ + int i; + short temp; + uint cnt2; + + for (i = 0; i < (int)overlapLength ; i ++) + { + temp = (short)(overlapLength - i); + cnt2 = 2 * i; + output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength; + output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength; + } +} + + +/// Calculates overlap period length in samples. +/// Integer version rounds overlap length to closest power of 2 +/// for a divide scaling operation. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0); + if (overlapDividerBits > 9) overlapDividerBits = 9; + if (overlapDividerBits < 4) overlapDividerBits = 4; + newOvl = 1<> overlapDividerBits; + } + + return corr; +} + + +long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const +{ + long corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += (mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; + } + + return corr; +} + +#endif // INTEGER_SAMPLES + +////////////////////////////////////////////////////////////////////////////// +// +// Floating point arithmetics specific algorithm implementations. +// + +#ifdef FLOAT_SAMPLES + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + cnt2 = i * 2; + pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp); + pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp); + } +} + + +// SSE-optimized version of the function overlapStereo +void TDStretch::overlapStereo(float *output, const float *input) const +{ + int i; + uint cnt2; + float fTemp; + float fScale; + float fi; + + fScale = 1.0f / (float)overlapLength; + + for (i = 0; i < (int)overlapLength ; i ++) + { + fTemp = (float)(overlapLength - i) * fScale; + fi = (float)i * fScale; + cnt2 = 2 * i; + output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp; + output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp; + } +} + + +/// Calculates overlap period length in samples. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + newOvl = (sampleRate * overlapMs) / 1000; + if (newOvl < 16) newOvl = 16; + + // must be divisible by 8 + newOvl -= newOvl % 8; + + acceptNewOverlapLength(newOvl); +} + + + +double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 1; i < overlapLength; i ++) + { + corr += mixingPos[i] * compare[i]; + } + + return corr; +} + + +double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]; + } + + return corr; +} + +#endif // FLOAT_SAMPLES diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.h new file mode 100644 index 0000000000..a05a7072fc --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/TDStretch.h @@ -0,0 +1,236 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: TDStretch.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TDStretch_H +#define TDStretch_H + +#include "STTypes.h" +#include "RateTransposer.h" +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +// Default values for sound processing parameters: + +/// Default length of a single processing sequence, in milliseconds. This determines to how +/// long sequences the original sound is chopped in the time-stretch algorithm. +/// +/// The larger this value is, the lesser sequences are used in processing. In principle +/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo +/// and vice versa. +/// +/// Increasing this value reduces computational burden & vice versa. +#define DEFAULT_SEQUENCE_MS 61 + +#define DEFAULT_SEEKWINDOW_MS 18 + +#define DEFAULT_OVERLAP_MS 7 + + +/// Class that does the time-stretch (tempo change) effect for the processed +/// sound. +class TDStretch : public FIFOProcessor +{ +protected: + uint channels; + uint sampleReq; + float tempo; + + SAMPLETYPE *pMidBuffer; + SAMPLETYPE *pRefMidBuffer; + SAMPLETYPE *pRefMidBufferUnaligned; + uint overlapLength; + uint overlapDividerBits; + uint slopingDivider; + uint seekLength; + uint seekWindowLength; + uint maxOffset; + float nominalSkip; + float skipFract; + FIFOSampleBuffer outputBuffer; + FIFOSampleBuffer inputBuffer; + BOOL bQuickseek; + BOOL bMidBufferDirty; + + uint sampleRate; + uint sequenceMs; + uint seekWindowMs; + uint overlapMs; + + void acceptNewOverlapLength(uint newOverlapLength); + + virtual void clearCrossCorrState(); + void calculateOverlapLength(uint overlapMs); + + virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + + virtual uint seekBestOverlapPositionStereo(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMono(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos); + uint seekBestOverlapPosition(const SAMPLETYPE *refPos); + + virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; + virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; + + void clearMidBuffer(); + void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; + + void precalcCorrReferenceMono(); + void precalcCorrReferenceStereo(); + + void processNominalTempo(); + + /// Changes the tempo of the given sound samples. + /// Returns amount of samples returned in the "output" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(); + +public: + TDStretch(); + virtual ~TDStretch(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX/SSE/etc-capable CPU available or not. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct feature set depending on if the CPU + /// supports MMX/SSE/etc extensions. + static TDStretch *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the input buffer object + FIFOSamplePipe *getInput() { return &inputBuffer; }; + + /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower + /// tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual void clear(); + + /// Clears the input buffer + void clearInput(); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Enables/disables the quick position seeking algorithm. Zero to disable, + /// nonzero to enable + void enableQuickSeek(BOOL enable); + + /// Returns nonzero if the quick seeking algorithm is enabled. + BOOL isQuickSeekEnabled() const; + + /// Sets routine control parameters. These control are certain time constants + /// defining how the sound is stretched to the desired duration. + // + /// 'sampleRate' = sample rate of the sound + /// 'sequenceMS' = one processing sequence length in milliseconds + /// 'seekwindowMS' = seeking window length for scanning the best overlapping + /// position + /// 'overlapMS' = overlapping length + void setParameters(uint sampleRate, ///< Samplerate of sound being processed (Hz) + uint sequenceMS = DEFAULT_SEQUENCE_MS, ///< Single processing sequence length (ms) + uint seekwindowMS = DEFAULT_SEEKWINDOW_MS, ///< Offset seeking window length (ms) + uint overlapMS = DEFAULT_OVERLAP_MS ///< Sequence overlapping length (ms) + ); + + /// Get routine control parameters, see setParameters() function. + /// Any of the parameters to this function can be NULL, in such case corresponding parameter + /// value isn't returned. + void getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs); + + /// Adds 'numsamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Input sample data + uint numSamples ///< Number of samples in 'samples' so that one sample + ///< contains both channels if stereo + ); +}; + + + +// Implementation-specific class declarations: + +//#ifdef ALLOW_MMX +// /// Class that implements MMX optimized routines for 16bit integer samples type. +// class TDStretchMMX : public TDStretch +// { +// protected: +// long calcCrossCorrStereo(const short *mixingPos, const short *compare) const; +// virtual void overlapStereo(short *output, const short *input) const; +// virtual void clearCrossCorrState(); +// }; +//#endif /// ALLOW_MMX +// +// +//#ifdef ALLOW_3DNOW +// /// Class that implements 3DNow! optimized routines for floating point samples type. +// class TDStretch3DNow : public TDStretch +// { +// protected: +// double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; +// }; +//#endif /// ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized routines for floating point samples type. + class TDStretchSSE : public TDStretch + { + protected: + double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; + }; + +#endif /// ALLOW_SSE + +} +#endif /// TDStretch_H diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.cpp new file mode 100644 index 0000000000..77db8cc431 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.cpp @@ -0,0 +1,714 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, +/// but the reason for 'yet another' one is that those generic WAV reader +/// libraries are exhaustingly large and cumbersome! Wanted to have something +/// simpler here, i.e. something that's not already larger than rest of the +/// SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.15 $ +// +// $Id: WavFile.cpp,v 1.15 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include +#include + +#include "WavFile.h" + +using namespace std; + +const static char riffStr[] = "RIFF"; +const static char waveStr[] = "WAVE"; +const static char fmtStr[] = "fmt "; +const static char dataStr[] = "data"; + + +////////////////////////////////////////////////////////////////////////////// +// +// Helper functions for swapping byte order to correctly read/write WAV files +// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to +// turn-on the conversion if it appears necessary. +// +// For example, Intel x86 is little-endian and doesn't require conversion, +// while PowerPC of Mac's and many other RISC cpu's are big-endian. + +#ifdef BYTE_ORDER + // In gcc compiler detect the byte order automatically + #if BYTE_ORDER == BIG_ENDIAN + // big-endian platform. + #define _BIG_ENDIAN_ + #endif +#endif + +#ifdef _BIG_ENDIAN_ + // big-endian CPU, swap bytes in 16 & 32 bit words + + // helper-function to swap byte-order of 32bit integer + static inline void _swap32(unsigned int &dwData) + { + dwData = ((dwData >> 24) & 0x000000FF) | + ((dwData >> 8) & 0x0000FF00) | + ((dwData << 8) & 0x00FF0000) | + ((dwData << 24) & 0xFF000000); + } + + // helper-function to swap byte-order of 16bit integer + static inline void _swap16(unsigned short &wData) + { + wData = ((wData >> 8) & 0x00FF) | + ((wData << 8) & 0xFF00); + } + + // helper-function to swap byte-order of buffer of 16bit integers + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords) + { + unsigned long i; + + for (i = 0; i < dwNumWords; i ++) + { + _swap16(pData[i]); + } + } + +#else // BIG_ENDIAN + // little-endian CPU, WAV file is ok as such + + // dummy helper-function + static inline void _swap32(unsigned int &dwData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16(unsigned short &wData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) + { + // do nothing + } + +#endif // BIG_ENDIAN + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavInFile +// + +WavInFile::WavInFile(const char *fileName) +{ + int hdrsOk; + + // Try to open the file for reading + fptr = fopen(fileName, "rb"); + if (fptr == NULL) + { + // didn't succeed + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for reading."; + throw runtime_error(msg); + } + + // Read the file headers + hdrsOk = readWavHeaders(); + if (hdrsOk != 0) + { + // Something didn't match in the wav file headers + string msg = "File \""; + msg += fileName; + msg += "\" is corrupt or not a WAV file"; + throw runtime_error(msg); + } + + if (header.format.fixed != 1) + { + string msg = "File \""; + msg += fileName; + msg += "\" uses unsupported encoding."; + throw runtime_error(msg); + } + + dataRead = 0; +} + + + +WavInFile::~WavInFile() +{ + close(); +} + + + +void WavInFile::rewind() +{ + int hdrsOk; + + fseek(fptr, 0, SEEK_SET); + hdrsOk = readWavHeaders(); + assert(hdrsOk == 0); + dataRead = 0; +} + + +int WavInFile::checkCharTags() +{ + // header.format.fmt should equal to 'fmt ' + if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; + // header.data.data_field should equal to 'data' + if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; + + return 0; +} + + +int WavInFile::read(char *buffer, int maxElems) +{ + int numBytes; + uint afterDataRead; + + // ensure it's 8 bit format + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples."); + } + assert(sizeof(char) == 1); + + numBytes = maxElems; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + + return numBytes; +} + + +int WavInFile::read(short *buffer, int maxElems) +{ + unsigned int afterDataRead; + int numBytes; + int numElems; + + if (header.format.bits_per_sample == 8) + { + // 8 bit format + char *temp = new char[maxElems]; + int i; + + numElems = read(temp, maxElems); + // convert from 8 to 16 bit + for (i = 0; i < numElems; i ++) + { + buffer[i] = temp[i] << 8; + } + delete[] temp; + } + else + { + // 16 bit format + assert(header.format.bits_per_sample == 16); + assert(sizeof(short) == 2); + + numBytes = maxElems * 2; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + numElems = numBytes / 2; + + // 16bit samples, swap byte order if necessary + _swap16Buffer((unsigned short *)buffer, numElems); + } + + return numElems; +} + + + +int WavInFile::read(float *buffer, int maxElems) +{ + short *temp = new short[maxElems]; + int num; + int i; + double fscale; + + num = read(temp, maxElems); + + fscale = 1.0 / 32768.0; + // convert to floats, scale to range [-1..+1[ + for (i = 0; i < num; i ++) + { + buffer[i] = (float)(fscale * (double)temp[i]); + } + + delete[] temp; + + return num; +} + + +int WavInFile::eof() const +{ + // return true if all data has been read or file eof has reached + return (dataRead == header.data.data_len || feof(fptr)); +} + + +void WavInFile::close() +{ + fclose(fptr); + fptr = NULL; +} + + + +// test if character code is between a white space ' ' and little 'z' +static int isAlpha(char c) +{ + return (c >= ' ' && c <= 'z') ? 1 : 0; +} + + +// test if all characters are between a white space ' ' and little 'z' +static int isAlphaStr(char *str) +{ + int c; + + c = str[0]; + while (c) + { + if (isAlpha(c) == 0) return 0; + str ++; + c = str[0]; + } + + return 1; +} + + +int WavInFile::readRIFFBlock() +{ + fread(&(header.riff), sizeof(WavRiff), 1, fptr); + + // swap 32bit data byte order if necessary + _swap32((unsigned int &)header.riff.package_len); + + // header.riff.riff_char should equal to 'RIFF'); + if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; + // header.riff.wave should equal to 'WAVE' + if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; + + return 0; +} + + + + +int WavInFile::readHeaderBlock() +{ + char label[5]; + string sLabel; + + // lead label string + fread(label, 1, 4, fptr); + label[4] = 0; + + if (isAlphaStr(label) == 0) return -1; // not a valid label + + // Decode blocks according to their label + if (strcmp(label, fmtStr) == 0) + { + int nLen, nDump; + + // 'fmt ' block + memcpy(header.format.fmt, fmtStr, 4); + + // read length of the format field + fread(&nLen, sizeof(int), 1, fptr); + // swap byte order if necessary + _swap32((unsigned int &)nLen); // int format_len; + header.format.format_len = nLen; + + // calculate how much length differs from expected + nDump = nLen - (sizeof(header.format) - 8); + + // if format_len is larger than expected, read only as much data as we've space for + if (nDump > 0) + { + nLen = sizeof(header.format) - 8; + } + + // read data + fread(&(header.format.fixed), nLen, 1, fptr); + + // swap byte order if necessary + _swap16((unsigned short &)header.format.fixed); // short int fixed; + _swap16((unsigned short &)header.format.channel_number); // short int channel_number; + _swap32((unsigned int &)header.format.sample_rate); // int sample_rate; + _swap32((unsigned int &)header.format.byte_rate); // int byte_rate; + _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample; + _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample; + + // if format_len is larger than expected, skip the extra data + if (nDump > 0) + { + fseek(fptr, nDump, SEEK_CUR); + } + + return 0; + } + else if (strcmp(label, dataStr) == 0) + { + // 'data' block + memcpy(header.data.data_field, dataStr, 4); + fread(&(header.data.data_len), sizeof(uint), 1, fptr); + + // swap byte order if necessary + _swap32((unsigned int &)header.data.data_len); + + return 1; + } + else + { + uint len, i; + uint temp; + // unknown block + + // read length + fread(&len, sizeof(len), 1, fptr); + // scan through the block + for (i = 0; i < len; i ++) + { + fread(&temp, 1, 1, fptr); + if (feof(fptr)) return -1; // unexpected eof + } + } + return 0; +} + + +int WavInFile::readWavHeaders() +{ + int res; + + memset(&header, 0, sizeof(header)); + + res = readRIFFBlock(); + if (res) return 1; + // read header blocks until data block is found + do + { + // read header blocks + res = readHeaderBlock(); + if (res < 0) return 1; // error in file structure + } while (res == 0); + // check that all required tags are legal + return checkCharTags(); +} + + +uint WavInFile::getNumChannels() const +{ + return header.format.channel_number; +} + + +uint WavInFile::getNumBits() const +{ + return header.format.bits_per_sample; +} + + +uint WavInFile::getBytesPerSample() const +{ + return getNumChannels() * getNumBits() / 8; +} + + +uint WavInFile::getSampleRate() const +{ + return header.format.sample_rate; +} + + + +uint WavInFile::getDataSizeInBytes() const +{ + return header.data.data_len; +} + + +uint WavInFile::getNumSamples() const +{ + return header.data.data_len / header.format.byte_per_sample; +} + + +uint WavInFile::getLengthMS() const +{ + uint numSamples; + uint sampleRate; + + numSamples = getNumSamples(); + sampleRate = getSampleRate(); + + assert(numSamples < UINT_MAX / 1000); + return (1000 * numSamples / sampleRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavOutFile +// + +WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) +{ + bytesWritten = 0; + fptr = fopen(fileName, "wb"); + if (fptr == NULL) + { + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for writing."; + //pmsg = msg.c_str; + throw runtime_error(msg); + } + + fillInHeader(sampleRate, bits, channels); + writeHeader(); +} + + + +WavOutFile::~WavOutFile() +{ + close(); +} + + + +void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) +{ + // fill in the 'riff' part.. + + // copy string 'RIFF' to riff_char + memcpy(&(header.riff.riff_char), riffStr, 4); + // package_len unknown so far + header.riff.package_len = 0; + // copy string 'WAVE' to wave + memcpy(&(header.riff.wave), waveStr, 4); + + + // fill in the 'format' part.. + + // copy string 'fmt ' to fmt + memcpy(&(header.format.fmt), fmtStr, 4); + + header.format.format_len = 0x10; + header.format.fixed = 1; + header.format.channel_number = (short)channels; + header.format.sample_rate = sampleRate; + header.format.bits_per_sample = (short)bits; + header.format.byte_per_sample = (short)(bits * channels / 8); + header.format.byte_rate = header.format.byte_per_sample * sampleRate; + header.format.sample_rate = sampleRate; + + // fill in the 'data' part.. + + // copy string 'data' to data_field + memcpy(&(header.data.data_field), dataStr, 4); + // data_len unknown so far + header.data.data_len = 0; +} + + +void WavOutFile::finishHeader() +{ + // supplement the file length into the header structure + header.riff.package_len = bytesWritten + 36; + header.data.data_len = bytesWritten; + + writeHeader(); +} + + + +void WavOutFile::writeHeader() +{ + WavHeader hdrTemp; + + // swap byte order if necessary + hdrTemp = header; + _swap32((unsigned int &)hdrTemp.riff.package_len); + _swap32((unsigned int &)hdrTemp.format.format_len); + _swap16((unsigned short &)hdrTemp.format.fixed); + _swap16((unsigned short &)hdrTemp.format.channel_number); + _swap32((unsigned int &)hdrTemp.format.sample_rate); + _swap32((unsigned int &)hdrTemp.format.byte_rate); + _swap16((unsigned short &)hdrTemp.format.byte_per_sample); + _swap16((unsigned short &)hdrTemp.format.bits_per_sample); + _swap32((unsigned int &)hdrTemp.data.data_len); + + // write the supplemented header in the beginning of the file + fseek(fptr, 0, SEEK_SET); + fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); + // jump back to the end of the file + fseek(fptr, 0, SEEK_END); +} + + + +void WavOutFile::close() +{ + finishHeader(); + fclose(fptr); + fptr = NULL; +} + + +void WavOutFile::write(const char *buffer, int numElems) +{ + int res; + + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples."); + } + assert(sizeof(char) == 1); + + res = fwrite(buffer, 1, numElems, fptr); + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + + bytesWritten += numElems; +} + + +void WavOutFile::write(const short *buffer, int numElems) +{ + int res; + + // 16 bit samples + if (numElems < 1) return; // nothing to do + + if (header.format.bits_per_sample == 8) + { + int i; + char *temp = new char[numElems]; + // convert from 16bit format to 8bit format + for (i = 0; i < numElems; i ++) + { + temp[i] = buffer[i] >> 8; + } + // write in 8bit format + write(temp, numElems); + delete[] temp; + } + else + { + // 16bit format + unsigned short *pTemp = new unsigned short[numElems]; + + assert(header.format.bits_per_sample == 16); + + // allocate temp buffer to swap byte order if necessary + memcpy(pTemp, buffer, numElems * 2); + _swap16Buffer(pTemp, numElems); + + res = fwrite(pTemp, 2, numElems, fptr); + + delete[] pTemp; + + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + bytesWritten += 2 * numElems; + } +} + + +void WavOutFile::write(const float *buffer, int numElems) +{ + int i; + short *temp = new short[numElems]; + int iTemp; + + // convert to 16 bit integer + for (i = 0; i < numElems; i ++) + { + // convert to integer + iTemp = (int)(32768.0f * buffer[i]); + + // saturate + if (iTemp < -32768) iTemp = -32768; + if (iTemp > 32767) iTemp = 32767; + temp[i] = (short)iTemp; + } + + write(temp, numElems); + + delete[] temp; +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.h new file mode 100644 index 0000000000..dd239034d2 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/WavFile.h @@ -0,0 +1,253 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, but +/// the reason for 'yet another' one is that those generic WAV reader libraries are +/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. +/// something that's not already larger than rest of the SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.7 $ +// +// $Id: WavFile.h,v 1.7 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef WAVFILE_H +#define WAVFILE_H + +#include + +#ifndef uint +typedef unsigned int uint; +#endif + + +/// WAV audio file 'riff' section header +typedef struct +{ + char riff_char[4]; + int package_len; + char wave[4]; +} WavRiff; + +/// WAV audio file 'format' section header +typedef struct +{ + char fmt[4]; + int format_len; + short fixed; + short channel_number; + int sample_rate; + int byte_rate; + short byte_per_sample; + short bits_per_sample; +} WavFormat; + +/// WAV audio file 'data' section header +typedef struct +{ + char data_field[4]; + uint data_len; +} WavData; + + +/// WAV audio file header +typedef struct +{ + WavRiff riff; + WavFormat format; + WavData data; +} WavHeader; + + +/// Class for reading WAV audio files. +class WavInFile +{ +private: + /// File pointer. + FILE *fptr; + + /// Counter of how many bytes of sample data have been read from the file. + uint dataRead; + + /// WAV header information + WavHeader header; + + /// Read WAV file headers. + /// \return zero if all ok, nonzero if file format is invalid. + int readWavHeaders(); + + /// Checks WAV file header tags. + /// \return zero if all ok, nonzero if file format is invalid. + int checkCharTags(); + + /// Reads a single WAV file header block. + /// \return zero if all ok, nonzero if file format is invalid. + int readHeaderBlock(); + + /// Reads WAV file 'riff' block + int readRIFFBlock(); + +public: + /// Constructor: Opens the given WAV file. If the file can't be opened, + /// throws 'runtime_error' exception. + WavInFile(const char *filename); + + /// Destructor: Closes the file. + ~WavInFile(); + + /// Close the file. Notice that file is automatically closed also when the + /// class instance is deleted. + void close(); + + /// Rewind to beginning of the file + void rewind(); + + /// Get sample rate. + uint getSampleRate() const; + + /// Get number of bits per sample, i.e. 8 or 16. + uint getNumBits() const; + + /// Get sample data size in bytes. Ahem, this should return same information as + /// 'getBytesPerSample'... + uint getDataSizeInBytes() const; + + /// Get total number of samples in file. + uint getNumSamples() const; + + /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) + uint getBytesPerSample() const; + + /// Get number of audio channels in the file (1=mono, 2=stereo) + uint getNumChannels() const; + + /// Get the audio file length in milliseconds + uint getLengthMS() const; + + /// Reads audio samples from the WAV file. This routine works only for 8 bit samples. + /// Reads given number of elements from the file or if end-of-file reached, as many + /// elements as are left in the file. + /// + /// \return Number of 8-bit integers read from the file. + int read(char *buffer, int maxElems); + + /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number + /// of elements from the file or if end-of-file reached, as many elements as are + /// left in the file. + /// + /// \return Number of 16-bit integers read from the file. + int read(short *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Reads audio samples from the WAV file to floating point format, converting + /// sample values to range [-1,1[. Reads given number of elements from the file + /// or if end-of-file reached, as many elements as are left in the file. + /// + /// \return Number of elements read from the file. + int read(float *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Check end-of-file. + /// + /// \return Nonzero if end-of-file reached. + int eof() const; +}; + + + +/// Class for writing WAV audio files. +class WavOutFile +{ +private: + /// Pointer to the WAV file + FILE *fptr; + + /// WAV file header data. + WavHeader header; + + /// Counter of how many bytes have been written to the file so far. + int bytesWritten; + + /// Fills in WAV file header information. + void fillInHeader(const uint sampleRate, const uint bits, const uint channels); + + /// Finishes the WAV file header by supplementing information of amount of + /// data written to file etc + void finishHeader(); + + /// Writes the WAV file header. + void writeHeader(); + +public: + /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception + /// if file creation fails. + WavOutFile(const char *fileName, ///< Filename + int sampleRate, ///< Sample rate (e.g. 44100 etc) + int bits, ///< Bits per sample (8 or 16 bits) + int channels ///< Number of channels (1=mono, 2=stereo) + ); + + /// Destructor: Finalizes & closes the WAV file. + ~WavOutFile(); + + /// Write data to WAV file. This function works only with 8bit samples. + /// Throws a 'runtime_error' exception if writing to file fails. + void write(const char *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file. Throws a 'runtime_error' exception if writing to + /// file fails. + void write(const short *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file in floating point format, saturating sample values to range + /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. + void write(const float *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Finalize & close the WAV file. Automatically supplements the WAV file header + /// information according to written data etc. + /// + /// Notice that file is automatically closed also when the class instance is deleted. + void close(); +}; + +#endif diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect.h b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect.h new file mode 100644 index 0000000000..568817f17b --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect.h @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A header file for detecting the Intel MMX instructions set extension. +/// +/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the +/// routine implementations for x86 Windows, x86 gnu version and non-x86 +/// platforms, respectively. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.4 $ +// +// $Id: cpu_detect.h,v 1.4 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _CPU_DETECT_H_ +#define _CPU_DETECT_H_ + +#include "STTypes.h" + +#define SUPPORT_MMX 0x0001 +#define SUPPORT_3DNOW 0x0002 +#define SUPPORT_ALTIVEC 0x0004 +#define SUPPORT_SSE 0x0008 +#define SUPPORT_SSE2 0x0010 + +/// Checks which instruction set extensions are supported by the CPU. +/// +/// \return A bitmask of supported extensions, see SUPPORT_... defines. +uint detectCPUextensions(void); + +/// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint wDisableMask); + +#endif // _CPU_DETECT_H_ diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp new file mode 100644 index 0000000000..75bd771099 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp @@ -0,0 +1,138 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// gcc version of the x86 CPU detect routine. +/// +/// This file is to be compiled on any platform with the GNU C compiler. +/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version +/// of this file. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.6 $ +// +// $Id: cpu_detect_x86_gcc.cpp,v 1.6 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "cpu_detect.h" + +#ifndef __GNUC__ +#error wrong platform - this source code file is for the GNU C compiler. +#endif + +using namespace std; + +#include +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ +#ifndef __i386__ + return 0; // always disable extensions on non-x86 platforms. +#else + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + asm volatile( + "\n\txor %%esi, %%esi" // clear %%esi = result register + // check if 'cpuid' instructions is available by toggling eflags bit 21 + + "\n\tpushf" // save eflags to stack + "\n\tpop %%eax" // load eax from stack (with eflags) + "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx + "\n\txor $0x00200000, %%eax" // toggle bit 21 + "\n\tpush %%eax" // store toggled eflags to stack + "\n\tpopf" // load eflags from stack + "\n\tpushf" // save updated eflags to stack + "\n\tpop %%eax" // load from stack + "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx + "\n\tcmp %%ecx, %%eax" // compare to original eflags values + "\n\tjz end" // jumps to 'end' if cpuid not present + + // cpuid instruction available, test for presence of mmx instructions + + "\n\tmovl $1, %%eax" + "\n\tcpuid" +// movl $0x00800000, %edx // force enable MMX + "\n\ttest $0x00800000, %%edx" + "\n\tjz end" // branch if MMX not available + + "\n\tor $0x01, %%esi" // otherwise add MMX support bit + + "\n\ttest $0x02000000, %%edx" + "\n\tjz test3DNow" // branch if SSE not available + + "\n\tor $0x08, %%esi" // otherwise add SSE support bit + + "\n\ttest3DNow:" + // test for precense of AMD extensions + "\n\tmov $0x80000000, %%eax" + "\n\tcpuid" + "\n\tcmp $0x80000000, %%eax" + "\n\tjbe end" // branch if no AMD extensions detected + + // test for precense of 3DNow! extension + "\n\tmov $0x80000001, %%eax" + "\n\tcpuid" + "\n\ttest $0x80000000, %%edx" + "\n\tjz end" // branch if 3DNow! not detected + + "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit + + "\n\tend:" + + "\n\tmov %%esi, %0" + + : "=r" (res) + : /* no inputs */ + : "%edx", "%eax", "%ecx", "%esi" ); + + return res & ~_dwDisabledISA; +#endif +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_win.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_win.cpp new file mode 100644 index 0000000000..d8f9e58dd0 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/cpu_detect_x86_win.cpp @@ -0,0 +1,126 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the x86 CPU detect routine. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version +/// for all GNU platforms. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: cpu_detect_x86_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" + +#ifndef _WIN32 +#error wrong platform - this source code file is exclusively for Win32 platform +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + _asm + { + ; check if 'cpuid' instructions is available by toggling eflags bit 21 + ; + xor esi, esi ; clear esi = result register + + pushfd ; save eflags to stack + pop eax ; load eax from stack (with eflags) + mov ecx, eax ; save the original eflags values to ecx + xor eax, 0x00200000 ; toggle bit 21 + push eax ; store toggled eflags to stack + popfd ; load eflags from stack + pushfd ; save updated eflags to stack + pop eax ; load from stack + xor edx, edx ; clear edx for defaulting no mmx + cmp eax, ecx ; compare to original eflags values + jz end ; jumps to 'end' if cpuid not present + + ; cpuid instruction available, test for presence of mmx instructions + mov eax, 1 + cpuid + test edx, 0x00800000 + jz end ; branch if MMX not available + + or esi, SUPPORT_MMX ; otherwise add MMX support bit + + test edx, 0x02000000 + jz test3DNow ; branch if SSE not available + + or esi, SUPPORT_SSE ; otherwise add SSE support bit + + test3DNow: + ; test for precense of AMD extensions + mov eax, 0x80000000 + cpuid + cmp eax, 0x80000000 + jbe end ; branch if no AMD extensions detected + + ; test for precense of 3DNow! extension + mov eax, 0x80000001 + cpuid + test edx, 0x80000000 + jz end ; branch if 3DNow! not detected + + or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit + + end: + + mov res, esi + } + + return res & ~_dwDisabledISA; +} diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/mmx_optimized.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/mmx_optimized.cpp new file mode 100644 index 0000000000..f5afb595a5 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/mmx_optimized.cpp @@ -0,0 +1,305 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// MMX optimized routines. All MMX optimized functions have been gathered into +/// this single source code file, regardless to their class or original source +/// code file, in order to ease porting the library to other compiler and +/// processor platforms. +/// +/// The MMX-optimizations are programmed using MMX compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support compiler intrinsic syntax. The update +/// is available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/06 18:52:43 $ +// File revision : $Revision: 1.1 $ +// +// $Id: mmx_optimized.cpp,v 1.1 2006/02/06 18:52:43 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "STTypes.h" + +#ifdef ALLOW_MMX +// MMX routines available only with integer sample type + +#if !(_WIN32 || __i386__ || __x86_64__) +#error "wrong platform - this source code file is exclusively for x86 platforms" +#endif + +using namespace soundtouch; + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'TDStretchMMX' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include +#include + + +// Calculates cross correlation of two buffers +long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const +{ + const __m64 *pVec1, *pVec2; + __m64 shifter; + __m64 accu; + long corr; + uint i; + + pVec1 = (__m64*)pV1; + pVec2 = (__m64*)pV2; + + shifter = _m_from_int(overlapDividerBits); + accu = _mm_setzero_si64(); + + // Process 4 parallel sets of 2 * stereo samples each during each + // round to improve CPU-level parallellization. + for (i = 0; i < overlapLength / 8; i ++) + { + __m64 temp; + + // dictionary of instructions: + // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] + // _mm_add_pi32 : 2*32bit add + // _m_psrad : 32bit right-shift + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), + _mm_madd_pi16(pVec1[1], pVec2[1])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), + _mm_madd_pi16(pVec1[3], pVec2[3])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + pVec1 += 4; + pVec2 += 4; + } + + // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 + // and finally store the result into the variable "corr" + + accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); + corr = _m_to_int(accu); + + // Clear MMS state + _m_empty(); + + return corr; + // Note: Warning about the missing EMMS instruction is harmless + // as it'll be called elsewhere. +} + + + +void TDStretchMMX::clearCrossCorrState() +{ + // Clear MMS state + _m_empty(); + //_asm EMMS; +} + + + +// MMX-optimized version of the function overlapStereo +void TDStretchMMX::overlapStereo(short *output, const short *input) const +{ + const __m64 *pVinput, *pVMidBuf; + __m64 *pVdest; + __m64 mix1, mix2, adder, shifter; + uint i; + + pVinput = (const __m64*)input; + pVMidBuf = (const __m64*)pMidBuffer; + pVdest = (__m64*)output; + + // mix1 = mixer values for 1st stereo sample + // mix1 = mixer values for 2nd stereo sample + // adder = adder for updating mixer values after each round + + mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); + adder = _mm_set_pi16(1, -1, 1, -1); + mix2 = _mm_add_pi16(mix1, adder); + adder = _mm_add_pi16(adder, adder); + + shifter = _m_from_int(overlapDividerBits); + + for (i = 0; i < overlapLength / 4; i ++) + { + __m64 temp1, temp2; + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r + temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + // --- second round begins here --- + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r + temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + pVinput += 2; + pVMidBuf += 2; + pVdest += 2; + } + + _m_empty(); // clear MMS state +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + + +FIRFilterMMX::FIRFilterMMX() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterMMX::~FIRFilterMMX() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for MMX routine +void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new short[2 * newLength + 8]; + filterCoeffsAlign = (short *)(((ulongptr)filterCoeffsUnalign + 15) & -16); + + // rearrange the filter coefficients for mmx routines + for (i = 0;i < length; i += 4) + { + filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; + filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; + + filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; + filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; + } +} + + + +// mmx-optimized version of the filter routine for stereo sound +uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, const uint numSamples) const +{ + // Create stack copies of the needed member variables for asm routines : + uint i, j; + __m64 *pVdest = (__m64*)dest; + + if (length < 2) return 0; + + for (i = 0; i < numSamples / 2; i ++) + { + __m64 accu1; + __m64 accu2; + const __m64 *pVsrc = (const __m64*)src; + const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; + + accu1 = accu2 = _mm_setzero_si64(); + for (j = 0; j < lengthDiv8 * 2; j ++) + { + __m64 temp1, temp2; + + temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 + temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 + + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0 + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1 + + temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2 + + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0 + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1 + + // accu1 += l2*f2+l0*f0 r2*f2+r0*f0 + // += l3*f3+l1*f1 r3*f3+r1*f1 + + // accu2 += l3*f2+l1*f0 r3*f2+r1*f0 + // l4*f3+l2*f1 r4*f3+r2*f1 + + pVfilter += 2; + pVsrc += 2; + } + // accu >>= resultDivFactor + accu1 = _mm_srai_pi32(accu1, resultDivFactor); + accu2 = _mm_srai_pi32(accu2, resultDivFactor); + + // pack 2*2*32bits => 4*16 bits + pVdest[0] = _mm_packs_pi32(accu1, accu2); + src += 4; + pVdest ++; + } + + _m_empty(); // clear emms state + + return (numSamples & 0xfffffffe) - length; +} + +#endif // ALLOW_MMX diff --git a/plugins/spu2ghz/src/3rdparty/SoundTouch/sse_optimized.cpp b/plugins/spu2ghz/src/3rdparty/SoundTouch/sse_optimized.cpp new file mode 100644 index 0000000000..57598d78d7 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/SoundTouch/sse_optimized.cpp @@ -0,0 +1,484 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE +/// optimized functions have been gathered into this single source +/// code file, regardless to their class or original source code file, in order +/// to ease porting the library to other compiler and processor platforms. +/// +/// The SSE-optimizations are programmed using SSE compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support SSE instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.2 $ +// +// $Id: sse_optimized.cpp,v 1.2 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +using namespace soundtouch; + +#ifdef ALLOW_SSE + +// SSE routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'TDStretchSSE' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// Calculates cross correlation of two buffers +double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint i; + __m128 vSum, *pVec2; + + // Note. It means a major slow-down if the routine needs to tolerate + // unaligned __m128 memory accesses. It's way faster if we can skip + // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. + // This can mean up to ~ 10-fold difference (incl. part of which is + // due to skipping every second round for stereo sound though). + // + // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided + // for choosing if this little cheating is allowed. + +#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION + // Little cheating allowed, return valid correlation only for + // aligned locations, meaning every second round for stereo sound. + + #define _MM_LOAD _mm_load_ps + + if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations + +#else + // No cheating allowed, use unaligned load & take the resulting + // performance hit. + #define _MM_LOAD _mm_loadu_ps +#endif + + // ensure overlapLength is divisible by 8 + assert((overlapLength % 8) == 0); + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. + pVec2 = (__m128*)pV2; + vSum = _mm_setzero_ps(); + + // Unroll the loop by factor of 4 * 4 operations + for (i = 0; i < overlapLength / 8; i ++) + { + // vSum += pV1[0..3] * pV2[0..3] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1),pVec2[0])); + + // vSum += pV1[4..7] * pV2[4..7] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 4), pVec2[1])); + + // vSum += pV1[8..11] * pV2[8..11] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 8), pVec2[2])); + + // vSum += pV1[12..15] * pV2[12..15] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 12), pVec2[3])); + + pV1 += 16; + pVec2 += 4; + } + + // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] + float *pvSum = (float*)&vSum; + return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]); + + /* This is approximately corresponding routine in C-language: + double corr; + uint i; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + corr = 0.0; + for (i = 0; i < overlapLength / 8; i ++) + { + corr += pV1[0] * pV2[0] + + pV1[1] * pV2[1] + + pV1[2] * pV2[2] + + pV1[3] * pV2[3] + + pV1[4] * pV2[4] + + pV1[5] * pV2[5] + + pV1[6] * pV2[6] + + pV1[7] * pV2[7] + + pV1[8] * pV2[8] + + pV1[9] * pV2[9] + + pV1[10] * pV2[10] + + pV1[11] * pV2[11] + + pV1[12] * pV2[12] + + pV1[13] * pV2[13] + + pV1[14] * pV2[14] + + pV1[15] * pV2[15]; + + pV1 += 16; + pV2 += 16; + } + */ + + /* This is corresponding routine in assembler. This may be teeny-weeny bit faster + than intrinsic version, but more difficult to maintain & get compiled on multiple + platforms. + + uint overlapLengthLocal = overlapLength; + float corr; + + _asm + { + // Very important note: data in 'pV2' _must_ be aligned to + // 16-byte boundary! + + // give prefetch hints to CPU of what data are to be needed soonish + // give more aggressive hints on pV1 as that changes while pV2 stays + // same between runs + prefetcht0 [pV1] + prefetcht0 [pV2] + prefetcht0 [pV1 + 32] + + mov eax, dword ptr pV1 + mov ebx, dword ptr pV2 + + xorps xmm0, xmm0 + + mov ecx, overlapLengthLocal + shr ecx, 3 // div by eight + + loop1: + prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish + movups xmm1, [eax] + mulps xmm1, [ebx] + addps xmm0, xmm1 + + movups xmm2, [eax + 16] + mulps xmm2, [ebx + 16] + addps xmm0, xmm2 + + prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm3, [eax + 32] + mulps xmm3, [ebx + 32] + addps xmm0, xmm3 + + movups xmm4, [eax + 48] + mulps xmm4, [ebx + 48] + addps xmm0, xmm4 + + add eax, 64 + add ebx, 64 + + dec ecx + jnz loop1 + + // add the four floats of xmm0 together and return the result. + + movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1 + addps xmm1, xmm0 + movaps xmm2, xmm1 + shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2 + addss xmm2, xmm1 + movss corr, xmm2 + } + + return (double)corr; + */ +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilterSSE::FIRFilterSSE() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterSSE::~FIRFilterSSE() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for SSE routine +void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + + +// SSE-optimized version of the filter routine for stereo sound +uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const +{ + int count = (numSamples - length) & -2; + int j; + + assert(count % 2 == 0); + + if (count < 2) return 0; + + assert((length % 8) == 0); + assert(((unsigned long)filterCoeffsAlign) % 16 == 0); + + // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' + for (j = 0; j < count; j += 2) + { + const float *pSrc; + const __m128 *pFil; + __m128 sum1, sum2; + uint i; + + pSrc = source; // source audio data + pFil = (__m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients + // are aligned to 16-byte boundary + sum1 = sum2 = _mm_setzero_ps(); + + for (i = 0; i < length / 8; i ++) + { + // Unroll loop for efficiency & calculate filter for 2*2 stereo samples + // at each pass + + // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset + // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); + + pSrc += 16; + pFil += 4; + } + + // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + // post-shuffle & add the filtered values and store to dest. + _mm_storeu_ps(dest, _mm_add_ps( + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 + )); + source += 4; + dest += 4; + } + + // Ideas for further improvement: + // 1. If it could be guaranteed that 'source' were always aligned to 16-byte + // boundary, a faster aligned '_mm_load_ps' instruction could be used. + // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte + // boundary, a faster '_mm_store_ps' instruction could be used. + + return (uint)count; + + /* original routine in C-language. please notice the C-version has differently + organized coefficients though. + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + const float *pFil; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + pFil = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * pFil[0] + + ptr[2] * pFil[2] + + ptr[4] * pFil[4] + + ptr[6] * pFil[6]; + + sumr1 += ptr[1] * pFil[1] + + ptr[3] * pFil[3] + + ptr[5] * pFil[5] + + ptr[7] * pFil[7]; + + suml2 += ptr[8] * pFil[0] + + ptr[10] * pFil[2] + + ptr[12] * pFil[4] + + ptr[14] * pFil[6]; + + sumr2 += ptr[9] * pFil[1] + + ptr[11] * pFil[3] + + ptr[13] * pFil[5] + + ptr[15] * pFil[7]; + + ptr += 16; + pFil += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + */ + + + /* Similar routine in assembly, again obsoleted due to maintainability + _asm + { + // Very important note: data in 'src' _must_ be aligned to + // 16-byte boundary! + mov edx, count + mov ebx, dword ptr src + mov eax, dword ptr dest + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + + // give prefetch hints to CPU of what data are to be needed soonish + prefetcht0 [ebx] + prefetcht0 [filterCoeffsLocal] + + mov esi, ebx + mov edi, filterCoeffsLocal + xorps xmm0, xmm0 + xorps xmm1, xmm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples + prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm2, [esi] // possibly unaligned load + movups xmm3, [esi + 8] // possibly unaligned load + mulps xmm2, [edi] + mulps xmm3, [edi] + addps xmm0, xmm2 + addps xmm1, xmm3 + + movups xmm4, [esi + 16] // possibly unaligned load + movups xmm5, [esi + 24] // possibly unaligned load + mulps xmm4, [edi + 16] + mulps xmm5, [edi + 16] + addps xmm0, xmm4 + addps xmm1, xmm5 + + prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm6, [esi + 32] // possibly unaligned load + movups xmm7, [esi + 40] // possibly unaligned load + mulps xmm6, [edi + 32] + mulps xmm7, [edi + 32] + addps xmm0, xmm6 + addps xmm1, xmm7 + + movups xmm4, [esi + 48] // possibly unaligned load + movups xmm5, [esi + 56] // possibly unaligned load + mulps xmm4, [edi + 48] + mulps xmm5, [edi + 48] + addps xmm0, xmm4 + addps xmm1, xmm5 + + add esi, 64 + add edi, 64 + dec ecx + jnz loop2 + + // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2 + movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2 + shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0 + addps xmm0, xmm2 + + movaps [eax], xmm0 + add ebx, 16 + add eax, 16 + + dec edx + jnz loop1 + } + */ +} + +#endif // ALLOW_SSE diff --git a/plugins/spu2ghz/src/3rdparty/liba52/a52.h b/plugins/spu2ghz/src/3rdparty/liba52/a52.h new file mode 100644 index 0000000000..2fc6c83309 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/a52.h @@ -0,0 +1,62 @@ +/* + * a52.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 A52_H +#define A52_H + +#ifndef LIBA52_DOUBLE +typedef float sample_t; +#else +typedef double sample_t; +#endif + +typedef struct a52_state_s a52_state_t; + +#define A52_CHANNEL 0 +#define A52_MONO 1 +#define A52_STEREO 2 +#define A52_3F 3 +#define A52_2F1R 4 +#define A52_3F1R 5 +#define A52_2F2R 6 +#define A52_3F2R 7 +#define A52_CHANNEL1 8 +#define A52_CHANNEL2 9 +#define A52_DOLBY 10 +#define A52_CHANNEL_MASK 15 + +#define A52_LFE 16 +#define A52_ADJUST_LEVEL 32 + +a52_state_t * a52_init (uint32_t mm_accel); +sample_t * a52_samples (a52_state_t * state); +int a52_syncinfo (uint8_t * buf, int * flags, + int * sample_rate, int * bit_rate); +int a52_frame (a52_state_t * state, uint8_t * buf, int * flags, + sample_t * level, sample_t bias); +void a52_dynrng (a52_state_t * state, + sample_t (* call) (sample_t, void *), void * data); +int a52_block (a52_state_t * state); +void a52_free (a52_state_t * state); + +#endif /* A52_H */ diff --git a/plugins/spu2ghz/src/3rdparty/liba52/a52_internal.h b/plugins/spu2ghz/src/3rdparty/liba52/a52_internal.h new file mode 100644 index 0000000000..bc896cb1ff --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/a52_internal.h @@ -0,0 +1,123 @@ +/* + * a52_internal.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ + +typedef struct { + uint8_t bai; /* fine SNR offset, fast gain */ + uint8_t deltbae; /* delta bit allocation exists */ + int8_t deltba[50]; /* per-band delta bit allocation */ +} ba_t; + +typedef struct { + uint8_t exp[256]; /* decoded channel exponents */ + int8_t bap[256]; /* derived channel bit allocation */ +} expbap_t; + +struct a52_state_s { + uint8_t fscod; /* sample rate */ + uint8_t halfrate; /* halfrate factor */ + uint8_t acmod; /* coded channels */ + uint8_t lfeon; /* coded lfe channel */ + sample_t clev; /* centre channel mix level */ + sample_t slev; /* surround channels mix level */ + + int output; /* type of output */ + sample_t level; /* output level */ + sample_t bias; /* output bias */ + + int dynrnge; /* apply dynamic range */ + sample_t dynrng; /* dynamic range */ + void * dynrngdata; /* dynamic range callback funtion and data */ + sample_t (* dynrngcall) (sample_t range, void * dynrngdata); + + uint8_t chincpl; /* channel coupled */ + uint8_t phsflginu; /* phase flags in use (stereo only) */ + uint8_t cplstrtmant; /* coupling channel start mantissa */ + uint8_t cplendmant; /* coupling channel end mantissa */ + uint32_t cplbndstrc; /* coupling band structure */ + sample_t cplco[5][18]; /* coupling coordinates */ + + /* derived information */ + uint8_t cplstrtbnd; /* coupling start band (for bit allocation) */ + uint8_t ncplbnd; /* number of coupling bands */ + + uint8_t rematflg; /* stereo rematrixing */ + + uint8_t endmant[5]; /* channel end mantissa */ + + uint16_t bai; /* bit allocation information */ + + uint32_t * buffer_start; + uint16_t lfsr_state; /* dither state */ + uint32_t bits_left; + uint32_t current_word; + + uint8_t csnroffst; /* coarse SNR offset */ + ba_t cplba; /* coupling bit allocation parameters */ + ba_t ba[5]; /* channel bit allocation parameters */ + ba_t lfeba; /* lfe bit allocation parameters */ + + uint8_t cplfleak; /* coupling fast leak init */ + uint8_t cplsleak; /* coupling slow leak init */ + + expbap_t cpl_expbap; + expbap_t fbw_expbap[5]; + expbap_t lfe_expbap; + + sample_t * samples; + int downmixed; +}; + +// [Air]: Added sample_t casts here. +// Improves SSE2 optimization efficiency under Visual Studio 2008 + +#define LEVEL_PLUS6DB ((sample_t)2.0) +#define LEVEL_PLUS3DB ((sample_t)1.4142135623730951) +#define LEVEL_3DB ((sample_t)0.7071067811865476) +#define LEVEL_45DB ((sample_t)0.5946035575013605) +#define LEVEL_6DB ((sample_t)0.5) + +#define EXP_REUSE (0) +#define EXP_D15 (1) +#define EXP_D25 (2) +#define EXP_D45 (3) + +#define DELTA_BIT_REUSE (0) +#define DELTA_BIT_NEW (1) +#define DELTA_BIT_NONE (2) +#define DELTA_BIT_RESERVED (3) + +void a52_bit_allocate (a52_state_t * state, ba_t * ba, int bndstart, + int start, int end, int fastleak, int slowleak, + expbap_t * expbap); + +int a52_downmix_init (int input, int flags, sample_t * level, + sample_t clev, sample_t slev); +int a52_downmix_coeff (sample_t * coeff, int acmod, int output, sample_t level, + sample_t clev, sample_t slev); +void a52_downmix (sample_t * samples, int acmod, int output, sample_t bias, + sample_t clev, sample_t slev); +void a52_upmix (sample_t * samples, int acmod, int output); + +void a52_imdct_init (uint32_t mm_accel); +void a52_imdct_256 (sample_t * data, sample_t * delay, sample_t bias); +void a52_imdct_512 (sample_t * data, sample_t * delay, sample_t bias); diff --git a/plugins/spu2ghz/src/3rdparty/liba52/attributes.h b/plugins/spu2ghz/src/3rdparty/liba52/attributes.h new file mode 100644 index 0000000000..5a9d4c7aae --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/attributes.h @@ -0,0 +1,29 @@ +/* + * attributes.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ + +/* use gcc attribs to align critical data structures */ +#ifdef ATTRIBUTE_ALIGNED_MAX +#define ATTR_ALIGN(align) __attribute__ ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX < align) ? ATTRIBUTE_ALIGNED_MAX : align))) +#else +#define ATTR_ALIGN(align) +#endif diff --git a/plugins/spu2ghz/src/3rdparty/liba52/bit_allocate.c b/plugins/spu2ghz/src/3rdparty/liba52/bit_allocate.c new file mode 100644 index 0000000000..6102b5c16d --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/bit_allocate.c @@ -0,0 +1,265 @@ +/* + * bit_allocate.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 "config.h" + +#include "inttypes.h" + +#include "a52.h" +#include "a52_internal.h" + +static int hthtab[3][50] = { + {0x730, 0x730, 0x7c0, 0x800, 0x820, 0x840, 0x850, 0x850, 0x860, 0x860, + 0x860, 0x860, 0x860, 0x870, 0x870, 0x870, 0x880, 0x880, 0x890, 0x890, + 0x8a0, 0x8a0, 0x8b0, 0x8b0, 0x8c0, 0x8c0, 0x8d0, 0x8e0, 0x8f0, 0x900, + 0x910, 0x910, 0x910, 0x910, 0x900, 0x8f0, 0x8c0, 0x870, 0x820, 0x7e0, + 0x7a0, 0x770, 0x760, 0x7a0, 0x7c0, 0x7c0, 0x6e0, 0x400, 0x3c0, 0x3c0}, + {0x710, 0x710, 0x7a0, 0x7f0, 0x820, 0x830, 0x840, 0x850, 0x850, 0x860, + 0x860, 0x860, 0x860, 0x860, 0x870, 0x870, 0x870, 0x880, 0x880, 0x880, + 0x890, 0x890, 0x8a0, 0x8a0, 0x8b0, 0x8b0, 0x8c0, 0x8c0, 0x8e0, 0x8f0, + 0x900, 0x910, 0x910, 0x910, 0x910, 0x900, 0x8e0, 0x8b0, 0x870, 0x820, + 0x7e0, 0x7b0, 0x760, 0x770, 0x7a0, 0x7c0, 0x780, 0x5d0, 0x3c0, 0x3c0}, + {0x680, 0x680, 0x750, 0x7b0, 0x7e0, 0x810, 0x820, 0x830, 0x840, 0x850, + 0x850, 0x850, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, + 0x870, 0x870, 0x870, 0x870, 0x880, 0x880, 0x880, 0x890, 0x8a0, 0x8b0, + 0x8c0, 0x8d0, 0x8e0, 0x8f0, 0x900, 0x910, 0x910, 0x910, 0x900, 0x8f0, + 0x8d0, 0x8b0, 0x840, 0x7f0, 0x790, 0x760, 0x7a0, 0x7c0, 0x7b0, 0x720} +}; + +static int8_t baptab[305] = { + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, /* 93 padding elems */ + + 16, 16, 16, 16, 16, 16, 16, 16, 16, 14, 14, 14, 14, 14, 14, 14, + 14, 12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9, + 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, + 5, 4, 4, -3, -3, 3, 3, 3, -2, -2, -1, -1, -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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 /* 148 padding elems */ +}; + +static int bndtab[30] = {21, 22, 23, 24, 25, 26, 27, 28, 31, 34, + 37, 40, 43, 46, 49, 55, 61, 67, 73, 79, + 85, 97, 109, 121, 133, 157, 181, 205, 229, 253}; + +static int8_t latab[256] = { + -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, + -52, -52, -51, -50, -49, -48, -47, -47, -46, -45, -44, -44, + -43, -42, -41, -41, -40, -39, -38, -38, -37, -36, -36, -35, + -35, -34, -33, -33, -32, -32, -31, -30, -30, -29, -29, -28, + -28, -27, -27, -26, -26, -25, -25, -24, -24, -23, -23, -22, + -22, -21, -21, -21, -20, -20, -19, -19, -19, -18, -18, -18, + -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, -14, + -13, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11, + -10, -10, -10, -10, -10, -9, -9, -9, -9, -9, -8, -8, + -8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -6, -6, + -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, + -5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, + -4, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, + -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -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, 0 +}; + +#define UPDATE_LEAK() \ +do { \ + fastleak += fdecay; \ + if (fastleak > psd + fgain) \ + fastleak = psd + fgain; \ + slowleak += sdecay; \ + if (slowleak > psd + sgain) \ + slowleak = psd + sgain; \ +} while (0) + +#define COMPUTE_MASK() \ +do { \ + if (psd > dbknee) \ + mask -= (psd - dbknee) >> 2; \ + if (mask > hth [i >> halfrate]) \ + mask = hth [i >> halfrate]; \ + mask -= snroffset + 128 * deltba[i]; \ + mask = (mask > 0) ? 0 : ((-mask) >> 5); \ + mask -= floor; \ +} while (0) + +void a52_bit_allocate (a52_state_t * state, ba_t * ba, int bndstart, + int start, int end, int fastleak, int slowleak, + expbap_t * expbap) +{ + static int slowgain[4] = {0x540, 0x4d8, 0x478, 0x410}; + static int dbpbtab[4] = {0xc00, 0x500, 0x300, 0x100}; + static int floortab[8] = {0x910, 0x950, 0x990, 0x9d0, + 0xa10, 0xa90, 0xb10, 0x1400}; + + int i, j; + uint8_t * exp; + int8_t * bap; + int fdecay, fgain, sdecay, sgain, dbknee, floor, snroffset; + int psd, mask; + int8_t * deltba; + int * hth; + int halfrate; + + halfrate = state->halfrate; + fdecay = (63 + 20 * ((state->bai >> 7) & 3)) >> halfrate; /* fdcycod */ + fgain = 128 + 128 * (ba->bai & 7); /* fgaincod */ + sdecay = (15 + 2 * (state->bai >> 9)) >> halfrate; /* sdcycod */ + sgain = slowgain[(state->bai >> 5) & 3]; /* sgaincod */ + dbknee = dbpbtab[(state->bai >> 3) & 3]; /* dbpbcod */ + hth = hthtab[state->fscod]; + /* + * if there is no delta bit allocation, make deltba point to an area + * known to contain zeroes. baptab+156 here. + */ + deltba = (ba->deltbae == DELTA_BIT_NONE) ? baptab + 156 : ba->deltba; + floor = floortab[state->bai & 7]; /* floorcod */ + snroffset = 960 - 64 * state->csnroffst - 4 * (ba->bai >> 3) + floor; + floor >>= 5; + + exp = expbap->exp; + bap = expbap->bap; + + i = bndstart; + j = start; + if (start == 0) { /* not the coupling channel */ + int lowcomp; + + lowcomp = 0; + j = end - 1; + do { + if (i < j) { + if (exp[i+1] == exp[i] - 2) + lowcomp = 384; + else if (lowcomp && (exp[i+1] > exp[i])) + lowcomp -= 64; + } + psd = 128 * exp[i]; + mask = psd + fgain + lowcomp; + COMPUTE_MASK (); + bap[i] = (baptab+156)[mask + 4 * exp[i]]; + i++; + } while ((i < 3) || ((i < 7) && (exp[i] > exp[i-1]))); + fastleak = psd + fgain; + slowleak = psd + sgain; + + while (i < 7) { + if (i < j) { + if (exp[i+1] == exp[i] - 2) + lowcomp = 384; + else if (lowcomp && (exp[i+1] > exp[i])) + lowcomp -= 64; + } + psd = 128 * exp[i]; + UPDATE_LEAK (); + mask = ((fastleak + lowcomp < slowleak) ? + fastleak + lowcomp : slowleak); + COMPUTE_MASK (); + bap[i] = (baptab+156)[mask + 4 * exp[i]]; + i++; + } + + if (end == 7) /* lfe channel */ + return; + + do { + if (exp[i+1] == exp[i] - 2) + lowcomp = 320; + else if (lowcomp && (exp[i+1] > exp[i])) + lowcomp -= 64; + psd = 128 * exp[i]; + UPDATE_LEAK (); + mask = ((fastleak + lowcomp < slowleak) ? + fastleak + lowcomp : slowleak); + COMPUTE_MASK (); + bap[i] = (baptab+156)[mask + 4 * exp[i]]; + i++; + } while (i < 20); + + while (lowcomp > 128) { /* two iterations maximum */ + lowcomp -= 128; + psd = 128 * exp[i]; + UPDATE_LEAK (); + mask = ((fastleak + lowcomp < slowleak) ? + fastleak + lowcomp : slowleak); + COMPUTE_MASK (); + bap[i] = (baptab+156)[mask + 4 * exp[i]]; + i++; + } + j = i; + } + + do { + int startband, endband; + + startband = j; + endband = ((bndtab-20)[i] < end) ? (bndtab-20)[i] : end; + psd = 128 * exp[j++]; + while (j < endband) { + int next, delta; + + next = 128 * exp[j++]; + delta = next - psd; + switch (delta >> 9) { + case -6: case -5: case -4: case -3: case -2: + psd = next; + break; + case -1: + psd = next + latab[(-delta) >> 1]; + break; + case 0: + psd += latab[delta >> 1]; + break; + } + } + /* minpsd = -289 */ + UPDATE_LEAK (); + mask = (fastleak < slowleak) ? fastleak : slowleak; + COMPUTE_MASK (); + i++; + j = startband; + do { + /* max(mask+4*exp)=147=-(minpsd+fgain-deltba-snroffset)>>5+4*exp */ + /* min(mask+4*exp)=-156=-(sgain-deltba-snroffset)>>5 */ + bap[j] = (baptab+156)[mask + 4 * exp[j]]; + } while (++j < endband); + } while (j < end); +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/bitstream.c b/plugins/spu2ghz/src/3rdparty/liba52/bitstream.c new file mode 100644 index 0000000000..f1bb17369a --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/bitstream.c @@ -0,0 +1,95 @@ +/* + * bitstream.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 "config.h" + +#include "inttypes.h" + +#include "a52.h" +#include "a52_internal.h" +#include "bitstream.h" + +#define BUFFER_SIZE 4096 + +void a52_bitstream_set_ptr (a52_state_t * state, uint8_t * buf) +{ + int align; + + align = (long)buf & 3; + state->buffer_start = (uint32_t *) (buf - align); + state->bits_left = 0; + bitstream_get (state, align * 8); +} + +static inline void bitstream_fill_current (a52_state_t * state) +{ + uint32_t tmp; + + tmp = *(state->buffer_start++); + state->current_word = swab32 (tmp); +} + +/* + * The fast paths for _get is in the + * bitstream.h header file so it can be inlined. + * + * The "bottom half" of this routine is suffixed _bh + * + * -ah + */ + +uint32_t a52_bitstream_get_bh (a52_state_t * state, uint32_t num_bits) +{ + uint32_t result; + + num_bits -= state->bits_left; + result = ((state->current_word << (32 - state->bits_left)) >> + (32 - state->bits_left)); + + bitstream_fill_current (state); + + if (num_bits != 0) + result = (result << num_bits) | (state->current_word >> (32 - num_bits)); + + state->bits_left = 32 - num_bits; + + return result; +} + +int32_t a52_bitstream_get_bh_2 (a52_state_t * state, uint32_t num_bits) +{ + int32_t result; + + num_bits -= state->bits_left; + result = ((((int32_t)state->current_word) << (32 - state->bits_left)) >> + (32 - state->bits_left)); + + bitstream_fill_current(state); + + if (num_bits != 0) + result = (result << num_bits) | (state->current_word >> (32 - num_bits)); + + state->bits_left = 32 - num_bits; + + return result; +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/bitstream.h b/plugins/spu2ghz/src/3rdparty/liba52/bitstream.h new file mode 100644 index 0000000000..aad3683eed --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/bitstream.h @@ -0,0 +1,77 @@ +/* + * bitstream.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* (stolen from the kernel) */ +#ifdef WORDS_BIGENDIAN + +# define swab32(x) (x) + +#else + +# if 0 && defined (__i386__) + +# define swab32(x) __i386_swab32(x) + static inline const uint32_t __i386_swab32(uint32_t x) + { + __asm__("bswap %0" : "=r" (x) : "0" (x)); + return x; + } + +# else + +# define swab32(x)\ +((((uint8_t*)&x)[0] << 24) | (((uint8_t*)&x)[1] << 16) | \ + (((uint8_t*)&x)[2] << 8) | (((uint8_t*)&x)[3])) + +# endif +#endif + +void a52_bitstream_set_ptr (a52_state_t * state, uint8_t * buf); +uint32_t a52_bitstream_get_bh (a52_state_t * state, uint32_t num_bits); +int32_t a52_bitstream_get_bh_2 (a52_state_t * state, uint32_t num_bits); + +static inline uint32_t bitstream_get (a52_state_t * state, uint32_t num_bits) +{ + uint32_t result; + + if (num_bits < state->bits_left) { + result = (state->current_word << (32 - state->bits_left)) >> (32 - num_bits); + state->bits_left -= num_bits; + return result; + } + + return a52_bitstream_get_bh (state, num_bits); +} + +static inline int32_t bitstream_get_2 (a52_state_t * state, uint32_t num_bits) +{ + int32_t result; + + if (num_bits < state->bits_left) { + result = (((int32_t)state->current_word) << (32 - state->bits_left)) >> (32 - num_bits); + state->bits_left -= num_bits; + return result; + } + + return a52_bitstream_get_bh_2 (state, num_bits); +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/config.h b/plugins/spu2ghz/src/3rdparty/liba52/config.h new file mode 100644 index 0000000000..bf4cf927be --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/config.h @@ -0,0 +1,124 @@ +/* vc++/config.h - manually adapted from include/config.h.in */ + +/* maximum supported data alignment */ +/* #undef ATTRIBUTE_ALIGNED_MAX */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you have the `ftime' function. */ +#define HAVE_FTIME 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +/* #undef HAVE_GETTIMEOFDAY */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_INTTYPES_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_IO_H 1 + +/* Define to 1 if you have the `memalign' function. */ +/* #undef HAVE_MEMALIGN */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STRINGS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_TIME_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UNISTD_H */ + +/* liba52 djbfft support */ +/* #undef LIBA52_DJBFFT */ + +/* a52 sample precision */ +/* #undef LIBA52_DOUBLE */ + +/* libao al support */ +/* #undef LIBAO_AL */ + +/* libao OSS support */ +/* #undef LIBAO_OSS */ + +/* libao solaris support */ +/* #undef LIBAO_SOLARIS */ + +/* libao win support */ +#define LIBAO_WIN + +/* Name of package */ +#define PACKAGE "a52dec" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* The size of a `char', as computed by sizeof. */ +#define SIZEOF_CHAR 1 + +/* The size of a `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of a `short', as computed by sizeof. */ +#define SIZEOF_SHORT 2 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "0.7.4-cvs" + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define as `__inline' if that's what the C compiler calls it, or to nothing + if it is not supported. */ +#define inline __inline + +/* Define as `__restrict' if that's what the C compiler calls it, or to + nothing if it is not supported. */ +#define restrict /*__restrict*/ + +/* Define to `unsigned' if does not define. */ +/* #undef size_t */ diff --git a/plugins/spu2ghz/src/3rdparty/liba52/configure.incl b/plugins/spu2ghz/src/3rdparty/liba52/configure.incl new file mode 100644 index 0000000000..4dbbcea6dc --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/configure.incl @@ -0,0 +1,19 @@ +AC_SUBST([LIBA52_CFLAGS]) +AC_SUBST([LIBA52_LIBS]) + +dnl avoid -fPIC when possible +LIBA52_CFLAGS="$LIBA52_CFLAGS -prefer-non-pic" + +AC_ARG_ENABLE([double], + [ --enable-double use double-precision samples]) +if test x"$enable_double" = x"yes"; then + AC_DEFINE([LIBA52_DOUBLE],,[a52 sample precision]) +fi + +dnl check for djbttf +AC_ARG_ENABLE([djbfft], + [ --enable-djbfft make a version using djbfft]) +if test x"$enable_djbfft" = x"yes"; then + AC_DEFINE([LIBA52_DJBFFT],,[liba52 djbfft support]) + LIBA52_LIBS="$LIBA52_LIBS -ldjbfft" +fi diff --git a/plugins/spu2ghz/src/3rdparty/liba52/downmix.c b/plugins/spu2ghz/src/3rdparty/liba52/downmix.c new file mode 100644 index 0000000000..a5a5c7393b --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/downmix.c @@ -0,0 +1,655 @@ +/* + * downmix.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ +#pragma warning(disable:4244) +#include "config.h" + +#include +#include "inttypes.h" + +#include "a52.h" +#include "a52_internal.h" + +#define CONVERT(acmod,output) (((output) << 3) + (acmod)) + +int a52_downmix_init (int input, int flags, sample_t * level, + sample_t clev, sample_t slev) +{ + static uint8_t table[11][8] = { + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, + A52_STEREO, A52_STEREO, A52_STEREO, A52_STEREO}, + {A52_MONO, A52_MONO, A52_MONO, A52_MONO, + A52_MONO, A52_MONO, A52_MONO, A52_MONO}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, + A52_STEREO, A52_STEREO, A52_STEREO, A52_STEREO}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F, + A52_STEREO, A52_3F, A52_STEREO, A52_3F}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, + A52_2F1R, A52_2F1R, A52_2F1R, A52_2F1R}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO, + A52_2F1R, A52_3F1R, A52_2F1R, A52_3F1R}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F, + A52_2F2R, A52_2F2R, A52_2F2R, A52_2F2R}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F, + A52_2F2R, A52_3F2R, A52_2F2R, A52_3F2R}, + {A52_CHANNEL1, A52_MONO, A52_MONO, A52_MONO, + A52_MONO, A52_MONO, A52_MONO, A52_MONO}, + {A52_CHANNEL2, A52_MONO, A52_MONO, A52_MONO, + A52_MONO, A52_MONO, A52_MONO, A52_MONO}, + {A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_DOLBY, + A52_DOLBY, A52_DOLBY, A52_DOLBY, A52_DOLBY} + }; + int output; + + output = flags & A52_CHANNEL_MASK; + if (output > A52_DOLBY) + return -1; + + output = table[output][input & 7]; + + if ((output == A52_STEREO) && + ((input == A52_DOLBY) || ((input == A52_3F) && (clev == LEVEL_3DB)))) + output = A52_DOLBY; + + if (flags & A52_ADJUST_LEVEL) + switch (CONVERT (input & 7, output)) { + + case CONVERT (A52_3F, A52_MONO): + *level *= LEVEL_3DB / (1 + clev); + break; + + case CONVERT (A52_STEREO, A52_MONO): + case CONVERT (A52_2F2R, A52_2F1R): + case CONVERT (A52_3F2R, A52_3F1R): + level_3db: + *level *= LEVEL_3DB; + break; + + case CONVERT (A52_3F2R, A52_2F1R): + if (clev < LEVEL_PLUS3DB - 1) + goto level_3db; + /* break thru */ + case CONVERT (A52_3F, A52_STEREO): + case CONVERT (A52_3F1R, A52_2F1R): + case CONVERT (A52_3F1R, A52_2F2R): + case CONVERT (A52_3F2R, A52_2F2R): + *level /= 1 + clev; + break; + + case CONVERT (A52_2F1R, A52_MONO): + *level *= LEVEL_PLUS3DB / (2 + slev); + break; + + case CONVERT (A52_2F1R, A52_STEREO): + case CONVERT (A52_3F1R, A52_3F): + *level /= 1 + slev * LEVEL_3DB; + break; + + case CONVERT (A52_3F1R, A52_MONO): + *level *= LEVEL_3DB / (1 + clev + 0.5 * slev); + break; + + case CONVERT (A52_3F1R, A52_STEREO): + *level /= 1 + clev + slev * LEVEL_3DB; + break; + + case CONVERT (A52_2F2R, A52_MONO): + *level *= LEVEL_3DB / (1 + slev); + break; + + case CONVERT (A52_2F2R, A52_STEREO): + case CONVERT (A52_3F2R, A52_3F): + *level /= 1 + slev; + break; + + case CONVERT (A52_3F2R, A52_MONO): + *level *= LEVEL_3DB / (1 + clev + slev); + break; + + case CONVERT (A52_3F2R, A52_STEREO): + *level /= 1 + clev + slev; + break; + + case CONVERT (A52_MONO, A52_DOLBY): + *level *= LEVEL_PLUS3DB; + break; + + case CONVERT (A52_3F, A52_DOLBY): + case CONVERT (A52_2F1R, A52_DOLBY): + *level *= 1 / (1 + LEVEL_3DB); + break; + + case CONVERT (A52_3F1R, A52_DOLBY): + case CONVERT (A52_2F2R, A52_DOLBY): + *level *= 1 / (1 + 2 * LEVEL_3DB); + break; + + case CONVERT (A52_3F2R, A52_DOLBY): + *level *= 1 / (1 + 3 * LEVEL_3DB); + break; + } + + return output; +} + +int a52_downmix_coeff (sample_t * coeff, int acmod, int output, sample_t level, + sample_t clev, sample_t slev) +{ + switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) { + + case CONVERT (A52_CHANNEL, A52_CHANNEL): + case CONVERT (A52_MONO, A52_MONO): + case CONVERT (A52_STEREO, A52_STEREO): + case CONVERT (A52_3F, A52_3F): + case CONVERT (A52_2F1R, A52_2F1R): + case CONVERT (A52_3F1R, A52_3F1R): + case CONVERT (A52_2F2R, A52_2F2R): + case CONVERT (A52_3F2R, A52_3F2R): + case CONVERT (A52_STEREO, A52_DOLBY): + coeff[0] = coeff[1] = coeff[2] = coeff[3] = coeff[4] = level; + return 0; + + case CONVERT (A52_CHANNEL, A52_MONO): + coeff[0] = coeff[1] = level * LEVEL_6DB; + return 3; + + case CONVERT (A52_STEREO, A52_MONO): + coeff[0] = coeff[1] = level * LEVEL_3DB; + return 3; + + case CONVERT (A52_3F, A52_MONO): + coeff[0] = coeff[2] = level * LEVEL_3DB; + coeff[1] = level * clev * LEVEL_PLUS3DB; + return 7; + + case CONVERT (A52_2F1R, A52_MONO): + coeff[0] = coeff[1] = level * LEVEL_3DB; + coeff[2] = level * slev * LEVEL_3DB; + return 7; + + case CONVERT (A52_2F2R, A52_MONO): + coeff[0] = coeff[1] = level * LEVEL_3DB; + coeff[2] = coeff[3] = level * slev * LEVEL_3DB; + return 15; + + case CONVERT (A52_3F1R, A52_MONO): + coeff[0] = coeff[2] = level * LEVEL_3DB; + coeff[1] = level * clev * LEVEL_PLUS3DB; + coeff[3] = level * slev * LEVEL_3DB; + return 15; + + case CONVERT (A52_3F2R, A52_MONO): + coeff[0] = coeff[2] = level * LEVEL_3DB; + coeff[1] = level * clev * LEVEL_PLUS3DB; + coeff[3] = coeff[4] = level * slev * LEVEL_3DB; + return 31; + + case CONVERT (A52_MONO, A52_DOLBY): + coeff[0] = level * LEVEL_3DB; + return 0; + + case CONVERT (A52_3F, A52_DOLBY): + clev = LEVEL_3DB; + case CONVERT (A52_3F, A52_STEREO): + case CONVERT (A52_3F1R, A52_2F1R): + case CONVERT (A52_3F2R, A52_2F2R): + coeff[0] = coeff[2] = coeff[3] = coeff[4] = level; + coeff[1] = level * clev; + return 7; + + case CONVERT (A52_2F1R, A52_DOLBY): + slev = 1; + case CONVERT (A52_2F1R, A52_STEREO): + coeff[0] = coeff[1] = level; + coeff[2] = level * slev * LEVEL_3DB; + return 7; + + case CONVERT (A52_3F1R, A52_DOLBY): + clev = LEVEL_3DB; + slev = 1; + case CONVERT (A52_3F1R, A52_STEREO): + coeff[0] = coeff[2] = level; + coeff[1] = level * clev; + coeff[3] = level * slev * LEVEL_3DB; + return 15; + + case CONVERT (A52_2F2R, A52_DOLBY): + slev = LEVEL_3DB; + case CONVERT (A52_2F2R, A52_STEREO): + coeff[0] = coeff[1] = level; + coeff[2] = coeff[3] = level * slev; + return 15; + + case CONVERT (A52_3F2R, A52_DOLBY): + clev = LEVEL_3DB; + case CONVERT (A52_3F2R, A52_2F1R): + slev = LEVEL_3DB; + case CONVERT (A52_3F2R, A52_STEREO): + coeff[0] = coeff[2] = level; + coeff[1] = level * clev; + coeff[3] = coeff[4] = level * slev; + return 31; + + case CONVERT (A52_3F1R, A52_3F): + coeff[0] = coeff[1] = coeff[2] = level; + coeff[3] = level * slev * LEVEL_3DB; + return 13; + + case CONVERT (A52_3F2R, A52_3F): + coeff[0] = coeff[1] = coeff[2] = level; + coeff[3] = coeff[4] = level * slev; + return 29; + + case CONVERT (A52_2F2R, A52_2F1R): + coeff[0] = coeff[1] = level; + coeff[2] = coeff[3] = level * LEVEL_3DB; + return 12; + + case CONVERT (A52_3F2R, A52_3F1R): + coeff[0] = coeff[1] = coeff[2] = level; + coeff[3] = coeff[4] = level * LEVEL_3DB; + return 24; + + case CONVERT (A52_2F1R, A52_2F2R): + coeff[0] = coeff[1] = level; + coeff[2] = level * LEVEL_3DB; + return 0; + + case CONVERT (A52_3F1R, A52_2F2R): + coeff[0] = coeff[2] = level; + coeff[1] = level * clev; + coeff[3] = level * LEVEL_3DB; + return 7; + + case CONVERT (A52_3F1R, A52_3F2R): + coeff[0] = coeff[1] = coeff[2] = level; + coeff[3] = level * LEVEL_3DB; + return 0; + + case CONVERT (A52_CHANNEL, A52_CHANNEL1): + coeff[0] = level; + coeff[1] = 0; + return 0; + + case CONVERT (A52_CHANNEL, A52_CHANNEL2): + coeff[0] = 0; + coeff[1] = level; + return 0; + } + + return -1; /* NOTREACHED */ +} + +static void mix2to1 (sample_t * dest, sample_t * src, sample_t bias) +{ + int i; + + for (i = 0; i < 256; i++) + dest[i] += src[i] + bias; +} + +static void mix3to1 (sample_t * samples, sample_t bias) +{ + int i; + + for (i = 0; i < 256; i++) + samples[i] += samples[i + 256] + samples[i + 512] + bias; +} + +static void mix4to1 (sample_t * samples, sample_t bias) +{ + int i; + + for (i = 0; i < 256; i++) + samples[i] += (samples[i + 256] + samples[i + 512] + + samples[i + 768] + bias); +} + +static void mix5to1 (sample_t * samples, sample_t bias) +{ + int i; + + for (i = 0; i < 256; i++) + samples[i] += (samples[i + 256] + samples[i + 512] + + samples[i + 768] + samples[i + 1024] + bias); +} + +static void mix3to2 (sample_t * samples, sample_t bias) +{ + int i; + sample_t common; + + for (i = 0; i < 256; i++) { + common = samples[i + 256] + bias; + samples[i] += common; + samples[i + 256] = samples[i + 512] + common; + } +} + +static void mix21to2 (sample_t * left, sample_t * right, sample_t bias) +{ + int i; + sample_t common; + + for (i = 0; i < 256; i++) { + common = right[i + 256] + bias; + left[i] += common; + right[i] += common; + } +} + +static void mix21toS (sample_t * samples, sample_t bias) +{ + int i; + sample_t surround; + + for (i = 0; i < 256; i++) { + surround = samples[i + 512]; + samples[i] += bias - surround; + samples[i + 256] += bias + surround; + } +} + +static void mix31to2 (sample_t * samples, sample_t bias) +{ + int i; + sample_t common; + + for (i = 0; i < 256; i++) { + common = samples[i + 256] + samples[i + 768] + bias; + samples[i] += common; + samples[i + 256] = samples[i + 512] + common; + } +} + +static void mix31toS (sample_t * samples, sample_t bias) +{ + int i; + sample_t common, surround; + + for (i = 0; i < 256; i++) { + common = samples[i + 256] + bias; + surround = samples[i + 768]; + samples[i] += common - surround; + samples[i + 256] = samples[i + 512] + common + surround; + } +} + +static void mix22toS (sample_t * samples, sample_t bias) +{ + int i; + sample_t surround; + + for (i = 0; i < 256; i++) { + surround = samples[i + 512] + samples[i + 768]; + samples[i] += bias - surround; + samples[i + 256] += bias + surround; + } +} + +static void mix32to2 (sample_t * samples, sample_t bias) +{ + int i; + sample_t common; + + for (i = 0; i < 256; i++) { + common = samples[i + 256] + bias; + samples[i] += common + samples[i + 768]; + samples[i + 256] = common + samples[i + 512] + samples[i + 1024]; + } +} + +static void mix32toS (sample_t * samples, sample_t bias) +{ + int i; + sample_t common, surround; + + for (i = 0; i < 256; i++) { + common = samples[i + 256] + bias; + surround = samples[i + 768] + samples[i + 1024]; + samples[i] += common - surround; + samples[i + 256] = samples[i + 512] + common + surround; + } +} + +static void move2to1 (sample_t * src, sample_t * dest, sample_t bias) +{ + int i; + + for (i = 0; i < 256; i++) + dest[i] = src[i] + src[i + 256] + bias; +} + +static void zero (sample_t * samples) +{ + int i; + + for (i = 0; i < 256; i++) + samples[i] = 0; +} + +void a52_downmix (sample_t * samples, int acmod, int output, sample_t bias, + sample_t clev, sample_t slev) +{ + switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) { + + case CONVERT (A52_CHANNEL, A52_CHANNEL2): + memcpy (samples, samples + 256, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_CHANNEL, A52_MONO): + case CONVERT (A52_STEREO, A52_MONO): + mix_2to1: + mix2to1 (samples, samples + 256, bias); + break; + + case CONVERT (A52_2F1R, A52_MONO): + if (slev == 0) + goto mix_2to1; + case CONVERT (A52_3F, A52_MONO): + mix_3to1: + mix3to1 (samples, bias); + break; + + case CONVERT (A52_3F1R, A52_MONO): + if (slev == 0) + goto mix_3to1; + case CONVERT (A52_2F2R, A52_MONO): + if (slev == 0) + goto mix_2to1; + mix4to1 (samples, bias); + break; + + case CONVERT (A52_3F2R, A52_MONO): + if (slev == 0) + goto mix_3to1; + mix5to1 (samples, bias); + break; + + case CONVERT (A52_MONO, A52_DOLBY): + memcpy (samples + 256, samples, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_3F, A52_STEREO): + case CONVERT (A52_3F, A52_DOLBY): + mix_3to2: + mix3to2 (samples, bias); + break; + + case CONVERT (A52_2F1R, A52_STEREO): + if (slev == 0) + break; + mix21to2 (samples, samples + 256, bias); + break; + + case CONVERT (A52_2F1R, A52_DOLBY): + mix21toS (samples, bias); + break; + + case CONVERT (A52_3F1R, A52_STEREO): + if (slev == 0) + goto mix_3to2; + mix31to2 (samples, bias); + break; + + case CONVERT (A52_3F1R, A52_DOLBY): + mix31toS (samples, bias); + break; + + case CONVERT (A52_2F2R, A52_STEREO): + if (slev == 0) + break; + mix2to1 (samples, samples + 512, bias); + mix2to1 (samples + 256, samples + 768, bias); + break; + + case CONVERT (A52_2F2R, A52_DOLBY): + mix22toS (samples, bias); + break; + + case CONVERT (A52_3F2R, A52_STEREO): + if (slev == 0) + goto mix_3to2; + mix32to2 (samples, bias); + break; + + case CONVERT (A52_3F2R, A52_DOLBY): + mix32toS (samples, bias); + break; + + case CONVERT (A52_3F1R, A52_3F): + if (slev == 0) + break; + mix21to2 (samples, samples + 512, bias); + break; + + case CONVERT (A52_3F2R, A52_3F): + if (slev == 0) + break; + mix2to1 (samples, samples + 768, bias); + mix2to1 (samples + 512, samples + 1024, bias); + break; + + case CONVERT (A52_3F1R, A52_2F1R): + mix3to2 (samples, bias); + memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_2F2R, A52_2F1R): + mix2to1 (samples + 512, samples + 768, bias); + break; + + case CONVERT (A52_3F2R, A52_2F1R): + mix3to2 (samples, bias); + move2to1 (samples + 768, samples + 512, bias); + break; + + case CONVERT (A52_3F2R, A52_3F1R): + mix2to1 (samples + 768, samples + 1024, bias); + break; + + case CONVERT (A52_2F1R, A52_2F2R): + memcpy (samples + 768, samples + 512, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_3F1R, A52_2F2R): + mix3to2 (samples, bias); + memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_3F2R, A52_2F2R): + mix3to2 (samples, bias); + memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t)); + memcpy (samples + 768, samples + 1024, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_3F1R, A52_3F2R): + memcpy (samples + 1027, samples + 768, 256 * sizeof (sample_t)); + break; + } +} + +void a52_upmix (sample_t * samples, int acmod, int output) +{ + switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) { + + case CONVERT (A52_CHANNEL, A52_CHANNEL2): + memcpy (samples + 256, samples, 256 * sizeof (sample_t)); + break; + + case CONVERT (A52_3F2R, A52_MONO): + zero (samples + 1024); + case CONVERT (A52_3F1R, A52_MONO): + case CONVERT (A52_2F2R, A52_MONO): + zero (samples + 768); + case CONVERT (A52_3F, A52_MONO): + case CONVERT (A52_2F1R, A52_MONO): + zero (samples + 512); + case CONVERT (A52_CHANNEL, A52_MONO): + case CONVERT (A52_STEREO, A52_MONO): + zero (samples + 256); + break; + + case CONVERT (A52_3F2R, A52_STEREO): + case CONVERT (A52_3F2R, A52_DOLBY): + zero (samples + 1024); + case CONVERT (A52_3F1R, A52_STEREO): + case CONVERT (A52_3F1R, A52_DOLBY): + zero (samples + 768); + case CONVERT (A52_3F, A52_STEREO): + case CONVERT (A52_3F, A52_DOLBY): + mix_3to2: + memcpy (samples + 512, samples + 256, 256 * sizeof (sample_t)); + zero (samples + 256); + break; + + case CONVERT (A52_2F2R, A52_STEREO): + case CONVERT (A52_2F2R, A52_DOLBY): + zero (samples + 768); + case CONVERT (A52_2F1R, A52_STEREO): + case CONVERT (A52_2F1R, A52_DOLBY): + zero (samples + 512); + break; + + case CONVERT (A52_3F2R, A52_3F): + zero (samples + 1024); + case CONVERT (A52_3F1R, A52_3F): + case CONVERT (A52_2F2R, A52_2F1R): + zero (samples + 768); + break; + + case CONVERT (A52_3F2R, A52_3F1R): + zero (samples + 1024); + break; + + case CONVERT (A52_3F2R, A52_2F1R): + zero (samples + 1024); + case CONVERT (A52_3F1R, A52_2F1R): + mix_31to21: + memcpy (samples + 768, samples + 512, 256 * sizeof (sample_t)); + goto mix_3to2; + + case CONVERT (A52_3F2R, A52_2F2R): + memcpy (samples + 1024, samples + 768, 256 * sizeof (sample_t)); + goto mix_31to21; + } +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/imdct.c b/plugins/spu2ghz/src/3rdparty/liba52/imdct.c new file mode 100644 index 0000000000..04eb16f33e --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/imdct.c @@ -0,0 +1,432 @@ +/* + * imdct.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * The ifft algorithms in this file have been largely inspired by Dan + * Bernstein's work, djbfft, available at http://cr.yp.to/djbfft.html + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ +#pragma warning(disable:4244) +#include "config.h" + +#include +#include +#ifdef LIBA52_DJBFFT +#include +#endif +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795029 +#endif +#include "inttypes.h" + +#include "a52.h" +#include "a52_internal.h" +#include "mm_accel.h" + +typedef struct complex_s { + sample_t real; + sample_t imag; +} complex_t; + +static uint8_t fftorder[] = { + 0,128, 64,192, 32,160,224, 96, 16,144, 80,208,240,112, 48,176, + 8,136, 72,200, 40,168,232,104,248,120, 56,184, 24,152,216, 88, + 4,132, 68,196, 36,164,228,100, 20,148, 84,212,244,116, 52,180, + 252,124, 60,188, 28,156,220, 92, 12,140, 76,204,236,108, 44,172, + 2,130, 66,194, 34,162,226, 98, 18,146, 82,210,242,114, 50,178, + 10,138, 74,202, 42,170,234,106,250,122, 58,186, 26,154,218, 90, + 254,126, 62,190, 30,158,222, 94, 14,142, 78,206,238,110, 46,174, + 6,134, 70,198, 38,166,230,102,246,118, 54,182, 22,150,214, 86 +}; + +/* Root values for IFFT */ +static sample_t roots16[3]; +static sample_t roots32[7]; +static sample_t roots64[15]; +static sample_t roots128[31]; + +/* Twiddle factors for IMDCT */ +static complex_t pre1[128]; +static complex_t post1[64]; +static complex_t pre2[64]; +static complex_t post2[32]; + +static sample_t a52_imdct_window[256]; + +static void (* ifft128) (complex_t * buf); +static void (* ifft64) (complex_t * buf); + +static inline void ifft2 (complex_t * buf) +{ + double r, i; + + r = buf[0].real; + i = buf[0].imag; + buf[0].real += buf[1].real; + buf[0].imag += buf[1].imag; + buf[1].real = r - buf[1].real; + buf[1].imag = i - buf[1].imag; +} + +static inline void ifft4 (complex_t * buf) +{ + double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; + + tmp1 = buf[0].real + buf[1].real; + tmp2 = buf[3].real + buf[2].real; + tmp3 = buf[0].imag + buf[1].imag; + tmp4 = buf[2].imag + buf[3].imag; + tmp5 = buf[0].real - buf[1].real; + tmp6 = buf[0].imag - buf[1].imag; + tmp7 = buf[2].imag - buf[3].imag; + tmp8 = buf[3].real - buf[2].real; + + buf[0].real = tmp1 + tmp2; + buf[0].imag = tmp3 + tmp4; + buf[2].real = tmp1 - tmp2; + buf[2].imag = tmp3 - tmp4; + buf[1].real = tmp5 + tmp7; + buf[1].imag = tmp6 + tmp8; + buf[3].real = tmp5 - tmp7; + buf[3].imag = tmp6 - tmp8; +} + +/* the basic split-radix ifft butterfly */ + +#define BUTTERFLY(a0,a1,a2,a3,wr,wi) do { \ + tmp5 = a2.real * wr + a2.imag * wi; \ + tmp6 = a2.imag * wr - a2.real * wi; \ + tmp7 = a3.real * wr - a3.imag * wi; \ + tmp8 = a3.imag * wr + a3.real * wi; \ + tmp1 = tmp5 + tmp7; \ + tmp2 = tmp6 + tmp8; \ + tmp3 = tmp6 - tmp8; \ + tmp4 = tmp7 - tmp5; \ + a2.real = a0.real - tmp1; \ + a2.imag = a0.imag - tmp2; \ + a3.real = a1.real - tmp3; \ + a3.imag = a1.imag - tmp4; \ + a0.real += tmp1; \ + a0.imag += tmp2; \ + a1.real += tmp3; \ + a1.imag += tmp4; \ +} while (0) + +/* split-radix ifft butterfly, specialized for wr=1 wi=0 */ + +#define BUTTERFLY_ZERO(a0,a1,a2,a3) do { \ + tmp1 = a2.real + a3.real; \ + tmp2 = a2.imag + a3.imag; \ + tmp3 = a2.imag - a3.imag; \ + tmp4 = a3.real - a2.real; \ + a2.real = a0.real - tmp1; \ + a2.imag = a0.imag - tmp2; \ + a3.real = a1.real - tmp3; \ + a3.imag = a1.imag - tmp4; \ + a0.real += tmp1; \ + a0.imag += tmp2; \ + a1.real += tmp3; \ + a1.imag += tmp4; \ +} while (0) + +/* split-radix ifft butterfly, specialized for wr=wi */ + +#define BUTTERFLY_HALF(a0,a1,a2,a3,w) do { \ + tmp5 = (a2.real + a2.imag) * w; \ + tmp6 = (a2.imag - a2.real) * w; \ + tmp7 = (a3.real - a3.imag) * w; \ + tmp8 = (a3.imag + a3.real) * w; \ + tmp1 = tmp5 + tmp7; \ + tmp2 = tmp6 + tmp8; \ + tmp3 = tmp6 - tmp8; \ + tmp4 = tmp7 - tmp5; \ + a2.real = a0.real - tmp1; \ + a2.imag = a0.imag - tmp2; \ + a3.real = a1.real - tmp3; \ + a3.imag = a1.imag - tmp4; \ + a0.real += tmp1; \ + a0.imag += tmp2; \ + a1.real += tmp3; \ + a1.imag += tmp4; \ +} while (0) + +static inline void ifft8 (complex_t * buf) +{ + double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; + + ifft4 (buf); + ifft2 (buf + 4); + ifft2 (buf + 6); + BUTTERFLY_ZERO (buf[0], buf[2], buf[4], buf[6]); + BUTTERFLY_HALF (buf[1], buf[3], buf[5], buf[7], roots16[1]); +} + +static void ifft_pass (complex_t * buf, sample_t * weight, int n) +{ + complex_t * buf1; + complex_t * buf2; + complex_t * buf3; + double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; + int i; + + buf++; + buf1 = buf + n; + buf2 = buf + 2 * n; + buf3 = buf + 3 * n; + + BUTTERFLY_ZERO (buf[-1], buf1[-1], buf2[-1], buf3[-1]); + + i = n - 1; + + do { + BUTTERFLY (buf[0], buf1[0], buf2[0], buf3[0], weight[n], weight[2*i]); + buf++; + buf1++; + buf2++; + buf3++; + weight++; + } while (--i); +} + +static void ifft16 (complex_t * buf) +{ + ifft8 (buf); + ifft4 (buf + 8); + ifft4 (buf + 12); + ifft_pass (buf, roots16 - 4, 4); +} + +static void ifft32 (complex_t * buf) +{ + ifft16 (buf); + ifft8 (buf + 16); + ifft8 (buf + 24); + ifft_pass (buf, roots32 - 8, 8); +} + +static void ifft64_c (complex_t * buf) +{ + ifft32 (buf); + ifft16 (buf + 32); + ifft16 (buf + 48); + ifft_pass (buf, roots64 - 16, 16); +} + +static void ifft128_c (complex_t * buf) +{ + ifft32 (buf); + ifft16 (buf + 32); + ifft16 (buf + 48); + ifft_pass (buf, roots64 - 16, 16); + + ifft32 (buf + 64); + ifft32 (buf + 96); + ifft_pass (buf, roots128 - 32, 32); +} + +void a52_imdct_512 (sample_t * data, sample_t * delay, sample_t bias) +{ + int i, k; + sample_t t_r, t_i, a_r, a_i, b_r, b_i, w_1, w_2; + const sample_t * window = a52_imdct_window; + complex_t buf[128]; + + for (i = 0; i < 128; i++) { + k = fftorder[i]; + t_r = pre1[i].real; + t_i = pre1[i].imag; + + buf[i].real = t_i * data[255-k] + t_r * data[k]; + buf[i].imag = t_r * data[255-k] - t_i * data[k]; + } + + ifft128 (buf); + + /* Post IFFT complex multiply plus IFFT complex conjugate*/ + /* Window and convert to real valued signal */ + for (i = 0; i < 64; i++) { + /* y[n] = z[n] * (xcos1[n] + j * xsin1[n]) ; */ + t_r = post1[i].real; + t_i = post1[i].imag; + + a_r = t_r * buf[i].real + t_i * buf[i].imag; + a_i = t_i * buf[i].real - t_r * buf[i].imag; + b_r = t_i * buf[127-i].real + t_r * buf[127-i].imag; + b_i = t_r * buf[127-i].real - t_i * buf[127-i].imag; + + w_1 = window[2*i]; + w_2 = window[255-2*i]; + data[2*i] = delay[2*i] * w_2 - a_r * w_1 + bias; + data[255-2*i] = delay[2*i] * w_1 + a_r * w_2 + bias; + delay[2*i] = a_i; + + w_1 = window[2*i+1]; + w_2 = window[254-2*i]; + data[2*i+1] = delay[2*i+1] * w_2 + b_r * w_1 + bias; + data[254-2*i] = delay[2*i+1] * w_1 - b_r * w_2 + bias; + delay[2*i+1] = b_i; + } +} + +void a52_imdct_256(sample_t * data, sample_t * delay, sample_t bias) +{ + int i, k; + sample_t t_r, t_i, a_r, a_i, b_r, b_i, c_r, c_i, d_r, d_i, w_1, w_2; + const sample_t * window = a52_imdct_window; + complex_t buf1[64], buf2[64]; + + /* Pre IFFT complex multiply plus IFFT cmplx conjugate */ + for (i = 0; i < 64; i++) { + k = fftorder[i]; + t_r = pre2[i].real; + t_i = pre2[i].imag; + + buf1[i].real = t_i * data[254-k] + t_r * data[k]; + buf1[i].imag = t_r * data[254-k] - t_i * data[k]; + + buf2[i].real = t_i * data[255-k] + t_r * data[k+1]; + buf2[i].imag = t_r * data[255-k] - t_i * data[k+1]; + } + + ifft64 (buf1); + ifft64 (buf2); + + /* Post IFFT complex multiply */ + /* Window and convert to real valued signal */ + for (i = 0; i < 32; i++) { + /* y1[n] = z1[n] * (xcos2[n] + j * xs in2[n]) ; */ + t_r = post2[i].real; + t_i = post2[i].imag; + + a_r = t_r * buf1[i].real + t_i * buf1[i].imag; + a_i = t_i * buf1[i].real - t_r * buf1[i].imag; + b_r = t_i * buf1[63-i].real + t_r * buf1[63-i].imag; + b_i = t_r * buf1[63-i].real - t_i * buf1[63-i].imag; + + c_r = t_r * buf2[i].real + t_i * buf2[i].imag; + c_i = t_i * buf2[i].real - t_r * buf2[i].imag; + d_r = t_i * buf2[63-i].real + t_r * buf2[63-i].imag; + d_i = t_r * buf2[63-i].real - t_i * buf2[63-i].imag; + + w_1 = window[2*i]; + w_2 = window[255-2*i]; + data[2*i] = delay[2*i] * w_2 - a_r * w_1 + bias; + data[255-2*i] = delay[2*i] * w_1 + a_r * w_2 + bias; + delay[2*i] = c_i; + + w_1 = window[128+2*i]; + w_2 = window[127-2*i]; + data[128+2*i] = delay[127-2*i] * w_2 + a_i * w_1 + bias; + data[127-2*i] = delay[127-2*i] * w_1 - a_i * w_2 + bias; + delay[127-2*i] = c_r; + + w_1 = window[2*i+1]; + w_2 = window[254-2*i]; + data[2*i+1] = delay[2*i+1] * w_2 - b_i * w_1 + bias; + data[254-2*i] = delay[2*i+1] * w_1 + b_i * w_2 + bias; + delay[2*i+1] = d_r; + + w_1 = window[129+2*i]; + w_2 = window[126-2*i]; + data[129+2*i] = delay[126-2*i] * w_2 + b_r * w_1 + bias; + data[126-2*i] = delay[126-2*i] * w_1 - b_r * w_2 + bias; + delay[126-2*i] = d_i; + } +} + +static double besselI0 (double x) +{ + double bessel = 1; + int i = 100; + + do + bessel = bessel * x / (i * i) + 1; + while (--i); + return bessel; +} + +void a52_imdct_init (uint32_t mm_accel) +{ + int i, k; + double sum; + + /* compute imdct window - kaiser-bessel derived window, alpha = 5.0 */ + sum = 0; + for (i = 0; i < 256; i++) { + sum += besselI0 (i * (256 - i) * (5 * M_PI / 256) * (5 * M_PI / 256)); + a52_imdct_window[i] = sum; + } + sum++; + for (i = 0; i < 256; i++) + a52_imdct_window[i] = sqrt (a52_imdct_window[i] / sum); + + for (i = 0; i < 3; i++) + roots16[i] = cos ((M_PI / 8) * (i + 1)); + + for (i = 0; i < 7; i++) + roots32[i] = cos ((M_PI / 16) * (i + 1)); + + for (i = 0; i < 15; i++) + roots64[i] = cos ((M_PI / 32) * (i + 1)); + + for (i = 0; i < 31; i++) + roots128[i] = cos ((M_PI / 64) * (i + 1)); + + for (i = 0; i < 64; i++) { + k = fftorder[i] / 2 + 64; + pre1[i].real = cos ((M_PI / 256) * (k - 0.25)); + pre1[i].imag = sin ((M_PI / 256) * (k - 0.25)); + } + + for (i = 64; i < 128; i++) { + k = fftorder[i] / 2 + 64; + pre1[i].real = -cos ((M_PI / 256) * (k - 0.25)); + pre1[i].imag = -sin ((M_PI / 256) * (k - 0.25)); + } + + for (i = 0; i < 64; i++) { + post1[i].real = cos ((M_PI / 256) * (i + 0.5)); + post1[i].imag = sin ((M_PI / 256) * (i + 0.5)); + } + + for (i = 0; i < 64; i++) { + k = fftorder[i] / 4; + pre2[i].real = cos ((M_PI / 128) * (k - 0.25)); + pre2[i].imag = sin ((M_PI / 128) * (k - 0.25)); + } + + for (i = 0; i < 32; i++) { + post2[i].real = cos ((M_PI / 128) * (i + 0.5)); + post2[i].imag = sin ((M_PI / 128) * (i + 0.5)); + } + +#ifdef LIBA52_DJBFFT + if (mm_accel & MM_ACCEL_DJBFFT) { + fprintf (stderr, "Using djbfft for IMDCT transform\n"); + ifft128 = (void (*) (complex_t *)) fftc4_un128; + ifft64 = (void (*) (complex_t *)) fftc4_un64; + } else +#endif + { + fprintf (stderr, "No accelerated IMDCT transform found\n"); + ifft128 = ifft128_c; + ifft64 = ifft64_c; + } +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/inttypes.h b/plugins/spu2ghz/src/3rdparty/liba52/inttypes.h new file mode 100644 index 0000000000..a0842e3391 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/inttypes.h @@ -0,0 +1,13 @@ +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +#ifdef ARCH_X86 +typedef signed long long int64_t; +#endif + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifdef ARCH_X86 +typedef unsigned long long uint64_t; +#endif diff --git a/plugins/spu2ghz/src/3rdparty/liba52/mm_accel.h b/plugins/spu2ghz/src/3rdparty/liba52/mm_accel.h new file mode 100644 index 0000000000..e6236fb4ea --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/mm_accel.h @@ -0,0 +1,37 @@ +/* + * mm_accel.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 MM_ACCEL_H +#define MM_ACCEL_H + +/* generic accelerations */ +#define MM_ACCEL_DJBFFT 0x00000001 + +/* x86 accelerations */ +#define MM_ACCEL_X86_MMX 0x80000000 +#define MM_ACCEL_X86_3DNOW 0x40000000 +#define MM_ACCEL_X86_MMXEXT 0x20000000 + +uint32_t mm_accel (void); + +#endif /* MM_ACCEL_H */ diff --git a/plugins/spu2ghz/src/3rdparty/liba52/parse.c b/plugins/spu2ghz/src/3rdparty/liba52/parse.c new file mode 100644 index 0000000000..960e5c52c9 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/parse.c @@ -0,0 +1,903 @@ +/* + * parse.c + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ +#pragma warning(disable:4305) +#pragma warning(disable:4244) + +#include "config.h" + +#include +#include +#include "inttypes.h" + +#include "a52.h" +#include "a52_internal.h" +#include "bitstream.h" +#include "tables.h" + +#ifdef HAVE_MEMALIGN +/* some systems have memalign() but no declaration for it */ +void * memalign (size_t align, size_t size); +#else +/* assume malloc alignment is sufficient */ +#define memalign(align,size) malloc (size) +#endif + +typedef struct { + sample_t q1[2]; + sample_t q2[2]; + sample_t q4; + int q1_ptr; + int q2_ptr; + int q4_ptr; +} quantizer_t; + +static uint8_t halfrate[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3}; + +a52_state_t * a52_init (uint32_t mm_accel) +{ + a52_state_t * state; + int i; + + state = malloc (sizeof (a52_state_t)); + if (state == NULL) + return NULL; + + state->samples = memalign (16, 256 * 12 * sizeof (sample_t)); + if (state->samples == NULL) { + free (state); + return NULL; + } + + for (i = 0; i < 256 * 12; i++) + state->samples[i] = 0; + + state->downmixed = 1; + + state->lfsr_state = 1; + + a52_imdct_init (mm_accel); + + return state; +} + +sample_t * a52_samples (a52_state_t * state) +{ + return state->samples; +} + +int a52_syncinfo (uint8_t * buf, int * flags, + int * sample_rate, int * bit_rate) +{ + static int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112, + 128, 160, 192, 224, 256, 320, 384, 448, + 512, 576, 640}; + static uint8_t lfeon[8] = {0x10, 0x10, 0x04, 0x04, 0x04, 0x01, 0x04, 0x01}; + int frmsizecod; + int bitrate; + int half; + int acmod; + + if ((buf[0] != 0x0b) || (buf[1] != 0x77)) /* syncword */ + return 0; + + if (buf[5] >= 0x60) /* bsid >= 12 */ + return 0; + half = halfrate[buf[5] >> 3]; + + /* acmod, dsurmod and lfeon */ + acmod = buf[6] >> 5; + *flags = ((((buf[6] & 0xf8) == 0x50) ? A52_DOLBY : acmod) | + ((buf[6] & lfeon[acmod]) ? A52_LFE : 0)); + + frmsizecod = buf[4] & 63; + if (frmsizecod >= 38) + return 0; + bitrate = rate [frmsizecod >> 1]; + *bit_rate = (bitrate * 1000) >> half; + + switch (buf[4] & 0xc0) { + case 0: + *sample_rate = 48000 >> half; + return 4 * bitrate; + case 0x40: + *sample_rate = 44100 >> half; + return 2 * (320 * bitrate / 147 + (frmsizecod & 1)); + case 0x80: + *sample_rate = 32000 >> half; + return 6 * bitrate; + default: + return 0; + } +} + +int a52_frame (a52_state_t * state, uint8_t * buf, int * flags, + sample_t * level, sample_t bias) +{ + static sample_t clev[4] = {LEVEL_3DB, LEVEL_45DB, LEVEL_6DB, LEVEL_45DB}; + static sample_t slev[4] = {LEVEL_3DB, LEVEL_6DB, 0, LEVEL_6DB}; + int chaninfo; + int acmod; + + state->fscod = buf[4] >> 6; + state->halfrate = halfrate[buf[5] >> 3]; + state->acmod = acmod = buf[6] >> 5; + + a52_bitstream_set_ptr (state, buf + 6); + bitstream_get (state, 3); /* skip acmod we already parsed */ + + if ((acmod == 2) && (bitstream_get (state, 2) == 2)) /* dsurmod */ + acmod = A52_DOLBY; + + if ((acmod & 1) && (acmod != 1)) + state->clev = clev[bitstream_get (state, 2)]; /* cmixlev */ + + if (acmod & 4) + state->slev = slev[bitstream_get (state, 2)]; /* surmixlev */ + + state->lfeon = bitstream_get (state, 1); + + state->output = a52_downmix_init (acmod, *flags, level, + state->clev, state->slev); + if (state->output < 0) + return 1; + if (state->lfeon && (*flags & A52_LFE)) + state->output |= A52_LFE; + *flags = state->output; + /* the 2* compensates for differences in imdct */ + state->dynrng = state->level = 2 * *level; + state->bias = bias; + state->dynrnge = 1; + state->dynrngcall = NULL; + state->cplba.deltbae = DELTA_BIT_NONE; + state->ba[0].deltbae = state->ba[1].deltbae = state->ba[2].deltbae = + state->ba[3].deltbae = state->ba[4].deltbae = DELTA_BIT_NONE; + + chaninfo = !acmod; + do { + bitstream_get (state, 5); /* dialnorm */ + if (bitstream_get (state, 1)) /* compre */ + bitstream_get (state, 8); /* compr */ + if (bitstream_get (state, 1)) /* langcode */ + bitstream_get (state, 8); /* langcod */ + if (bitstream_get (state, 1)) /* audprodie */ + bitstream_get (state, 7); /* mixlevel + roomtyp */ + } while (chaninfo--); + + bitstream_get (state, 2); /* copyrightb + origbs */ + + if (bitstream_get (state, 1)) /* timecod1e */ + bitstream_get (state, 14); /* timecod1 */ + if (bitstream_get (state, 1)) /* timecod2e */ + bitstream_get (state, 14); /* timecod2 */ + + if (bitstream_get (state, 1)) { /* addbsie */ + int addbsil; + + addbsil = bitstream_get (state, 6); + do { + bitstream_get (state, 8); /* addbsi */ + } while (addbsil--); + } + + return 0; +} + +void a52_dynrng (a52_state_t * state, + sample_t (* call) (sample_t, void *), void * data) +{ + state->dynrnge = 0; + if (call) { + state->dynrnge = 1; + state->dynrngcall = call; + state->dynrngdata = data; + } +} + +static int parse_exponents (a52_state_t * state, int expstr, int ngrps, + uint8_t exponent, uint8_t * dest) +{ + int exps; + + while (ngrps--) { + exps = bitstream_get (state, 7); + + exponent += exp_1[exps]; + if (exponent > 24) + return 1; + + switch (expstr) { + case EXP_D45: + *(dest++) = exponent; + *(dest++) = exponent; + case EXP_D25: + *(dest++) = exponent; + case EXP_D15: + *(dest++) = exponent; + } + + exponent += exp_2[exps]; + if (exponent > 24) + return 1; + + switch (expstr) { + case EXP_D45: + *(dest++) = exponent; + *(dest++) = exponent; + case EXP_D25: + *(dest++) = exponent; + case EXP_D15: + *(dest++) = exponent; + } + + exponent += exp_3[exps]; + if (exponent > 24) + return 1; + + switch (expstr) { + case EXP_D45: + *(dest++) = exponent; + *(dest++) = exponent; + case EXP_D25: + *(dest++) = exponent; + case EXP_D15: + *(dest++) = exponent; + } + } + + return 0; +} + +static int parse_deltba (a52_state_t * state, int8_t * deltba) +{ + int deltnseg, deltlen, delta, j; + + memset (deltba, 0, 50); + + deltnseg = bitstream_get (state, 3); + j = 0; + do { + j += bitstream_get (state, 5); + deltlen = bitstream_get (state, 4); + delta = bitstream_get (state, 3); + delta -= (delta >= 4) ? 3 : 4; + if (!deltlen) + continue; + if (j + deltlen >= 50) + return 1; + while (deltlen--) + deltba[j++] = delta; + } while (deltnseg--); + + return 0; +} + +static inline int zero_snr_offsets (int nfchans, a52_state_t * state) +{ + int i; + + if ((state->csnroffst) || + (state->chincpl && state->cplba.bai >> 3) || /* cplinu, fsnroffst */ + (state->lfeon && state->lfeba.bai >> 3)) /* fsnroffst */ + return 0; + for (i = 0; i < nfchans; i++) + if (state->ba[i].bai >> 3) /* fsnroffst */ + return 0; + return 1; +} + +static inline int16_t dither_gen (a52_state_t * state) +{ + int16_t nstate; + + nstate = dither_lut[state->lfsr_state >> 8] ^ (state->lfsr_state << 8); + + state->lfsr_state = (uint16_t) nstate; + + return nstate; +} + +static void coeff_get (a52_state_t * state, sample_t * coeff, + expbap_t * expbap, quantizer_t * quantizer, + sample_t level, int dither, int end) +{ + int i; + uint8_t * exp; + int8_t * bap; + sample_t factor[25]; + + for (i = 0; i <= 24; i++) + factor[i] = scale_factor[i] * level; + + exp = expbap->exp; + bap = expbap->bap; + + for (i = 0; i < end; i++) { + int bapi; + + bapi = bap[i]; + switch (bapi) { + case 0: + if (dither) { + coeff[i] = dither_gen (state) * LEVEL_3DB * factor[exp[i]]; + continue; + } else { + coeff[i] = 0; + continue; + } + + case -1: + if (quantizer->q1_ptr >= 0) { + coeff[i] = quantizer->q1[quantizer->q1_ptr--] * factor[exp[i]]; + continue; + } else { + int code; + + code = bitstream_get (state, 5); + + quantizer->q1_ptr = 1; + quantizer->q1[0] = q_1_2[code]; + quantizer->q1[1] = q_1_1[code]; + coeff[i] = q_1_0[code] * factor[exp[i]]; + continue; + } + + case -2: + if (quantizer->q2_ptr >= 0) { + coeff[i] = quantizer->q2[quantizer->q2_ptr--] * factor[exp[i]]; + continue; + } else { + int code; + + code = bitstream_get (state, 7); + + quantizer->q2_ptr = 1; + quantizer->q2[0] = q_2_2[code]; + quantizer->q2[1] = q_2_1[code]; + coeff[i] = q_2_0[code] * factor[exp[i]]; + continue; + } + + case 3: + coeff[i] = q_3[bitstream_get (state, 3)] * factor[exp[i]]; + continue; + + case -3: + if (quantizer->q4_ptr == 0) { + quantizer->q4_ptr = -1; + coeff[i] = quantizer->q4 * factor[exp[i]]; + continue; + } else { + int code; + + code = bitstream_get (state, 7); + + quantizer->q4_ptr = 0; + quantizer->q4 = q_4_1[code]; + coeff[i] = q_4_0[code] * factor[exp[i]]; + continue; + } + + case 4: + coeff[i] = q_5[bitstream_get (state, 4)] * factor[exp[i]]; + continue; + + default: + coeff[i] = ((bitstream_get_2 (state, bapi) << (16 - bapi)) * + factor[exp[i]]); + } + } +} + +static void coeff_get_coupling (a52_state_t * state, int nfchans, + sample_t * coeff, sample_t (* samples)[256], + quantizer_t * quantizer, uint8_t dithflag[5]) +{ + int cplbndstrc, bnd, i, i_end, ch; + uint8_t * exp; + int8_t * bap; + sample_t cplco[5]; + + exp = state->cpl_expbap.exp; + bap = state->cpl_expbap.bap; + bnd = 0; + cplbndstrc = state->cplbndstrc; + i = state->cplstrtmant; + while (i < state->cplendmant) { + i_end = i + 12; + while (cplbndstrc & 1) { + cplbndstrc >>= 1; + i_end += 12; + } + cplbndstrc >>= 1; + for (ch = 0; ch < nfchans; ch++) + cplco[ch] = state->cplco[ch][bnd] * coeff[ch]; + bnd++; + + while (i < i_end) { + sample_t cplcoeff; + int bapi; + + bapi = bap[i]; + switch (bapi) { + case 0: + cplcoeff = LEVEL_3DB * scale_factor[exp[i]]; + for (ch = 0; ch < nfchans; ch++) + if ((state->chincpl >> ch) & 1) { + if (dithflag[ch]) + samples[ch][i] = (cplcoeff * cplco[ch] * + dither_gen (state)); + else + samples[ch][i] = 0; + } + i++; + continue; + + case -1: + if (quantizer->q1_ptr >= 0) { + cplcoeff = quantizer->q1[quantizer->q1_ptr--]; + break; + } else { + int code; + + code = bitstream_get (state, 5); + + quantizer->q1_ptr = 1; + quantizer->q1[0] = q_1_2[code]; + quantizer->q1[1] = q_1_1[code]; + cplcoeff = q_1_0[code]; + break; + } + + case -2: + if (quantizer->q2_ptr >= 0) { + cplcoeff = quantizer->q2[quantizer->q2_ptr--]; + break; + } else { + int code; + + code = bitstream_get (state, 7); + + quantizer->q2_ptr = 1; + quantizer->q2[0] = q_2_2[code]; + quantizer->q2[1] = q_2_1[code]; + cplcoeff = q_2_0[code]; + break; + } + + case 3: + cplcoeff = q_3[bitstream_get (state, 3)]; + break; + + case -3: + if (quantizer->q4_ptr == 0) { + quantizer->q4_ptr = -1; + cplcoeff = quantizer->q4; + break; + } else { + int code; + + code = bitstream_get (state, 7); + + quantizer->q4_ptr = 0; + quantizer->q4 = q_4_1[code]; + cplcoeff = q_4_0[code]; + break; + } + + case 4: + cplcoeff = q_5[bitstream_get (state, 4)]; + break; + + default: + cplcoeff = bitstream_get_2 (state, bapi) << (16 - bapi); + } + + cplcoeff *= scale_factor[exp[i]]; + for (ch = 0; ch < nfchans; ch++) + if ((state->chincpl >> ch) & 1) + samples[ch][i] = cplcoeff * cplco[ch]; + i++; + } + } +} + +int a52_block (a52_state_t * state) +{ + static const uint8_t nfchans_tbl[] = {2, 1, 2, 3, 3, 4, 4, 5, 1, 1, 2}; + static int rematrix_band[4] = {25, 37, 61, 253}; + int i, nfchans, chaninfo; + uint8_t cplexpstr, chexpstr[5], lfeexpstr, do_bit_alloc, done_cpl; + uint8_t blksw[5], dithflag[5]; + sample_t coeff[5]; + int chanbias; + quantizer_t quantizer; + sample_t * samples; + + nfchans = nfchans_tbl[state->acmod]; + + for (i = 0; i < nfchans; i++) + blksw[i] = bitstream_get (state, 1); + + for (i = 0; i < nfchans; i++) + dithflag[i] = bitstream_get (state, 1); + + chaninfo = !state->acmod; + do { + if (bitstream_get (state, 1)) { /* dynrnge */ + int dynrng; + + dynrng = bitstream_get_2 (state, 8); + if (state->dynrnge) { + sample_t range; + + range = ((((dynrng & 0x1f) | 0x20) << 13) * + scale_factor[3 - (dynrng >> 5)]); + if (state->dynrngcall) + range = state->dynrngcall (range, state->dynrngdata); + state->dynrng = state->level * range; + } + } + } while (chaninfo--); + + if (bitstream_get (state, 1)) { /* cplstre */ + state->chincpl = 0; + if (bitstream_get (state, 1)) { /* cplinu */ + static uint8_t bndtab[16] = {31, 35, 37, 39, 41, 42, 43, 44, + 45, 45, 46, 46, 47, 47, 48, 48}; + int cplbegf; + int cplendf; + int ncplsubnd; + + for (i = 0; i < nfchans; i++) + state->chincpl |= bitstream_get (state, 1) << i; + switch (state->acmod) { + case 0: case 1: + return 1; + case 2: + state->phsflginu = bitstream_get (state, 1); + } + cplbegf = bitstream_get (state, 4); + cplendf = bitstream_get (state, 4); + + if (cplendf + 3 - cplbegf < 0) + return 1; + state->ncplbnd = ncplsubnd = cplendf + 3 - cplbegf; + state->cplstrtbnd = bndtab[cplbegf]; + state->cplstrtmant = cplbegf * 12 + 37; + state->cplendmant = cplendf * 12 + 73; + + state->cplbndstrc = 0; + for (i = 0; i < ncplsubnd - 1; i++) + if (bitstream_get (state, 1)) { + state->cplbndstrc |= 1 << i; + state->ncplbnd--; + } + } + } + + if (state->chincpl) { /* cplinu */ + int j, cplcoe; + + cplcoe = 0; + for (i = 0; i < nfchans; i++) + if ((state->chincpl) >> i & 1) + if (bitstream_get (state, 1)) { /* cplcoe */ + int mstrcplco, cplcoexp, cplcomant; + + cplcoe = 1; + mstrcplco = 3 * bitstream_get (state, 2); + for (j = 0; j < state->ncplbnd; j++) { + cplcoexp = bitstream_get (state, 4); + cplcomant = bitstream_get (state, 4); + if (cplcoexp == 15) + cplcomant <<= 14; + else + cplcomant = (cplcomant | 0x10) << 13; + state->cplco[i][j] = + cplcomant * scale_factor[cplcoexp + mstrcplco]; + } + } + if ((state->acmod == 2) && state->phsflginu && cplcoe) + for (j = 0; j < state->ncplbnd; j++) + if (bitstream_get (state, 1)) /* phsflg */ + state->cplco[1][j] = -state->cplco[1][j]; + } + + if ((state->acmod == 2) && (bitstream_get (state, 1))) { /* rematstr */ + int end; + + state->rematflg = 0; + end = (state->chincpl) ? state->cplstrtmant : 253; /* cplinu */ + i = 0; + do + state->rematflg |= bitstream_get (state, 1) << i; + while (rematrix_band[i++] < end); + } + + cplexpstr = EXP_REUSE; + lfeexpstr = EXP_REUSE; + if (state->chincpl) /* cplinu */ + cplexpstr = bitstream_get (state, 2); + for (i = 0; i < nfchans; i++) + chexpstr[i] = bitstream_get (state, 2); + if (state->lfeon) + lfeexpstr = bitstream_get (state, 1); + + for (i = 0; i < nfchans; i++) + if (chexpstr[i] != EXP_REUSE) { + if ((state->chincpl >> i) & 1) + state->endmant[i] = state->cplstrtmant; + else { + int chbwcod; + + chbwcod = bitstream_get (state, 6); + if (chbwcod > 60) + return 1; + state->endmant[i] = chbwcod * 3 + 73; + } + } + + do_bit_alloc = 0; + + if (cplexpstr != EXP_REUSE) { + int cplabsexp, ncplgrps; + + do_bit_alloc = 64; + ncplgrps = ((state->cplendmant - state->cplstrtmant) / + (3 << (cplexpstr - 1))); + cplabsexp = bitstream_get (state, 4) << 1; + if (parse_exponents (state, cplexpstr, ncplgrps, cplabsexp, + state->cpl_expbap.exp + state->cplstrtmant)) + return 1; + } + for (i = 0; i < nfchans; i++) + if (chexpstr[i] != EXP_REUSE) { + int grp_size, nchgrps; + + do_bit_alloc |= 1 << i; + grp_size = 3 << (chexpstr[i] - 1); + nchgrps = (state->endmant[i] + grp_size - 4) / grp_size; + state->fbw_expbap[i].exp[0] = bitstream_get (state, 4); + if (parse_exponents (state, chexpstr[i], nchgrps, + state->fbw_expbap[i].exp[0], + state->fbw_expbap[i].exp + 1)) + return 1; + bitstream_get (state, 2); /* gainrng */ + } + if (lfeexpstr != EXP_REUSE) { + do_bit_alloc |= 32; + state->lfe_expbap.exp[0] = bitstream_get (state, 4); + if (parse_exponents (state, lfeexpstr, 2, state->lfe_expbap.exp[0], + state->lfe_expbap.exp + 1)) + return 1; + } + + if (bitstream_get (state, 1)) { /* baie */ + do_bit_alloc = -1; + state->bai = bitstream_get (state, 11); + } + if (bitstream_get (state, 1)) { /* snroffste */ + do_bit_alloc = -1; + state->csnroffst = bitstream_get (state, 6); + if (state->chincpl) /* cplinu */ + state->cplba.bai = bitstream_get (state, 7); + for (i = 0; i < nfchans; i++) + state->ba[i].bai = bitstream_get (state, 7); + if (state->lfeon) + state->lfeba.bai = bitstream_get (state, 7); + } + if ((state->chincpl) && (bitstream_get (state, 1))) { /* cplleake */ + do_bit_alloc |= 64; + state->cplfleak = 9 - bitstream_get (state, 3); + state->cplsleak = 9 - bitstream_get (state, 3); + } + + if (bitstream_get (state, 1)) { /* deltbaie */ + do_bit_alloc = -1; + if (state->chincpl) /* cplinu */ + state->cplba.deltbae = bitstream_get (state, 2); + for (i = 0; i < nfchans; i++) + state->ba[i].deltbae = bitstream_get (state, 2); + if (state->chincpl && /* cplinu */ + (state->cplba.deltbae == DELTA_BIT_NEW) && + parse_deltba (state, state->cplba.deltba)) + return 1; + for (i = 0; i < nfchans; i++) + if ((state->ba[i].deltbae == DELTA_BIT_NEW) && + parse_deltba (state, state->ba[i].deltba)) + return 1; + } + + if (do_bit_alloc) { + if (zero_snr_offsets (nfchans, state)) { + memset (state->cpl_expbap.bap, 0, sizeof (state->cpl_expbap.bap)); + for (i = 0; i < nfchans; i++) + memset (state->fbw_expbap[i].bap, 0, + sizeof (state->fbw_expbap[i].bap)); + memset (state->lfe_expbap.bap, 0, sizeof (state->lfe_expbap.bap)); + } else { + if (state->chincpl && (do_bit_alloc & 64)) /* cplinu */ + a52_bit_allocate (state, &state->cplba, state->cplstrtbnd, + state->cplstrtmant, state->cplendmant, + state->cplfleak << 8, state->cplsleak << 8, + &state->cpl_expbap); + for (i = 0; i < nfchans; i++) + if (do_bit_alloc & (1 << i)) + a52_bit_allocate (state, state->ba + i, 0, 0, + state->endmant[i], 0, 0, + state->fbw_expbap +i); + if (state->lfeon && (do_bit_alloc & 32)) { + state->lfeba.deltbae = DELTA_BIT_NONE; + a52_bit_allocate (state, &state->lfeba, 0, 0, 7, 0, 0, + &state->lfe_expbap); + } + } + } + + if (bitstream_get (state, 1)) { /* skiple */ + i = bitstream_get (state, 9); /* skipl */ + while (i--) + bitstream_get (state, 8); + } + + samples = state->samples; + if (state->output & A52_LFE) + samples += 256; /* shift for LFE channel */ + + chanbias = a52_downmix_coeff (coeff, state->acmod, state->output, + state->dynrng, state->clev, state->slev); + + quantizer.q1_ptr = quantizer.q2_ptr = quantizer.q4_ptr = -1; + done_cpl = 0; + + for (i = 0; i < nfchans; i++) { + int j; + + coeff_get (state, samples + 256 * i, state->fbw_expbap +i, &quantizer, + coeff[i], dithflag[i], state->endmant[i]); + + if ((state->chincpl >> i) & 1) { + if (!done_cpl) { + done_cpl = 1; + coeff_get_coupling (state, nfchans, coeff, + (sample_t (*)[256])samples, &quantizer, + dithflag); + } + j = state->cplendmant; + } else + j = state->endmant[i]; + do + (samples + 256 * i)[j] = 0; + while (++j < 256); + } + + if (state->acmod == 2) { + int j, end, band, rematflg; + + end = ((state->endmant[0] < state->endmant[1]) ? + state->endmant[0] : state->endmant[1]); + + i = 0; + j = 13; + rematflg = state->rematflg; + do { + if (! (rematflg & 1)) { + rematflg >>= 1; + j = rematrix_band[i++]; + continue; + } + rematflg >>= 1; + band = rematrix_band[i++]; + if (band > end) + band = end; + do { + sample_t tmp0, tmp1; + + tmp0 = samples[j]; + tmp1 = (samples+256)[j]; + samples[j] = tmp0 + tmp1; + (samples+256)[j] = tmp0 - tmp1; + } while (++j < band); + } while (j < end); + } + + if (state->lfeon) { + if (state->output & A52_LFE) { + coeff_get (state, samples - 256, &state->lfe_expbap, &quantizer, + state->dynrng, 0, 7); + for (i = 7; i < 256; i++) + (samples-256)[i] = 0; + a52_imdct_512 (samples - 256, samples + 1536 - 256, state->bias); + } else { + /* just skip the LFE coefficients */ + coeff_get (state, samples + 1280, &state->lfe_expbap, &quantizer, + 0, 0, 7); + } + } + + i = 0; + if (nfchans_tbl[state->output & A52_CHANNEL_MASK] < nfchans) + for (i = 1; i < nfchans; i++) + if (blksw[i] != blksw[0]) + break; + + if (i < nfchans) { + if (state->downmixed) { + state->downmixed = 0; + a52_upmix (samples + 1536, state->acmod, state->output); + } + + for (i = 0; i < nfchans; i++) { + sample_t bias; + + bias = 0; + if (!(chanbias & (1 << i))) + bias = state->bias; + + if (coeff[i]) { + if (blksw[i]) + a52_imdct_256 (samples + 256 * i, samples + 1536 + 256 * i, + bias); + else + a52_imdct_512 (samples + 256 * i, samples + 1536 + 256 * i, + bias); + } else { + int j; + + for (j = 0; j < 256; j++) + (samples + 256 * i)[j] = bias; + } + } + + a52_downmix (samples, state->acmod, state->output, state->bias, + state->clev, state->slev); + } else { + nfchans = nfchans_tbl[state->output & A52_CHANNEL_MASK]; + + a52_downmix (samples, state->acmod, state->output, 0, + state->clev, state->slev); + + if (!state->downmixed) { + state->downmixed = 1; + a52_downmix (samples + 1536, state->acmod, state->output, 0, + state->clev, state->slev); + } + + if (blksw[0]) + for (i = 0; i < nfchans; i++) + a52_imdct_256 (samples + 256 * i, samples + 1536 + 256 * i, + state->bias); + else + for (i = 0; i < nfchans; i++) + a52_imdct_512 (samples + 256 * i, samples + 1536 + 256 * i, + state->bias); + } + + return 0; +} + +void a52_free (a52_state_t * state) +{ + free (state->samples); + free (state); +} diff --git a/plugins/spu2ghz/src/3rdparty/liba52/tables.h b/plugins/spu2ghz/src/3rdparty/liba52/tables.h new file mode 100644 index 0000000000..5581779618 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/tables.h @@ -0,0 +1,246 @@ +/* + * tables.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ + +static const int8_t exp_1[128] = { + -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-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, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 25,25,25 +}; +static const int8_t exp_2[128] = { + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 25,25,25 +}; +static const int8_t exp_3[128] = { + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + 25,25,25 +}; + +#define Q0 ((-2 << 15) / 3.0) +#define Q1 (0) +#define Q2 ((2 << 15) / 3.0) + +static const sample_t q_1_0[32] = { + Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, + Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, + Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, + 0,0,0,0,0 +}; + +static const sample_t q_1_1[32] = { + Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, + Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, + Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2, + 0,0,0,0,0 +}; + +static const sample_t q_1_2[32] = { + Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, + Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, + Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2, + 0,0,0,0,0 +}; + +#undef Q0 +#undef Q1 +#undef Q2 + +#define Q0 ((-4 << 15) / 5.0) +#define Q1 ((-2 << 15) / 5.0) +#define Q2 (0) +#define Q3 ((2 << 15) / 5.0) +#define Q4 ((4 << 15) / 5.0) + +static const sample_t q_2_0[128] = { + Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, + Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, + Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, + Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3, + Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4, + 0,0,0 +}; + +static const sample_t q_2_1[128] = { + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + 0,0,0 +}; + +static const sample_t q_2_2[128] = { + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + 0,0,0 +}; + +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +#undef Q4 + +static const sample_t q_3[8] = { + (-6 << 15)/7.0, (-4 << 15)/7.0, (-2 << 15)/7.0, 0, + ( 2 << 15)/7.0, ( 4 << 15)/7.0, ( 6 << 15)/7.0, 0 +}; + +#define Q0 ((-10 << 15) / 11.0) +#define Q1 ((-8 << 15) / 11.0) +#define Q2 ((-6 << 15) / 11.0) +#define Q3 ((-4 << 15) / 11.0) +#define Q4 ((-2 << 15) / 11.0) +#define Q5 (0) +#define Q6 ((2 << 15) / 11.0) +#define Q7 ((4 << 15) / 11.0) +#define Q8 ((6 << 15) / 11.0) +#define Q9 ((8 << 15) / 11.0) +#define QA ((10 << 15) / 11.0) + +static const sample_t q_4_0[128] = { + Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, + Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, + Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, + Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, + Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, + Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, + Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, + Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, + Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, + Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, + QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, + 0, 0, 0, 0, 0, 0, 0 +}; + +static const sample_t q_4_1[128] = { + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + 0, 0, 0, 0, 0, 0, 0 +}; + +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +#undef Q4 +#undef Q5 +#undef Q6 +#undef Q7 +#undef Q8 +#undef Q9 +#undef QA + +static const sample_t q_5[16] = { + (-14 << 15)/15.0,(-12 << 15)/15.0,(-10 << 15)/15.0, + ( -8 << 15)/15.0,( -6 << 15)/15.0,( -4 << 15)/15.0, + ( -2 << 15)/15.0, 0 ,( 2 << 15)/15.0, + ( 4 << 15)/15.0,( 6 << 15)/15.0,( 8 << 15)/15.0, + ( 10 << 15)/15.0,( 12 << 15)/15.0,( 14 << 15)/15.0, + 0 +}; + +static const sample_t scale_factor[25] = { + 0.000030517578125, + 0.0000152587890625, + 0.00000762939453125, + 0.000003814697265625, + 0.0000019073486328125, + 0.00000095367431640625, + 0.000000476837158203125, + 0.0000002384185791015625, + 0.00000011920928955078125, + 0.000000059604644775390625, + 0.0000000298023223876953125, + 0.00000001490116119384765625, + 0.000000007450580596923828125, + 0.0000000037252902984619140625, + 0.00000000186264514923095703125, + 0.000000000931322574615478515625, + 0.0000000004656612873077392578125, + 0.00000000023283064365386962890625, + 0.000000000116415321826934814453125, + 0.0000000000582076609134674072265625, + 0.00000000002910383045673370361328125, + 0.000000000014551915228366851806640625, + 0.0000000000072759576141834259033203125, + 0.00000000000363797880709171295166015625, + 0.000000000001818989403545856475830078125 +}; + +static const uint16_t dither_lut[256] = { + 0x0000, 0xa011, 0xe033, 0x4022, 0x6077, 0xc066, 0x8044, 0x2055, + 0xc0ee, 0x60ff, 0x20dd, 0x80cc, 0xa099, 0x0088, 0x40aa, 0xe0bb, + 0x21cd, 0x81dc, 0xc1fe, 0x61ef, 0x41ba, 0xe1ab, 0xa189, 0x0198, + 0xe123, 0x4132, 0x0110, 0xa101, 0x8154, 0x2145, 0x6167, 0xc176, + 0x439a, 0xe38b, 0xa3a9, 0x03b8, 0x23ed, 0x83fc, 0xc3de, 0x63cf, + 0x8374, 0x2365, 0x6347, 0xc356, 0xe303, 0x4312, 0x0330, 0xa321, + 0x6257, 0xc246, 0x8264, 0x2275, 0x0220, 0xa231, 0xe213, 0x4202, + 0xa2b9, 0x02a8, 0x428a, 0xe29b, 0xc2ce, 0x62df, 0x22fd, 0x82ec, + 0x8734, 0x2725, 0x6707, 0xc716, 0xe743, 0x4752, 0x0770, 0xa761, + 0x47da, 0xe7cb, 0xa7e9, 0x07f8, 0x27ad, 0x87bc, 0xc79e, 0x678f, + 0xa6f9, 0x06e8, 0x46ca, 0xe6db, 0xc68e, 0x669f, 0x26bd, 0x86ac, + 0x6617, 0xc606, 0x8624, 0x2635, 0x0660, 0xa671, 0xe653, 0x4642, + 0xc4ae, 0x64bf, 0x249d, 0x848c, 0xa4d9, 0x04c8, 0x44ea, 0xe4fb, + 0x0440, 0xa451, 0xe473, 0x4462, 0x6437, 0xc426, 0x8404, 0x2415, + 0xe563, 0x4572, 0x0550, 0xa541, 0x8514, 0x2505, 0x6527, 0xc536, + 0x258d, 0x859c, 0xc5be, 0x65af, 0x45fa, 0xe5eb, 0xa5c9, 0x05d8, + 0xae79, 0x0e68, 0x4e4a, 0xee5b, 0xce0e, 0x6e1f, 0x2e3d, 0x8e2c, + 0x6e97, 0xce86, 0x8ea4, 0x2eb5, 0x0ee0, 0xaef1, 0xeed3, 0x4ec2, + 0x8fb4, 0x2fa5, 0x6f87, 0xcf96, 0xefc3, 0x4fd2, 0x0ff0, 0xafe1, + 0x4f5a, 0xef4b, 0xaf69, 0x0f78, 0x2f2d, 0x8f3c, 0xcf1e, 0x6f0f, + 0xede3, 0x4df2, 0x0dd0, 0xadc1, 0x8d94, 0x2d85, 0x6da7, 0xcdb6, + 0x2d0d, 0x8d1c, 0xcd3e, 0x6d2f, 0x4d7a, 0xed6b, 0xad49, 0x0d58, + 0xcc2e, 0x6c3f, 0x2c1d, 0x8c0c, 0xac59, 0x0c48, 0x4c6a, 0xec7b, + 0x0cc0, 0xacd1, 0xecf3, 0x4ce2, 0x6cb7, 0xcca6, 0x8c84, 0x2c95, + 0x294d, 0x895c, 0xc97e, 0x696f, 0x493a, 0xe92b, 0xa909, 0x0918, + 0xe9a3, 0x49b2, 0x0990, 0xa981, 0x89d4, 0x29c5, 0x69e7, 0xc9f6, + 0x0880, 0xa891, 0xe8b3, 0x48a2, 0x68f7, 0xc8e6, 0x88c4, 0x28d5, + 0xc86e, 0x687f, 0x285d, 0x884c, 0xa819, 0x0808, 0x482a, 0xe83b, + 0x6ad7, 0xcac6, 0x8ae4, 0x2af5, 0x0aa0, 0xaab1, 0xea93, 0x4a82, + 0xaa39, 0x0a28, 0x4a0a, 0xea1b, 0xca4e, 0x6a5f, 0x2a7d, 0x8a6c, + 0x4b1a, 0xeb0b, 0xab29, 0x0b38, 0x2b6d, 0x8b7c, 0xcb5e, 0x6b4f, + 0x8bf4, 0x2be5, 0x6bc7, 0xcbd6, 0xeb83, 0x4b92, 0x0bb0, 0xaba1 +}; diff --git a/plugins/spu2ghz/src/3rdparty/liba52/tendra.h b/plugins/spu2ghz/src/3rdparty/liba52/tendra.h new file mode 100644 index 0000000000..c2b1b62a55 --- /dev/null +++ b/plugins/spu2ghz/src/3rdparty/liba52/tendra.h @@ -0,0 +1,35 @@ +/* + * tendra.h + * Copyright (C) 2000-2002 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of a52dec, a free ATSC A-52 stream decoder. + * See http://liba52.sourceforge.net/ for updates. + * + * a52dec 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. + * + * a52dec 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 + */ + +#pragma TenDRA begin +#pragma TenDRA longlong type warning + +#ifdef TenDRA_check + +#pragma TenDRA conversion analysis (pointer-int explicit) off +#pragma TenDRA implicit function declaration off + +/* avoid the "No declarations in translation unit" problem */ +int TenDRA; + +#endif /* TenDRA_check */ diff --git a/plugins/spu2ghz/src/Win32/SPU2ghz.def b/plugins/spu2ghz/src/Win32/SPU2ghz.def new file mode 100644 index 0000000000..d304b8fe49 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/SPU2ghz.def @@ -0,0 +1,57 @@ +;GiGaHeRz's SPU2 Driver +;Copyright (c) David Quintana (gigaherz@gmail.com) +; +;This library is free software; you can redistribute it and/or +;modify it under the terms of the GNU Lesser General Public +;License as published by the Free Software Foundation; either +;version 2.1 of the License, or (at your option) any later version. +; +;This library 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 +;Lesser General Public License for more details. +; +;You should have received a copy of the GNU Lesser General Public +;License along with this library; if not, write to the Free Software +;Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +; +; SPU2ghz.def : Declares the module parameters for the DLL. + +;LIBRARY "SPU2ghz" + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + SPU2init @5 + SPU2shutdown @6 + SPU2open @7 + SPU2close @8 + SPU2write @9 + SPU2read @10 + SPU2readDMA4Mem @11 + SPU2writeDMA4Mem @12 + SPU2readDMA7Mem @13 + SPU2writeDMA7Mem @14 + SPU2async @15 + SPU2interruptDMA4 @16 + SPU2interruptDMA7 @17 + SPU2irqCallback @18 + + SPU2setupRecording @19 + + SPU2configure @20 + SPU2test @21 + SPU2about @22 + + SPU2ReadMemAddr @23 + SPU2WriteMemAddr @24 + + SPU2setClockPtr @25 + + SPU2setDMABaseAddr @26 + + SPU2replay = s2r_replay @27 + + SPU2freeze @28 \ No newline at end of file diff --git a/plugins/spu2ghz/src/Win32/SPU2ghz.rc b/plugins/spu2ghz/src/Win32/SPU2ghz.rc new file mode 100644 index 0000000000..474a628c0c --- /dev/null +++ b/plugins/spu2ghz/src/Win32/SPU2ghz.rc @@ -0,0 +1,268 @@ +// 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 + +///////////////////////////////////////////////////////////////////////////// +// Spanish resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESN) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_MODERN +#pragma code_page(1252) +#endif //_WIN32 + +#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 + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 3, 1, 410, 237 +STYLE DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "SPU2ghz Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + PUSHBUTTON "OK",IDOK,291,219,54,15,NOT WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,351,219,54,15,NOT WS_TABSTOP + GROUPBOX "Mixing Settings",IDC_STATIC,6,6,119,116 + GROUPBOX "Speed Limiter (obsolete)",IDC_STATIC,6,127,120,98 + GROUPBOX "Output Settings",IDC_STATIC,132,6,119,182 + GROUPBOX "",IDC_DEBUG_GROUP,257,7,148,208 + GROUPBOX "",IDC_STATIC,264,19,135,85 + GROUPBOX "Logging",IDC_STATIC,264,107,136,50 + GROUPBOX "Dumps (on close)",IDC_STATIC,264,160,135,49 + COMBOBOX IDC_OUTPUT,138,27,108,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure...",IDC_OUTCONF,198,42,48,12 + COMBOBOX IDC_INTERPOLATE,12,28,108,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Enable at start-up",IDC_SPEEDLIMIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,176,106,12 + COMBOBOX IDC_SRATE,188,62,58,201,CBS_DROPDOWN | WS_DISABLED | WS_TABSTOP,WS_EX_RIGHT + CONTROL "Slider2",IDC_LATENCY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,177,94,72,10 + CONTROL "Use Time-stretching",IDC_TS_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,138,114,79,11 + CONTROL "Use a Winamp DSP plugin",IDC_DSP_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,138,160,103,11 + CHECKBOX "Enable Debug Options",IDC_DEBUG,264,7,87,10,NOT WS_TABSTOP + CONTROL "Show In Console",IDC_MSGSHOW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,270,19,69,10 + CHECKBOX "KeyOn/Off Events",IDC_MSGKEY,276,31,74,10,NOT WS_TABSTOP + CONTROL "Voice Stop Events",IDC_MSGVOICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,43,75,10 + CONTROL "DMA Operations",IDC_MSGDMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,55,68,10 + CONTROL "AutoDMA Operations",IDC_MSGADMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,283,67,83,10 + CONTROL "Buffer Over/Underruns",IDC_DBG_OVERRUNS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,79,97,11 + CONTROL "ADPCM Cache Statistics",IDC_DBG_CACHE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,91,114,9 + CHECKBOX "Dump Core and Voice State",IDC_DUMPCORE,270,172,104,10,NOT WS_TABSTOP + CHECKBOX "Dump Memory Contents",IDC_DUMPMEM,270,184,91,10,NOT WS_TABSTOP + CHECKBOX "Dump Register Data",IDC_DUMPREGS,270,196,80,10,NOT WS_TABSTOP + CHECKBOX "Enable Effects Processing",IDC_EFFECTS,12,49,99,10,WS_DISABLED | NOT WS_TABSTOP + LTEXT "Latency:",IDC_STATIC,138,89,33,8,NOT WS_GROUP + LTEXT "Sample Rate:",IDC_STATIC,137,63,44,8,NOT WS_GROUP + LTEXT "Interpolation:",IDC_STATIC,12,18,42,10,NOT WS_GROUP + LTEXT "Module:",IDC_STATIC,138,17,50,9,NOT WS_GROUP + LTEXT "Not working yet, disabled for now.",IDC_STATIC,24,61,96,17 + LTEXT "(configure in the .ini)",IDC_STATIC,150,172,64,8 + LTEXT "Uses the SPU2 to limit framerate for games that cause buffer overruns. Use Timestretching instead.",IDC_STATIC,11,138,109,34 + CTEXT "100 ms (avg)",IDC_LATENCY_LABEL,185,84,58,10 + LTEXT "Helps reduce latency and usually eliminates audio skips. Uses a little extra CPU.",IDC_STATIC,150,127,96,25 + CHECKBOX "Log Register/DMA Actions",IDC_LOGREGS,269,119,101,10,WS_GROUP | NOT WS_TABSTOP + CHECKBOX "Log DMA Writes",IDC_LOGDMA,269,131,68,10,NOT WS_TABSTOP + CHECKBOX "Log Audio Output",IDC_LOGWAVE,269,143,71,10,NOT WS_TABSTOP + CONTROL "Enable runtime toggle",IDC_SPEEDLIMIT_RUNTIME_TOGGLE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,190,110,10 + LTEXT "Allows speed limiter to be toggled with the minus (-) key.",IDC_STATIC,23,202,95,17 + CONTROL "Volume Boost",IDC_VOLBOOST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,86,85,11 + LTEXT "Can break sound in games that are already loud.",IDC_STATIC,24,99,96,17 +END + +IDD_DEBUG DIALOGEX 0, 0, 326, 525 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "SPU2ghz Debug" +FONT 9, "Lucida Console", 400, 0, 0x0 +BEGIN + DEFPUSHBUTTON "Close",IDOK,269,504,50,14 +END + +IDD_DSOUND DIALOGEX 0, 0, 170, 122 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "DirectSound Output Module Settings" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,52,104,50,14 + PUSHBUTTON "Cancel",IDCANCEL,115,104,50,14 + COMBOBOX IDC_DS_DEVICE,4,15,161,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "DirectSound Device",IDC_STATIC,4,3,63,8 + LTEXT "Number of Buffers",IDC_STATIC,4,40,61,11 + CONTROL "",IDC_BUFFERS_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,71,48,94,10 + LTEXT "Use extra buffers if you are experiencing loopy or studdery audio even when games run at high FPS.",IDC_STATIC,8,66,151,27 + CTEXT "8 (80 ms latency)",IDC_LATENCY_LABEL,70,37,95,11 +END + +IDD_DSOUND51 DIALOGEX 0, 0, 336, 180 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "DirectSound 5.1 Output Module Settings" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,228,161,50,14 + PUSHBUTTON "Cancel",IDCANCEL,281,161,50,14 + COMBOBOX IDC_DS_DEVICE,5,17,142,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "DirectSound Device",IDC_STATIC,5,5,63,8 + CONTROL "",IDC_LEFT_GAIN_SLIDER,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,15,53,30,36 + CONTROL "",IDC_CENTER_GAIN_SLIDER,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,57,54,30,34 + CONTROL "",IDC_RIGHT_GAIN_SLIDER,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,99,54,30,34 + GROUPBOX "Surround Volume Correction",IDC_STATIC,5,35,138,139 + CTEXT "Center",IDC_STATIC,50,46,42,8 + CTEXT "Left",IDC_STATIC,8,46,42,8 + CTEXT "Right",IDC_STATIC,92,46,42,8 + CONTROL "",IDC_RLEFT_GAIN_SLIDER,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,15,115,30,40 + CONTROL "",IDC_LFE_SLIDER,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,57,115,30,40 + CONTROL "",IDC_RRIGHT_GAIN_SLIDER,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,99,115,30,40 + CTEXT "LFE (sub)",IDC_STATIC,51,107,42,8 + CTEXT "Rear Left",IDC_STATIC,9,107,42,8 + CTEXT "Rear Right",IDC_STATIC,93,107,42,8 + GROUPBOX "Other Tweaks",IDC_STATIC,153,77,63,97 + CONTROL "",IDC_LR_CENTER_SLIDER,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,169,99,30,49 + CTEXT "Center in LR",IDC_STATIC,163,90,42,8 + EDITTEXT IDC_LEFT_GAIN_EDIT,15,88,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_CENTER_GAIN_EDIT,57,88,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_RIGHT_GAIN_EDIT,99,88,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_RLEFT_GAIN_EDIT,15,155,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_LFE_EDIT,57,155,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_RRIGHT_GAIN_EDIT,99,155,30,14,ES_AUTOHSCROLL + EDITTEXT IDC_LR_CENTER_EDIT,169,151,30,14,ES_AUTOHSCROLL + LTEXT "Number of Buffers",IDC_STATIC,160,32,61,11 + CONTROL "",IDC_BUFFERS_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,229,40,94,10 + LTEXT "Use extra buffers if you are experiencing loopy or studdery audio even when games run at high FPS.",IDC_STATIC,226,69,102,46 + CTEXT "8 (80 ms latency)",IDC_LATENCY_LABEL2,227,29,95,11 + GROUPBOX "Latency",IDC_STATIC,154,13,174,48 +END + +IDD_ASIO DIALOGEX 0, 0, 186, 58 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "ASIO Output Module Settings" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,75,37,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,37,50,14 + COMBOBOX IDC_DS_DEVICE,7,17,172,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "ASIO Driver",IDC_STATIC,7,7,39,8 +END + +IDD_WAVEOUT DIALOGEX 0, 0, 170, 122 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "waveOut Output Module Settings" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,52,104,50,14 + PUSHBUTTON "Cancel",IDCANCEL,115,104,50,14 + COMBOBOX IDC_DS_DEVICE,4,15,161,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "waveOut Device",IDC_STATIC,4,3,54,8 + LTEXT "Number of Buffers",IDC_STATIC,4,39,61,11 + CONTROL "",IDC_BUFFERS_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,71,48,94,10 + LTEXT "Use extra buffers if you are experiencing loopy or studdery audio even when games run at high FPS.",IDC_STATIC,8,66,151,27 + CTEXT "8 (80 ms latency)",IDC_LATENCY_LABEL,70,37,95,11 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 6 + RIGHTMARGIN, 405 + BOTTOMMARGIN, 234 + END + + IDD_DEBUG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 319 + TOPMARGIN, 7 + BOTTOMMARGIN, 518 + END + + IDD_DSOUND, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 165 + TOPMARGIN, 3 + BOTTOMMARGIN, 118 + END + + IDD_DSOUND51, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 331 + TOPMARGIN, 5 + BOTTOMMARGIN, 175 + END + + IDD_ASIO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 51 + END + + IDD_WAVEOUT, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 165 + TOPMARGIN, 3 + BOTTOMMARGIN, 118 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Spanish resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/spu2ghz/src/Win32/SPU2ghz_vs2008.vcproj b/plugins/spu2ghz/src/Win32/SPU2ghz_vs2008.vcproj new file mode 100644 index 0000000000..d6ad991073 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/SPU2ghz_vs2008.vcproj @@ -0,0 +1,1074 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spu2ghz/src/Win32/config.cpp b/plugins/spu2ghz/src/Win32/config.cpp new file mode 100644 index 0000000000..704ca90b21 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/config.cpp @@ -0,0 +1,618 @@ +///GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include "spu2.h" +#include "dialogs.h" +// Config Vars + + +static bool VolumeBoostEnabled = false; +static int VolumeShiftModifier = 0; + +#ifndef PUBLIC +static const int LATENCY_MAX = 2000; +#else +static const int LATENCY_MAX = 500; +#endif + +static const int LATENCY_MIN = 40; + + +// DEBUG + +bool DebugEnabled=false; +bool _MsgToConsole=false; +bool _MsgKeyOnOff=false; +bool _MsgVoiceOff=false; +bool _MsgDMA=false; +bool _MsgAutoDMA=false; +bool _MsgOverruns=false; +bool _MsgCache=false; + +bool _AccessLog=false; +bool _DMALog=false; +bool _WaveLog=false; + +bool _CoresDump=false; +bool _MemDump=false; +bool _RegDump=false; + + + +char AccessLogFileName[255]; +char WaveLogFileName[255]; + +char DMA4LogFileName[255]; +char DMA7LogFileName[255]; + +char CoresDumpFileName[255]; +char MemDumpFileName[255]; +char RegDumpFileName[255]; + +int WaveDumpFormat; + +int AutoDMAPlayRate[2]={0,0}; + +// MIXING +int Interpolation=1; +/* values: + 0: no interpolation (use nearest) + 1. linear interpolation + 2. cubic interpolation +*/ + +bool EffectsEnabled=false; + +// OUTPUT +int SampleRate=48000; +int SndOutLatencyMS=160; +//int SndOutLatency=1024; +//int MaxBufferCount=8; +//int CurBufferCount=MaxBufferCount; +bool timeStretchEnabled=true; + +u32 OutputModule=0; //OUTPUT_DSOUND; + +//int VolumeMultiplier=1; +//int VolumeDivisor=1; + +int LimitMode=0; +/* values: + 0. No limiter + 1. Soft limiter -- less cpu-intensive, but can cause problems + 2. Hard limiter -- more cpu-intensive while limiting, but should give better (constant) speeds +*/ + + +CONFIG_DSOUNDOUT Config_DSoundOut; +CONFIG_DSOUND51 Config_DSound51; +CONFIG_WAVEOUT Config_WaveOut; + +// MISC +bool LimiterToggleEnabled=false; +int LimiterToggle=VK_SUBTRACT; + +// DSP +bool dspPluginEnabled=false; +char dspPlugin[256]; +int dspPluginModule=0; + +// OUTPUT MODULES +char AsioDriver[129]=""; + + +////// + +const char NewCfgFile[]="inis\\SPU2Ghz-v2.ini"; +const char LegacyCfgFile[]="inis\\SPU2Ghz.ini"; +const char* CfgFile=NewCfgFile; + + + /*| Config File Format: |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*\ ++--+---------------------+------------------------+ +| | +| Option=Value | +| | +| | +| Boolean Values: TRUE,YES,1,T,Y mean 'true', | +| everything else means 'false'. | +| | +| All Values are limited to 255 chars. | +| | ++-------------------------------------------------+ + \*_____________________________________________*/ + + +void CfgWriteBool(const char *Section, const char*Name, bool Value) { + char *Data=Value?"TRUE":"FALSE"; + + WritePrivateProfileString(Section,Name,Data,CfgFile); +} + +void CfgWriteInt(const char *Section, const char*Name, int Value) { + char Data[255]; + _itoa(Value,Data,10); + + WritePrivateProfileString(Section,Name,Data,CfgFile); +} + +void CfgWriteStr(const char *Section, const char* Name, const char *Data) { + WritePrivateProfileString(Section,Name,Data,CfgFile); +} + +/*****************************************************************************/ + +bool CfgReadBool(const char *Section,const char *Name,bool Default) { + char Data[255]=""; + GetPrivateProfileString(Section,Name,"",Data,255,CfgFile); + Data[254]=0; + if(strlen(Data)==0) { + CfgWriteBool(Section,Name,Default); + return Default; + } + + if(strcmp(Data,"1")==0) return true; + if(strcmp(Data,"Y")==0) return true; + if(strcmp(Data,"T")==0) return true; + if(strcmp(Data,"YES")==0) return true; + if(strcmp(Data,"TRUE")==0) return true; + return false; +} + + +int CfgReadInt(const char *Section, const char*Name,int Default) { + char Data[255]=""; + GetPrivateProfileString(Section,Name,"",Data,255,CfgFile); + Data[254]=0; + + if(strlen(Data)==0) { + CfgWriteInt(Section,Name,Default); + return Default; + } + + return atoi(Data); +} + + +void CfgReadStr(const char *Section, const char* Name, char *Data, int DataSize, const char *Default) { + GetPrivateProfileString(Section,Name,"",Data,DataSize,CfgFile); + + if(strlen(Data)==0) { + sprintf_s( Data, DataSize, "%s", Default ); + CfgWriteStr(Section,Name,Data); + } +} + +// Tries to read the requested value. +// Returns FALSE if the value isn't found. +bool CfgFindName( const char *Section, const char* Name) +{ + // Only load 24 characters. No need to load more. + char Data[24]=""; + GetPrivateProfileString(Section,Name,"",Data,24,CfgFile); + Data[23]=0; + + if(strlen(Data)==0) return false; + return true; +} +/*****************************************************************************/ + +void ReadSettings() +{ + DebugEnabled=CfgReadBool("DEBUG","Global_Debug_Enabled",0); + _MsgToConsole=CfgReadBool("DEBUG","Show_Messages",0); + _MsgKeyOnOff =CfgReadBool("DEBUG","Show_Messages_Key_On_Off",0); + _MsgVoiceOff =CfgReadBool("DEBUG","Show_Messages_Voice_Off",0); + _MsgDMA =CfgReadBool("DEBUG","Show_Messages_DMA_Transfer",0); + _MsgAutoDMA =CfgReadBool("DEBUG","Show_Messages_AutoDMA",0); + _MsgOverruns =CfgReadBool("DEBUG","Show_Messages_Overruns",0); + _MsgCache =CfgReadBool("DEBUG","Show_Messages_CacheStats",0); + + _AccessLog =CfgReadBool("DEBUG","Log_Register_Access",0); + _DMALog =CfgReadBool("DEBUG","Log_DMA_Transfers",0); + _WaveLog =CfgReadBool("DEBUG","Log_WAVE_Output",0); + + _CoresDump =CfgReadBool("DEBUG","Dump_Info",0); + _MemDump =CfgReadBool("DEBUG","Dump_Memory",0); + _RegDump =CfgReadBool("DEBUG","Dump_Regs",0); + + CfgReadStr("DEBUG","Access_Log_Filename",AccessLogFileName,255,"logs\\SPU2Log.txt"); + CfgReadStr("DEBUG","WaveLog_Filename", WaveLogFileName, 255,"logs\\SPU2log.wav"); + CfgReadStr("DEBUG","DMA4Log_Filename", DMA4LogFileName, 255,"logs\\SPU2dma4.dat"); + CfgReadStr("DEBUG","DMA7Log_Filename", DMA7LogFileName, 255,"logs\\SPU2dma7.dat"); + + CfgReadStr("DEBUG","Info_Dump_Filename",CoresDumpFileName,255,"logs\\SPU2Cores.txt"); + CfgReadStr("DEBUG","Mem_Dump_Filename", MemDumpFileName, 255,"logs\\SPU2mem.dat"); + CfgReadStr("DEBUG","Reg_Dump_Filename", RegDumpFileName, 255,"logs\\SPU2regs.dat"); + + WaveDumpFormat=CfgReadInt("DEBUG","Wave_Log_Format",0); + + + AutoDMAPlayRate[0]=CfgReadInt("MIXING","AutoDMA_Play_Rate_0",0); + AutoDMAPlayRate[1]=CfgReadInt("MIXING","AutoDMA_Play_Rate_1",0); + + Interpolation=CfgReadInt("MIXING","Interpolation",1); + + // Moved Timestretch from DSP to Output + timeStretchEnabled = CfgReadBool( + CfgFindName( "OUTPUT", "Timestretch_Enable" ) ? "OUTPUT" : "DSP", + "Timestretch_Enable", true + ); + + // Moved Effects_Enable from Effects to Mixing + EffectsEnabled = CfgReadBool( + CfgFindName( "MIXING", "Enable_Effects" ) ? "MIXING" : "EFFECTS", + "Enable_Effects", false + ); + EffectsEnabled = false; // force disabled for now. + + SampleRate=CfgReadInt("OUTPUT","Sample_Rate",48000); + SndOutLatencyMS=CfgReadInt("OUTPUT","Latency", 160); + + //OutputModule = CfgReadInt("OUTPUT","Output_Module", OUTPUT_DSOUND ); + char omodid[128]; + CfgReadStr( "OUTPUT", "Output_Module", omodid, 127, XAudio2Out->GetIdent() ); + + // find the driver index of this module: + OutputModule = FindOutputModuleById( omodid ); + + VolumeShiftModifier = CfgReadInt( "OUTPUT","Volume_Shift", 0 ); + LimitMode=CfgReadInt("OUTPUT","Speed_Limit_Mode",0); + + CfgReadStr("DSP PLUGIN","Filename",dspPlugin,255,""); + dspPluginModule = CfgReadInt("DSP PLUGIN","ModuleNum",0); + dspPluginEnabled= CfgReadBool("DSP PLUGIN","Enabled",false); + + LimiterToggleEnabled = CfgReadBool("KEYS","Limiter_Toggle_Enabled",false); + LimiterToggle = CfgReadInt ("KEYS","Limiter_Toggle",VK_SUBTRACT); + + // Read DSOUNDOUT and WAVEOUT configs: + CfgReadStr( "DSOUNDOUT", "Device", Config_DSoundOut.Device, 254, "default" ); + CfgReadStr( "WAVEOUT", "Device", Config_WaveOut.Device, 254, "default" ); + Config_DSoundOut.NumBuffers = CfgReadInt( "DSOUNDOUT", "Buffer_Count", 5 ); + Config_WaveOut.NumBuffers = CfgReadInt( "WAVEOUT", "Buffer_Count", 4 ); + + // Read DSOUND51 config: + CfgReadStr( "DSOUND51", "Device", Config_DSound51.Device, 254, "default" ); + Config_DSound51.NumBuffers = CfgReadInt( "DSOUND51", "Buffer_Count", 5 ); + Config_DSound51.GainL =CfgReadInt("DSOUND51","Channel_Gain_L", 256); + Config_DSound51.GainR =CfgReadInt("DSOUND51","Channel_Gain_R", 256); + Config_DSound51.GainC =CfgReadInt("DSOUND51","Channel_Gain_C", 256); + Config_DSound51.GainLFE=CfgReadInt("DSOUND51","Channel_Gain_LFE",256); + Config_DSound51.GainSL =CfgReadInt("DSOUND51","Channel_Gain_SL", 200); + Config_DSound51.GainSR =CfgReadInt("DSOUND51","Channel_Gain_SR", 200); + Config_DSound51.AddCLR =CfgReadInt("DSOUND51","Channel_Center_In_LR", 56); + Config_DSound51.LowpassLFE = CfgReadInt("DSOUND51","LFE_Lowpass_Frequency", 80); + + // Sanity Checks + // ------------- + + SampleRate = 48000; // Yup nothing else is supported for now. + VolumeShiftModifier = min( max( VolumeShiftModifier, -2 ), 2 ); + SndOutVolumeShift = SndOutVolumeShiftBase - VolumeShiftModifier; + SndOutLatencyMS = min( max( SndOutLatencyMS, LATENCY_MIN ), LATENCY_MAX ); + + Config_DSoundOut.NumBuffers = min( max( Config_DSoundOut.NumBuffers, 2 ), 8 ); + Config_WaveOut.NumBuffers = min( max( Config_DSoundOut.NumBuffers, 3 ), 8 ); + + if( mods[OutputModule] == NULL ) + { + // Unsupported or legacy module. + fprintf( stderr, " * SPU2: Unknown output module '%s' specified in configuration file.\n", omodid ); + fprintf( stderr, " * SPU2: Defaulting to DirectSound (%s).\n", DSoundOut->GetIdent() ); + OutputModule = FindOutputModuleById( DSoundOut->GetIdent() ); + } + + +} + +/*****************************************************************************/ + +void WriteSettings() +{ + CfgWriteBool("DEBUG","Global_Debug_Enabled",DebugEnabled); + + // [Air] : Commented out so that we retain debug settings even if disabled... + //if(DebugEnabled) + { + CfgWriteBool("DEBUG","Show_Messages", _MsgToConsole); + CfgWriteBool("DEBUG","Show_Messages_Key_On_Off", _MsgKeyOnOff); + CfgWriteBool("DEBUG","Show_Messages_Voice_Off", _MsgVoiceOff); + CfgWriteBool("DEBUG","Show_Messages_DMA_Transfer",_MsgDMA); + CfgWriteBool("DEBUG","Show_Messages_AutoDMA", _MsgAutoDMA); + CfgWriteBool("DEBUG","Show_Messages_Overruns", _MsgOverruns); + CfgWriteBool("DEBUG","Show_Messages_CacheStats", _MsgCache); + + CfgWriteBool("DEBUG","Log_Register_Access",_AccessLog); + CfgWriteBool("DEBUG","Log_DMA_Transfers", _DMALog); + CfgWriteBool("DEBUG","Log_WAVE_Output", _WaveLog); + + CfgWriteBool("DEBUG","Dump_Info", _CoresDump); + CfgWriteBool("DEBUG","Dump_Memory",_MemDump); + CfgWriteBool("DEBUG","Dump_Regs", _RegDump); + + CfgWriteStr("DEBUG","Access_Log_Filename",AccessLogFileName); + CfgWriteStr("DEBUG","WaveLog_Filename", WaveLogFileName); + CfgWriteStr("DEBUG","DMA4Log_Filename", DMA4LogFileName); + CfgWriteStr("DEBUG","DMA7Log_Filename", DMA7LogFileName); + + CfgWriteStr("DEBUG","Info_Dump_Filename",CoresDumpFileName); + CfgWriteStr("DEBUG","Mem_Dump_Filename", MemDumpFileName); + CfgWriteStr("DEBUG","Reg_Dump_Filename", RegDumpFileName); + + CfgWriteInt("DEBUG","Wave_Log_Format", WaveDumpFormat); + } + + CfgWriteInt("MIXING","Interpolation",Interpolation); + + CfgWriteInt("MIXING","AutoDMA_Play_Rate_0",AutoDMAPlayRate[0]); + CfgWriteInt("MIXING","AutoDMA_Play_Rate_1",AutoDMAPlayRate[1]); + + CfgWriteBool("MIXING","Enable_Effects",EffectsEnabled); + + CfgWriteStr("OUTPUT","Output_Module",mods[OutputModule]->GetIdent() ); + CfgWriteInt("OUTPUT","Sample_Rate",SampleRate); + CfgWriteInt("OUTPUT","Latency",SndOutLatencyMS); + CfgWriteBool("OUTPUT","Timestretch_Enable",timeStretchEnabled); + CfgWriteInt("OUTPUT","Speed_Limit_Mode",LimitMode); + + CfgWriteInt("OUTPUT","Volume_Shift",SndOutVolumeShiftBase - SndOutVolumeShift); + + if( strlen( Config_DSoundOut.Device ) == 0 ) strcpy( Config_DSoundOut.Device, "default" ); + if( strlen( Config_DSound51.Device ) == 0 ) strcpy( Config_DSound51.Device, "default" ); + if( strlen( Config_WaveOut.Device ) == 0 ) strcpy( Config_WaveOut.Device, "default" ); + + CfgWriteStr("DSOUNDOUT","Device",Config_DSoundOut.Device); + CfgWriteInt("DSOUNDOUT","Buffer_Count",Config_DSoundOut.NumBuffers); + + CfgWriteStr("WAVEOUT","Device",Config_WaveOut.Device); + CfgWriteInt("WAVEOUT","Buffer_Count",Config_WaveOut.NumBuffers); + + CfgWriteStr("DSOUND51","Device",Config_DSound51.Device); + CfgWriteInt("DSOUND51","Buffer_Count", Config_DSound51.NumBuffers); + CfgWriteInt("DSOUND51","Channel_Gain_L", Config_DSound51.GainL); + CfgWriteInt("DSOUND51","Channel_Gain_R", Config_DSound51.GainR); + CfgWriteInt("DSOUND51","Channel_Gain_C", Config_DSound51.GainC); + CfgWriteInt("DSOUND51","Channel_Gain_LFE",Config_DSound51.GainLFE); + CfgWriteInt("DSOUND51","Channel_Gain_SL", Config_DSound51.GainSL); + CfgWriteInt("DSOUND51","Channel_Gain_SR", Config_DSound51.GainSR); + CfgWriteInt("DSOUND51","Channel_Center_In_LR", Config_DSound51.AddCLR); + CfgWriteInt("DSOUND51","LFE_Lowpass_Frequency", Config_DSound51.LowpassLFE); + + CfgWriteStr("DSP PLUGIN","Filename",dspPlugin); + CfgWriteInt("DSP PLUGIN","ModuleNum",dspPluginModule); + CfgWriteBool("DSP PLUGIN","Enabled",dspPluginEnabled); + + CfgWriteBool("KEYS","Limiter_Toggle_Enabled",LimiterToggleEnabled); + CfgWriteInt ("KEYS","Limiter_Toggle",LimiterToggle); +} + +static void EnableDebugMessages( HWND hWnd ) +{ + ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled); + ENABLE_CONTROL(IDC_MSGKEY, MsgToConsole()); + ENABLE_CONTROL(IDC_MSGVOICE,MsgToConsole()); + ENABLE_CONTROL(IDC_MSGDMA, MsgToConsole()); + ENABLE_CONTROL(IDC_MSGADMA, MsgDMA()); + ENABLE_CONTROL(IDC_DBG_OVERRUNS, MsgToConsole()); + ENABLE_CONTROL(IDC_DBG_CACHE, MsgToConsole()); +} + +static void EnableDebugControls( HWND hWnd ) +{ + EnableDebugMessages( hWnd ); + ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled); + ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled); + ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled); + ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled); + ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled); + ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled); +} + +static int myWidth, myDebugWidth; +static int myHeight; +static bool debugShow = false; + +BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + int wmId,wmEvent; + char temp[384]={0}; + + switch(uMsg) + { + + case WM_PAINT: + return FALSE; + + case WM_INITDIALOG: + + // If debugging is enabled, show the debug box by default: + debugShow = DebugEnabled; + + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_RESETCONTENT,0,0); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"16000"); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"22050"); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"24000"); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"32000"); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"44100"); + SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"48000"); + + sprintf_s(temp,48,"%d",SampleRate); + SetDlgItemText(hWnd,IDC_SRATE,temp); + + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_RESETCONTENT,0,0); + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"0 - Nearest (none/fast)"); + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"1 - Linear (recommended)"); + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"2 - Cubic (better/slower)"); + SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_SETCURSEL,Interpolation,0); + + SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_RESETCONTENT,0,0); + + { + int modidx = 0; + while( mods[modidx] != NULL ) + { + sprintf_s( temp, 72, "%d - %s", modidx, mods[modidx]->GetLongName() ); + SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)temp); + ++modidx; + } + SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_SETCURSEL,OutputModule,0); + } + + //INIT_SLIDER(IDC_BUFFER,512,16384,4096,2048,512); + INIT_SLIDER( IDC_LATENCY_SLIDER, LATENCY_MIN, LATENCY_MAX, 100, 20, 5 ); + + SendMessage(GetDlgItem(hWnd,IDC_LATENCY_SLIDER),TBM_SETPOS,TRUE,SndOutLatencyMS); + sprintf_s(temp,80,"%d ms (avg)",SndOutLatencyMS); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + + EnableDebugControls( hWnd ); + + // Debugging / Logging Flags: + SET_CHECK(IDC_EFFECTS, EffectsEnabled); + SET_CHECK(IDC_DEBUG, DebugEnabled); + SET_CHECK(IDC_MSGSHOW, _MsgToConsole); + SET_CHECK(IDC_MSGKEY, _MsgKeyOnOff); + SET_CHECK(IDC_MSGVOICE,_MsgVoiceOff); + SET_CHECK(IDC_MSGDMA, _MsgDMA); + SET_CHECK(IDC_MSGADMA, _MsgAutoDMA); + SET_CHECK(IDC_DBG_OVERRUNS, _MsgOverruns ); + SET_CHECK(IDC_DBG_CACHE, _MsgCache ); + SET_CHECK(IDC_LOGREGS, _AccessLog); + SET_CHECK(IDC_LOGDMA, _DMALog); + SET_CHECK(IDC_LOGWAVE, _WaveLog); + SET_CHECK(IDC_DUMPCORE,_CoresDump); + SET_CHECK(IDC_DUMPMEM, _MemDump); + SET_CHECK(IDC_DUMPREGS,_RegDump); + + SET_CHECK(IDC_SPEEDLIMIT,LimitMode); + SET_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled); + SET_CHECK(IDC_DSP_ENABLE,dspPluginEnabled); + SET_CHECK(IDC_TS_ENABLE,timeStretchEnabled); + + VolumeBoostEnabled = ( VolumeShiftModifier > 0 ) ? true : false; + SET_CHECK(IDC_VOLBOOST, VolumeBoostEnabled ); + + break; + + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDOK: + GetDlgItemText(hWnd,IDC_SRATE,temp,20); + temp[19]=0; + SampleRate=atoi(temp); + + SndOutLatencyMS = (int)SendMessage( GetDlgItem( hWnd, IDC_LATENCY_SLIDER ), TBM_GETPOS, 0, 0 ); + + if( SndOutLatencyMS > LATENCY_MAX ) SndOutLatencyMS = LATENCY_MAX; + if( SndOutLatencyMS < LATENCY_MIN ) SndOutLatencyMS = LATENCY_MIN; + + Interpolation=(int)SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_GETCURSEL,0,0); + OutputModule=(int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0); + + WriteSettings(); + EndDialog(hWnd,0); + break; + case IDCANCEL: + EndDialog(hWnd,0); + break; + + case IDC_OUTCONF: + SndConfigure( hWnd, + (int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0) + ); + break; + + HANDLE_CHECKNB( IDC_VOLBOOST, VolumeBoostEnabled ); + VolumeShiftModifier = (VolumeBoostEnabled ? 1 : 0 ); + SndOutVolumeShift = SndOutVolumeShiftBase - VolumeShiftModifier; + break; + + HANDLE_CHECK(IDC_EFFECTS,EffectsEnabled); + HANDLE_CHECKNB(IDC_DEBUG,DebugEnabled); + EnableDebugControls( hWnd ); + break; + HANDLE_CHECKNB(IDC_MSGSHOW,_MsgToConsole); + EnableDebugMessages( hWnd ); + break; + HANDLE_CHECK(IDC_MSGKEY,_MsgKeyOnOff); + HANDLE_CHECK(IDC_MSGVOICE,_MsgVoiceOff); + HANDLE_CHECKNB(IDC_MSGDMA,_MsgDMA); + ENABLE_CONTROL(IDC_MSGADMA, MsgDMA()); + break; + HANDLE_CHECK(IDC_MSGADMA,_MsgAutoDMA); + HANDLE_CHECK(IDC_DBG_OVERRUNS,_MsgOverruns); + HANDLE_CHECK(IDC_DBG_CACHE,_MsgCache); + HANDLE_CHECK(IDC_LOGREGS,_AccessLog); + HANDLE_CHECK(IDC_LOGDMA, _DMALog); + HANDLE_CHECK(IDC_LOGWAVE,_WaveLog); + HANDLE_CHECK(IDC_DUMPCORE,_CoresDump); + HANDLE_CHECK(IDC_DUMPMEM, _MemDump); + HANDLE_CHECK(IDC_DUMPREGS,_RegDump); + HANDLE_CHECK(IDC_DSP_ENABLE,dspPluginEnabled); + HANDLE_CHECK(IDC_TS_ENABLE,timeStretchEnabled); + HANDLE_CHECK(IDC_SPEEDLIMIT,LimitMode); + HANDLE_CHECK(IDC_SPEEDLIMIT_RUNTIME_TOGGLE,LimiterToggleEnabled); + default: + return FALSE; + } + break; + case WM_HSCROLL: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch(wmId) { + //case TB_ENDTRACK: + //case TB_THUMBPOSITION: + case TB_LINEUP: + case TB_LINEDOWN: + case TB_PAGEUP: + case TB_PAGEDOWN: + wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); + case TB_THUMBTRACK: + if(wmEventLATENCY_MAX) wmEvent=LATENCY_MAX; + SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); + sprintf_s(temp,80,"%d ms (avg)",wmEvent); + SetDlgItemText(hWnd,IDC_LATENCY_LABEL,temp); + break; + default: + return FALSE; + } + break; + default: + return FALSE; + } + return TRUE; +} + +void configure() +{ + INT_PTR ret; + ReadSettings(); + ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_CONFIG),GetActiveWindow(),(DLGPROC)ConfigProc,1); + if(ret==-1) + { + MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); + return; + } + ReadSettings(); +} diff --git a/plugins/spu2ghz/src/Win32/config.h b/plugins/spu2ghz/src/Win32/config.h new file mode 100644 index 0000000000..84031aa3e3 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/config.h @@ -0,0 +1,169 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#ifndef CONFIG_H_INCLUDED +#define CONFIG_H_INCLUDED + +extern bool DebugEnabled; + +extern bool _MsgToConsole; +extern bool _MsgKeyOnOff; +extern bool _MsgVoiceOff; +extern bool _MsgDMA; +extern bool _MsgAutoDMA; +extern bool _MsgOverruns; +extern bool _MsgCache; + +extern bool _AccessLog; +extern bool _DMALog; +extern bool _WaveLog; + +extern bool _CoresDump; +extern bool _MemDump; +extern bool _RegDump; + +static __forceinline bool MsgToConsole() { return _MsgToConsole & DebugEnabled; } + +static __forceinline bool MsgKeyOnOff() { return _MsgKeyOnOff & MsgToConsole(); } +static __forceinline bool MsgVoiceOff() { return _MsgVoiceOff & MsgToConsole(); } +static __forceinline bool MsgDMA() { return _MsgDMA & MsgToConsole(); } +static __forceinline bool MsgAutoDMA() { return _MsgAutoDMA & MsgDMA(); } +static __forceinline bool MsgOverruns() { return _MsgOverruns & MsgToConsole(); } +static __forceinline bool MsgCache() { return _MsgCache & MsgToConsole(); } + +static __forceinline bool AccessLog() { return _AccessLog & DebugEnabled; } +static __forceinline bool DMALog() { return _DMALog & DebugEnabled; } +static __forceinline bool WaveLog() { return _WaveLog & DebugEnabled; } + +static __forceinline bool CoresDump() { return _CoresDump & DebugEnabled; } +static __forceinline bool MemDump() { return _MemDump & DebugEnabled; } +static __forceinline bool RegDump() { return _RegDump & DebugEnabled; } + + +extern char AccessLogFileName[255]; +extern char WaveLogFileName[255]; + +extern char DMA4LogFileName[255]; +extern char DMA7LogFileName[255]; + +extern char CoresDumpFileName[255]; +extern char MemDumpFileName[255]; +extern char RegDumpFileName[255]; + +extern int Interpolation; + +extern int WaveDumpFormat; + +extern int SampleRate; + +extern bool EffectsEnabled; + +extern int AutoDMAPlayRate[2]; + +extern u32 OutputModule; +extern int SndOutLatencyMS; + +//extern int VolumeMultiplier; +//extern int VolumeDivisor; + +extern int LimitMode; + +extern char AsioDriver[129]; + +extern char dspPlugin[]; +extern int dspPluginModule; + +extern bool dspPluginEnabled; +extern bool timeStretchEnabled; + +extern bool LimiterToggleEnabled; +extern int LimiterToggle; + +// *** BEGIN DRIVER-SPECIFIC CONFIGURATION *** +// ------------------------------------------- + +// DSOUND +struct CONFIG_DSOUNDOUT +{ + char Device[256]; + s8 NumBuffers; + + CONFIG_DSOUNDOUT() : + NumBuffers( 3 ) + { + memset( Device, 0, sizeof( Device ) ); + } +}; + +// WAVEOUT +struct CONFIG_WAVEOUT +{ + char Device[255]; + s8 NumBuffers; + + CONFIG_WAVEOUT() : + NumBuffers( 4 ) + { + memset( Device, 0, sizeof( Device ) ); + } +}; + +// DSOUND51 +struct CONFIG_DSOUND51 +{ + char Device[256]; + u32 NumBuffers; + + u32 GainL; + u32 GainR; + u32 GainSL; + u32 GainSR; + u32 GainC; + u32 GainLFE; + u32 AddCLR; + u32 LowpassLFE; + + // C++ style struct/class initializer + CONFIG_DSOUND51() : + NumBuffers( 4 ) + , GainL( 256 ) + , GainR( 256 ) + , GainSL( 200 ) + , GainSR( 200 ) + , GainC( 200 ) + , GainLFE( 256 ) + , AddCLR( 56 ) + , LowpassLFE( 80 ) + { + memset( Device, 0, sizeof( Device ) ); + } +}; + + +extern CONFIG_DSOUNDOUT Config_DSoundOut; +extern CONFIG_DSOUND51 Config_DSound51; +extern CONFIG_WAVEOUT Config_WaveOut; + + +////// + +void ReadSettings(); +void WriteSettings(); +void configure(); + +#endif // CONFIG_H_INCLUDED diff --git a/plugins/spu2ghz/src/Win32/dialogs.h b/plugins/spu2ghz/src/Win32/dialogs.h new file mode 100644 index 0000000000..71ed7c3c4d --- /dev/null +++ b/plugins/spu2ghz/src/Win32/dialogs.h @@ -0,0 +1,16 @@ +#pragma once + +#include "resource.h" +#include + +#define SET_CHECK(idc,value) SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,((value)==0)?BST_UNCHECKED:BST_CHECKED,0) +#define HANDLE_CHECK(idc,hvar) case idc: hvar=hvar?0:1; SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar==1)?BST_CHECKED:BST_UNCHECKED,0); break +#define HANDLE_CHECKNB(idc,hvar)case idc: hvar=hvar?0:1; SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar==1)?BST_CHECKED:BST_UNCHECKED,0) +#define ENABLE_CONTROL(idc,value) EnableWindow(GetDlgItem(hWnd,idc),value) + +#define INIT_SLIDER(idc,minrange,maxrange,tickfreq,pagesize,linesize) \ + SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMIN,FALSE,minrange); \ + SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMAX,FALSE,maxrange); \ + SendMessage(GetDlgItem(hWnd,idc),TBM_SETTICFREQ,tickfreq,0); \ + SendMessage(GetDlgItem(hWnd,idc),TBM_SETPAGESIZE,0,pagesize); \ + SendMessage(GetDlgItem(hWnd,idc),TBM_SETLINESIZE,0,linesize) diff --git a/plugins/spu2ghz/src/Win32/dsound51.cpp b/plugins/spu2ghz/src/Win32/dsound51.cpp new file mode 100644 index 0000000000..e783585d93 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/dsound51.cpp @@ -0,0 +1,690 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#define _WIN32_DCOM +#include "spu2.h" +#include "dialogs.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lowpass.h" + +#define ENABLE_DPLII + +struct ds_device_data { + char name[256]; + GUID guid; + bool hasGuid; +}; + +static ds_device_data devices[32]; +static int ndevs; +static GUID DevGuid; // currently employed GUID. +static bool haveGuid; + +extern HRESULT GUIDFromString(const char *str, LPGUID guid); + +class DSound51: public SndOutModule +{ +private: + # define MAX_BUFFER_COUNT 8 + + static const int PacketsPerBuffer = 1; + static const int BufferSize = SndOutPacketSize * PacketsPerBuffer * 3; + static const int BufferSizeBytes = BufferSize << 1; + + + FILE *voicelog; + + u32 numBuffers; // cached copy of our configuration setting. + int channel; + int myLastWrite; + + bool dsound_running; + HANDLE thread; + DWORD tid; + + IDirectSound8* dsound; + IDirectSoundBuffer8* buffer; + IDirectSoundNotify8* buffer_notify; + HANDLE buffer_events[MAX_BUFFER_COUNT]; + + WAVEFORMATEXTENSIBLE wfx; + + SndBuffer *buff; + + s32 LAccum; + s32 RAccum; + s32 ANum; + + s32 LBuff[128]; + s32 RBuff[128]; + + LPF_data lpf_l; + LPF_data lpf_r; + + void Convert(s16 *obuffer, s32 ValL, s32 ValR) + { + static u8 bufdone=1; + static s32 Gfl=0,Gfr=0; + + static s32 spdif_data[6]; + static s32 LMax=0,RMax=0; + + if(PlayMode&4) + { + spdif_get_samples(spdif_data); + } + else + { + spdif_data[0]=0; + spdif_data[1]=0; + spdif_data[2]=0; + spdif_data[3]=0; + spdif_data[4]=0; + spdif_data[5]=0; + } + +#ifdef ENABLE_DPLII +#ifdef USE_AVERAGING + LAccum+=abs(ValL); + RAccum+=abs(ValR); + ANum++; + + if(ANum>=512) + { + LMax=0;RMax=0; + + LAccum/=ANum; + RAccum/=ANum; + ANum=0; + + for(int i=0;i<127;i++) + { + LMax+=LBuff[i]; + RMax+=RBuff[i]; + LBuff[i]=LBuff[i+1]; + RBuff[i]=RBuff[i+1]; + } + LBuff[127]=LAccum; + RBuff[127]=RAccum; + LMax+=LAccum; + RMax+=RAccum; + + s32 TL = (LMax>>15)+1; + s32 TR = (RMax>>15)+1; + + Gfl=(RMax)/(TL); + Gfr=(LMax)/(TR); + + if(Gfl>255) Gfl=255; + if(Gfr>255) Gfr=255; + } +#else + + if(ValL>LMax) LMax = ValL; + if(-ValL>LMax) LMax = -ValL; + if(ValR>RMax) RMax = ValR; + if(-ValR>RMax) RMax = -ValR; + ANum++; + if(ANum>=128) + { + // shift into a 21 bit value + const u8 shift = SndOutVolumeShift-5; + + ANum=0; + LAccum = ((LAccum * 224) + (LMax>>shift))>>8; + RAccum = ((RAccum * 224) + (RMax>>shift))>>8; + + LMax=0; + RMax=0; + + if(LAccum<1) LAccum=1; + if(RAccum<1) RAccum=1; + + Gfl=(RAccum)*255/(LAccum); + Gfr=(LAccum)*255/(RAccum); + + int gMax = max(Gfl,Gfr); + + Gfl=Gfl*255/gMax; + Gfr=Gfr*255/gMax; + + if(Gfl>255) Gfl=255; + if(Gfr>255) Gfr=255; + if(Gfl<1) Gfl=1; + if(Gfr<1) Gfr=1; + } +#endif + + Gfr = 1; Gfl = 1; + + s32 L,R,C,LFE,SL,SR,LL,LR; + + extern double pow_2_31; + + // shift Values into 12 bits: + u8 shift2 = SndOutVolumeShift + 4; + + LL = (s32)(LPF(&lpf_l,(ValL>>shift2)/pow_2_31)*pow_2_31); + LR = (s32)(LPF(&lpf_r,(ValR>>shift2)/pow_2_31)*pow_2_31); + LFE = (LL + LR)>>4; + + C=(ValL+ValR)>>1; //16.8 + + ValL-=C;//16.8 + ValR-=C;//16.8 + + L=ValL>>SndOutVolumeShift; //16.0 + R=ValR>>SndOutVolumeShift; //16.0 + C=C>>SndOutVolumeShift; //16.0 + + s32 VL=(ValL>>4) * Gfl; //16.12 + s32 VR=(ValR>>4) * Gfr; + + SL=(VL/209 - VR/148)>>4; //16.0 (?) + SR=(VL/148 - VR/209)>>4; //16.0 (?) + + // increase surround stereo separation + int SC = (SL+SR)>>1; //16.0 + int SLd = SL - SC; //16.0 + int SRd = SL - SC; //16.0 + + SL = (SLd * 209 + SC * 148)>>8; //16.0 + SR = (SRd * 209 + SC * 148)>>8; //16.0 + + obuffer[0]=spdif_data[0] + (((L * Config_DSound51.GainL ) + (C * Config_DSound51.AddCLR))>>8); + obuffer[1]=spdif_data[1] + (((R * Config_DSound51.GainR ) + (C * Config_DSound51.AddCLR))>>8); + obuffer[2]=spdif_data[2] + (((C * Config_DSound51.GainC ))>>8); + obuffer[3]=spdif_data[3] + (((LFE * Config_DSound51.GainLFE))>>8); + obuffer[4]=spdif_data[4] + (((SL * Config_DSound51.GainSL ))>>8); + obuffer[5]=spdif_data[5] + (((SR * Config_DSound51.GainSR ))>>8); +#else + obuffer[0]=spdif_data[0]+(ValL>>8); + obuffer[1]=spdif_data[1]+(ValR>>8); + obuffer[2]=spdif_data[2]; + obuffer[3]=spdif_data[3]; + obuffer[4]=spdif_data[4]; + obuffer[5]=spdif_data[5]; +#endif + } + +# define STRFY(x) #x + +# define verifyc(x) if(Verifyc(x,STRFY(x))) return -1; + + static DWORD CALLBACK RThread(DSound51*obj) + { + return obj->Thread(); + } + + int __forceinline Verifyc(HRESULT hr,const char* fn) + { + if(FAILED(hr)) + { + SysMessage("ERROR: Call to %s Failed.",fn); + return -1; + } + return 0; + } + + DWORD Thread() + { + while( dsound_running ) + { + u32 rv = WaitForMultipleObjects(numBuffers,buffer_events,FALSE,200); + + s16* p1, *oldp1; + LPVOID p2; + DWORD s1,s2; + + u32 poffset=BufferSizeBytes * rv; + +#ifdef _DEBUG + verifyc(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0)); +#else + if( FAILED(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0) ) ) + { + fputs( " * SPU2 : Directsound Warning > Buffer lock failure. You may need to increase the DSound buffer count.\n", stderr ); + continue; + } +#endif + oldp1 = p1; + + for(int p=0; pReadSamples( temp ); + for(int j=0;jUnlock(oldp1,s1,p2,s2)); +#else + buffer->Unlock(oldp1,s1,p2,s2); +#endif + verifyc(buffer->Unlock(oldp1,s1,p2,s2)); + + // Set the write pointer to the beginning of the next block. + myLastWrite = (poffset + BufferSizeBytes) % (BufferSizeBytes*numBuffers); + } + return 0; + } + +public: + s32 Init(SndBuffer *sb) + { + buff = sb; + numBuffers = Config_DSound51.NumBuffers; + + // + // Initialize DSound + // + GUID cGuid; + bool success = false; + + if( (strlen(Config_DSound51.Device)>0)&&(!FAILED(GUIDFromString(Config_DSound51.Device,&cGuid)))) + { + if( !FAILED( DirectSoundCreate8(&cGuid,&dsound,NULL) ) ) + success = true; + } + + // if the GUID failed, just open up the default dsound driver: + if( !success ) + { + verifyc(DirectSoundCreate8(NULL,&dsound,NULL)); + } + + verifyc(dsound->SetCooperativeLevel(GetDesktopWindow(),DSSCL_PRIORITY)); + IDirectSoundBuffer* buffer_; + DSBUFFERDESC desc; + + // Set up WAV format structure. + + memset(&wfx, 0, sizeof(WAVEFORMATEX)); + wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfx.Format.nSamplesPerSec = SampleRate; + wfx.Format.nChannels=6; + wfx.Format.wBitsPerSample = 16; + wfx.Format.nBlockAlign = wfx.Format.nChannels*wfx.Format.wBitsPerSample/8; + wfx.Format.nAvgBytesPerSec = SampleRate * wfx.Format.nBlockAlign; + wfx.Format.cbSize=22; + wfx.Samples.wValidBitsPerSample=0; + wfx.dwChannelMask=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT; + wfx.SubFormat=KSDATAFORMAT_SUBTYPE_PCM; + + verifyc(dsound->SetSpeakerConfig(DSSPEAKER_5POINT1)); + + // Set up DSBUFFERDESC structure. + + memset(&desc, 0, sizeof(DSBUFFERDESC)); + desc.dwSize = sizeof(DSBUFFERDESC); + desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; + desc.dwBufferBytes = BufferSizeBytes * numBuffers; + desc.lpwfxFormat = &wfx.Format; + + desc.dwFlags |=DSBCAPS_LOCSOFTWARE; + desc.dwFlags|=DSBCAPS_GLOBALFOCUS; + + verifyc(dsound->CreateSoundBuffer(&desc,&buffer_,0)); + verifyc(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer)); + buffer_->Release(); + + verifyc(buffer->QueryInterface(IID_IDirectSoundNotify8,(void**)&buffer_notify)); + + DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT]; + + for(u32 i=0;iSetNotificationPositions(numBuffers,not); + + LPVOID p1=0,p2=0; + DWORD s1=0,s2=0; + + verifyc(buffer->Lock(0,desc.dwBufferBytes,&p1,&s1,&p2,&s2,0)); + assert(p2==0); + memset(p1,0,s1); + verifyc(buffer->Unlock(p1,s1,p2,s2)); + + LPF_init(&lpf_l,Config_DSound51.LowpassLFE,SampleRate); + LPF_init(&lpf_r,Config_DSound51.LowpassLFE,SampleRate); + + //Play the buffer ! + verifyc(buffer->Play(0,0,DSBPLAY_LOOPING)); + + // Start Thread + myLastWrite = 0; + dsound_running=true; + thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid); + SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL); + + return 0; + } + + void Close() + { + // Stop Thread + fprintf(stderr," * SPU2: Waiting for DSound thread to finish..."); + dsound_running=false; + + WaitForSingleObject(thread,INFINITE); + CloseHandle(thread); + + fprintf(stderr," Done.\n"); + + // + // Clean up + // + if( buffer != NULL ) + { + buffer->Stop(); + + for(u32 i=0;i=0) + { + SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0); + } + + INIT_SLIDER(IDC_LEFT_GAIN_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_RIGHT_GAIN_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_RLEFT_GAIN_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_RRIGHT_GAIN_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_CENTER_GAIN_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_LFE_SLIDER,0,512,64,16,8); + INIT_SLIDER(IDC_LR_CENTER_SLIDER,0,512,64,16,8); + + AssignSliderValue( hWnd, IDC_LEFT_GAIN_SLIDER, IDC_LEFT_GAIN_EDIT, Config_DSound51.GainL ); + AssignSliderValue( hWnd, IDC_RIGHT_GAIN_SLIDER, IDC_RIGHT_GAIN_EDIT, Config_DSound51.GainR ); + AssignSliderValue( hWnd, IDC_RLEFT_GAIN_SLIDER, IDC_RLEFT_GAIN_EDIT, Config_DSound51.GainSL ); + AssignSliderValue( hWnd, IDC_RRIGHT_GAIN_SLIDER, IDC_RRIGHT_GAIN_EDIT, Config_DSound51.GainSR ); + AssignSliderValue( hWnd, IDC_CENTER_GAIN_SLIDER, IDC_CENTER_GAIN_EDIT, Config_DSound51.GainC); + AssignSliderValue( hWnd, IDC_LFE_SLIDER, IDC_LFE_EDIT, Config_DSound51.GainLFE); + AssignSliderValue( hWnd, IDC_LR_CENTER_SLIDER, IDC_LR_CENTER_EDIT, Config_DSound51.AddCLR ); + + char temp[128]; + INIT_SLIDER( IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1 ); + SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_DSound51.NumBuffers); + sprintf_s(temp, 128, "%d (%d ms latency)",Config_DSound51.NumBuffers, 1000 / (96000 / (Config_DSound51.NumBuffers * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL2),temp); + break; + + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDOK: + { + int i = (int)SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_GETCURSEL,0,0); + + if(!devices[i].hasGuid) + { + Config_DSound51.Device[0]=0; // clear device name to "" + } + else + { + sprintf_s(Config_DSound51.Device,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + devices[i].guid.Data1, + devices[i].guid.Data2, + devices[i].guid.Data3, + devices[i].guid.Data4[0], + devices[i].guid.Data4[1], + devices[i].guid.Data4[2], + devices[i].guid.Data4[3], + devices[i].guid.Data4[4], + devices[i].guid.Data4[5], + devices[i].guid.Data4[6], + devices[i].guid.Data4[7] + ); + + Config_DSound51.NumBuffers = GetSliderValue( hWnd, IDC_BUFFERS_SLIDER ); + Config_DSound51.GainL = GetSliderValue( hWnd, IDC_LEFT_GAIN_SLIDER ); + Config_DSound51.GainR = GetSliderValue( hWnd, IDC_RIGHT_GAIN_SLIDER ); + Config_DSound51.GainSL = GetSliderValue( hWnd, IDC_RLEFT_GAIN_SLIDER ); + Config_DSound51.GainSR = GetSliderValue( hWnd, IDC_RRIGHT_GAIN_SLIDER ); + Config_DSound51.GainLFE = GetSliderValue( hWnd, IDC_LFE_SLIDER ); + Config_DSound51.GainC = GetSliderValue( hWnd, IDC_CENTER_GAIN_SLIDER ); + Config_DSound51.AddCLR = GetSliderValue( hWnd, IDC_LR_CENTER_SLIDER ); + + if( Config_DSound51.NumBuffers < 2 ) Config_DSound51.NumBuffers = 2; + if( Config_DSound51.NumBuffers > MAX_BUFFER_COUNT ) Config_DSound51.NumBuffers = MAX_BUFFER_COUNT; + } + } + EndDialog(hWnd,0); + break; + case IDCANCEL: + EndDialog(hWnd,0); + break; + default: + return FALSE; + } + break; + + case WM_HSCROLL: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch(wmId) { + //case TB_ENDTRACK: + //case TB_THUMBPOSITION: + case TB_LINEUP: + case TB_LINEDOWN: + case TB_PAGEUP: + case TB_PAGEDOWN: + wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); + case TB_THUMBTRACK: + if( wmEvent < 2 ) wmEvent = 2; + if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; + SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); + sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL2),temp); + break; + default: + return FALSE; + } + break; + + case WM_VSCROLL: + HANDLE_SCROLL_MESSAGE(IDC_LEFT_GAIN_SLIDER,IDC_LEFT_GAIN_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_RIGHT_GAIN_SLIDER,IDC_RIGHT_GAIN_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_RLEFT_GAIN_SLIDER,IDC_RLEFT_GAIN_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_RRIGHT_GAIN_SLIDER,IDC_RRIGHT_GAIN_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_CENTER_GAIN_SLIDER,IDC_CENTER_GAIN_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_LFE_SLIDER,IDC_LFE_EDIT); + HANDLE_SCROLL_MESSAGE(IDC_LR_CENTER_SLIDER,IDC_LR_CENTER_EDIT); + + default: + return FALSE; + } + return TRUE; + } + +public: + virtual void Configure(HWND parent) + { + INT_PTR ret; + ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND51),GetActiveWindow(),(DLGPROC)ConfigProc,1); + if(ret==-1) + { + MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); + return; + } + } + + s32 Test() const + { + return 0; + } + + bool Is51Out() const { return true; } + + int GetEmptySampleCount() const + { + DWORD play, write; + buffer->GetCurrentPosition( &play, &write ); + + // Note: Dsound's write cursor is bogus. Use our own instead: + + int empty = play - myLastWrite; + if( empty < 0 ) + empty = -empty; + + return empty / 6; + + } + + const char* GetIdent() const + { + return "dsound51"; + } + + const char* GetLongName() const + { + return "DSound 5.1 (Experimental)"; + } +} DS51; + +SndOutModule *DSound51Out=&DS51; \ No newline at end of file diff --git a/plugins/spu2ghz/src/Win32/dsoundout.cpp b/plugins/spu2ghz/src/Win32/dsoundout.cpp new file mode 100644 index 0000000000..fd00a3bc83 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/dsoundout.cpp @@ -0,0 +1,459 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#define _WIN32_DCOM +#include "spu2.h" +#include "dialogs.h" +#include +#include +#include +#include +#include +#include +#include +#include + +struct ds_device_data { + char name[256]; + GUID guid; + bool hasGuid; +}; + +static ds_device_data devices[32]; +static int ndevs; +static GUID DevGuid; // currently employed GUID. +static bool haveGuid; + +HRESULT GUIDFromString(const char *str, LPGUID guid) +{ + // "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" + + struct T{ // this is a hack because for some reason sscanf writes too much :/ + GUID g; + int k; + } t; + + int r = sscanf_s(str,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + &t.g.Data1, + &t.g.Data2, + &t.g.Data3, + &t.g.Data4[0], + &t.g.Data4[1], + &t.g.Data4[2], + &t.g.Data4[3], + &t.g.Data4[4], + &t.g.Data4[5], + &t.g.Data4[6], + &t.g.Data4[7] + ); + + if(r!=11) return -1; + + *guid = t.g; + return 0; +} + +class DSound: public SndOutModule +{ +private: + # define MAX_BUFFER_COUNT 8 + + static const int PacketsPerBuffer = 1; + static const int BufferSize = SndOutPacketSize * PacketsPerBuffer; + static const int BufferSizeBytes = BufferSize << 1; + + + FILE *voicelog; + + u32 numBuffers; // cached copy of our configuration setting. + int channel; + int myLastWrite; // last write position, in bytes + + bool dsound_running; + HANDLE thread; + DWORD tid; + + IDirectSound8* dsound; + IDirectSoundBuffer8* buffer; + IDirectSoundNotify8* buffer_notify; + HANDLE buffer_events[MAX_BUFFER_COUNT]; + + WAVEFORMATEX wfx; + + HANDLE waitEvent; + + SndBuffer *buff; + +# define STRFY(x) #x +# define verifyc(x) if(Verifyc(x,STRFY(x))) return -1; + + int __forceinline Verifyc(HRESULT hr,const char* fn) + { + if(FAILED(hr)) + { + SysMessage("ERROR: Call to %s Failed.",fn); + return -1; + } + return 0; + } + + static DWORD CALLBACK RThread(DSound*obj) + { + return obj->Thread(); + } + + DWORD CALLBACK Thread() + { + + while( dsound_running ) + { + u32 rv = WaitForMultipleObjects(numBuffers,buffer_events,FALSE,200); + + s16* p1, *oldp1; + LPVOID p2; + DWORD s1,s2; + + u32 poffset=BufferSizeBytes * rv; + +#ifdef _DEBUG + verifyc(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0)); +#else + if( FAILED(buffer->Lock(poffset,BufferSizeBytes,(LPVOID*)&p1,&s1,&p2,&s2,0) ) ) + { + fputs( " * SPU2 : Directsound Warning > Buffer lock failure. You may need to increase the DSound buffer count.\n", stderr ); + continue; + } +#endif + oldp1 = p1; + + for(int p=0; pReadSamples( p1 ); + +#ifndef PUBLIC + verifyc(buffer->Unlock(oldp1,s1,p2,s2)); +#else + buffer->Unlock(oldp1,s1,p2,s2); +#endif + // Set the write pointer to the beginning of the next block. + myLastWrite = (poffset + BufferSizeBytes) & ~BufferSizeBytes; + } + return 0; + } + +public: + s32 Init(SndBuffer *sb) + { + buff = sb; + numBuffers = Config_DSoundOut.NumBuffers; + + // + // Initialize DSound + // + GUID cGuid; + bool success = false; + + if( (strlen(Config_DSoundOut.Device)>0)&&(!FAILED(GUIDFromString(Config_DSoundOut.Device,&cGuid)))) + { + if( !FAILED( DirectSoundCreate8(&cGuid,&dsound,NULL) ) ) + success = true; + } + + // if the GUID failed, just open up the default dsound driver: + if( !success ) + { + verifyc(DirectSoundCreate8(NULL,&dsound,NULL)); + } + + verifyc(dsound->SetCooperativeLevel(GetDesktopWindow(),DSSCL_PRIORITY)); + IDirectSoundBuffer* buffer_; + DSBUFFERDESC desc; + + // Set up WAV format structure. + + memset(&wfx, 0, sizeof(WAVEFORMATEX)); + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nSamplesPerSec = SampleRate; + wfx.nChannels=2; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = 2*2; + wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign; + wfx.cbSize=0; + + // Set up DSBUFFERDESC structure. + + memset(&desc, 0, sizeof(DSBUFFERDESC)); + desc.dwSize = sizeof(DSBUFFERDESC); + desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; + desc.dwBufferBytes = BufferSizeBytes * numBuffers; + desc.lpwfxFormat = &wfx; + + desc.dwFlags |=DSBCAPS_LOCSOFTWARE; + desc.dwFlags|=DSBCAPS_GLOBALFOCUS; + + verifyc(dsound->CreateSoundBuffer(&desc,&buffer_,0)); + verifyc(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer)); + buffer_->Release(); + + verifyc(buffer->QueryInterface(IID_IDirectSoundNotify8,(void**)&buffer_notify)); + + DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT]; + + for(u32 i=0;iSetNotificationPositions(numBuffers,not); + + LPVOID p1=0,p2=0; + DWORD s1=0,s2=0; + + verifyc(buffer->Lock(0,desc.dwBufferBytes,&p1,&s1,&p2,&s2,0)); + assert(p2==0); + memset(p1,0,s1); + verifyc(buffer->Unlock(p1,s1,p2,s2)); + + //Play the buffer ! + verifyc(buffer->Play(0,0,DSBPLAY_LOOPING)); + + // Start Thread + myLastWrite = 0; + dsound_running=true; + thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid); + SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL); + + return 0; + } + + void Close() + { + // Stop Thread + fprintf(stderr," * SPU2: Waiting for DSound thread to finish..."); + dsound_running=false; + + WaitForSingleObject(thread,INFINITE); + CloseHandle(thread); + + fprintf(stderr," Done.\n"); + + // + // Clean up + // + if( buffer != NULL ) + { + buffer->Stop(); + + for(u32 i=0;i=0) + { + SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0); + } + + char temp[128]; + INIT_SLIDER( IDC_BUFFERS_SLIDER, 2, MAX_BUFFER_COUNT, 2, 1, 1 ); + SendMessage(GetDlgItem(hWnd,IDC_BUFFERS_SLIDER),TBM_SETPOS,TRUE,Config_DSoundOut.NumBuffers); + sprintf_s(temp, 128, "%d (%d ms latency)",Config_DSoundOut.NumBuffers, 1000 / (96000 / (Config_DSoundOut.NumBuffers * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDOK: + { + int i = (int)SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_GETCURSEL,0,0); + + if(!devices[i].hasGuid) + { + Config_DSoundOut.Device[0] = 0; // clear device name to "" + } + else + { + sprintf_s(Config_DSoundOut.Device,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + devices[i].guid.Data1, + devices[i].guid.Data2, + devices[i].guid.Data3, + devices[i].guid.Data4[0], + devices[i].guid.Data4[1], + devices[i].guid.Data4[2], + devices[i].guid.Data4[3], + devices[i].guid.Data4[4], + devices[i].guid.Data4[5], + devices[i].guid.Data4[6], + devices[i].guid.Data4[7] + ); + } + + Config_DSoundOut.NumBuffers = (int)SendMessage( GetDlgItem( hWnd, IDC_BUFFERS_SLIDER ), TBM_GETPOS, 0, 0 ); + + if( Config_DSoundOut.NumBuffers < 2 ) Config_DSoundOut.NumBuffers = 2; + if( Config_DSoundOut.NumBuffers > MAX_BUFFER_COUNT ) Config_DSoundOut.NumBuffers = MAX_BUFFER_COUNT; + } + EndDialog(hWnd,0); + break; + case IDCANCEL: + EndDialog(hWnd,0); + break; + default: + return FALSE; + } + break; + + case WM_HSCROLL: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch(wmId) { + //case TB_ENDTRACK: + //case TB_THUMBPOSITION: + case TB_LINEUP: + case TB_LINEDOWN: + case TB_PAGEUP: + case TB_PAGEDOWN: + wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); + case TB_THUMBTRACK: + if( wmEvent < 2 ) wmEvent = 2; + if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; + SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); + sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + break; + default: + return FALSE; + } + break; + + default: + return FALSE; + } + return TRUE; + } + +public: + virtual void Configure(HWND parent) + { + INT_PTR ret; + ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND),GetActiveWindow(),(DLGPROC)ConfigProc,1); + if(ret==-1) + { + MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); + return; + } + } + + virtual bool Is51Out() const { return false; } + + s32 Test() const + { + return 0; + } + + int GetEmptySampleCount() const + { + DWORD play, write; + buffer->GetCurrentPosition( &play, &write ); + + // Note: Dsound's write cursor is bogus. Use our own instead: + + int empty = play - myLastWrite; + if( empty < 0 ) + empty = -empty; + + return empty / 2; + } + + const char* GetIdent() const + { + return "dsound"; + } + + const char* GetLongName() const + { + return "DirectSound (nice)"; + } + +} DS; + +SndOutModule *DSoundOut=&DS; diff --git a/plugins/spu2ghz/src/Win32/dsp.cpp b/plugins/spu2ghz/src/Win32/dsp.cpp new file mode 100644 index 0000000000..ca8fd681d4 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/dsp.cpp @@ -0,0 +1,174 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "spu2.h" + +extern "C" { +#include "dsp.h" + +typedef winampDSPHeader* (*pWinampDSPGetHeader2)(); +} + +HMODULE hLib = NULL; +pWinampDSPGetHeader2 pGetHeader = NULL; +winampDSPHeader* pHeader = NULL; + +winampDSPModule* pModule = NULL; + +HWND hTemp; + +#define USE_A_THREAD +#ifdef USE_A_THREAD + +HANDLE hUpdateThread; +DWORD UpdateThreadId; + +bool running; + +DWORD WINAPI DspUpdateThread(PVOID param); +#endif +s32 DspLoadLibrary(char *fileName, int modNum) +#ifdef USE_A_THREAD +{ + if(!dspPluginEnabled) return -1; + + running=true; + hUpdateThread = CreateThread(NULL,0,DspUpdateThread,NULL,0,&UpdateThreadId); + return (hUpdateThread==INVALID_HANDLE_VALUE); +} + +s32 DspLoadLibrary2(char *fileName, int modNum) +#endif +{ + if(!dspPluginEnabled) return -1; + + hLib = LoadLibraryA(fileName); + if(!hLib) + { + return 1; + } + + pGetHeader = (pWinampDSPGetHeader2)GetProcAddress(hLib,"winampDSPGetHeader2"); + + if(!pGetHeader) + { + FreeLibrary(hLib); + hLib=NULL; + return 1; + } + + pHeader = pGetHeader(); + + pModule = pHeader->getModule(modNum); + + if(!pModule) + { + pGetHeader=NULL; + pHeader=NULL; + FreeLibrary(hLib); + hLib=NULL; + return -1; + } + + pModule->hDllInstance = hLib; + pModule->hwndParent=0; + pModule->Init(pModule); + + return 0; +} + +void DspCloseLibrary() +#ifdef USE_A_THREAD +{ + if(!dspPluginEnabled) return ; + + PostThreadMessage(UpdateThreadId,WM_QUIT,0,0); + running=false; + if(WaitForSingleObject(hUpdateThread,1000)==WAIT_TIMEOUT) + { + TerminateThread(hUpdateThread,1); + } +} + +void DspCloseLibrary2() +#endif +{ + if(!dspPluginEnabled) return ; + + if(hLib) + { + pModule->Quit(pModule); + FreeLibrary(hLib); + } + pModule=NULL; + pHeader=NULL; + pGetHeader=NULL; + hLib=NULL; +} + +int DspProcess(s16 *buffer, int samples) +{ + if(!dspPluginEnabled) return samples; + + if(hLib) + { + return pModule->ModifySamples(pModule,buffer,samples,16,2,SampleRate); + } + return samples; +} + +void DspUpdate() +#ifdef USE_A_THREAD +{ +} + +DWORD WINAPI DspUpdateThread(PVOID param) +{ + if(!dspPluginEnabled) return -1; + + if(DspLoadLibrary2(dspPlugin,dspPluginModule)) + return -1; + + MSG msg; + while(running) + { + GetMessage(&msg,0,0,0); + if((msg.hwnd==NULL)&&(msg.message==WM_QUIT)) + { + break; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + DspCloseLibrary2(); + return 0; +} + +#else +{ + if(!dspPluginEnabled) return; + + MSG msg; + while(PeekMessage(&msg,0,0,0,PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +#endif \ No newline at end of file diff --git a/plugins/spu2ghz/src/Win32/dsp.h b/plugins/spu2ghz/src/Win32/dsp.h new file mode 100644 index 0000000000..d0675782d5 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/dsp.h @@ -0,0 +1,56 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +// DSP plugin interface + +// notes: +// any window that remains in foreground should optimally pass unused +// keystrokes to the parent (winamp's) window, so that the user +// can still control it. As for storing configuration, +// Configuration data should be stored in \plugin.ini +// (look at the vis plugin for configuration code) + +typedef struct winampDSPModule { + char *description; // description + HWND hwndParent; // parent window (filled in by calling app) + HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app) + + void (*Config)(struct winampDSPModule *this_mod); // configuration dialog (if needed) + int (*Init)(struct winampDSPModule *this_mod); // 0 on success, creates window, etc (if needed) + + // modify waveform samples: returns number of samples to actually write + // (typically numsamples, but no more than twice numsamples, and no less than half numsamples) + // numsamples should always be at least 128. should, but I'm not sure + int (*ModifySamples)(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate); + + void (*Quit)(struct winampDSPModule *this_mod); // called when unloading + + void *userData; // user data, optional +} winampDSPModule; + +typedef struct { + int version; // DSP_HDRVER + char *description; // description of library + winampDSPModule* (*getModule)(int); // module retrieval function +} winampDSPHeader; + +// exported symbols +typedef winampDSPHeader* (*winampDSPGetHeaderType)(); + +// header version: 0x20 == 0.20 == winamp 2.0 +#define DSP_HDRVER 0x20 diff --git a/plugins/spu2ghz/src/Win32/resource.h b/plugins/spu2ghz/src/Win32/resource.h new file mode 100644 index 0000000000..6c9cf14e7c --- /dev/null +++ b/plugins/spu2ghz/src/Win32/resource.h @@ -0,0 +1,86 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by SPU2ghz.rc +// +#define IDD_CONFIG 9 +#define IDD_DEBUG 105 +#define IDD_DSOUND 106 +#define IDD_DSOUND51 107 +#define IDD_ASIO 108 +#define IDD_WAVEOUT 109 +#define IDC_EFFECTS 1001 +#define IDC_DUMPREGS 1003 +#define IDC_DUMPMEM 1004 +#define IDC_DUMPCORE 1005 +#define IDC_LOGWAVE 1006 +#define IDC_LOGDMA 1007 +#define IDC_LOGREGS 1008 +#define IDC_DEBUG 1010 +#define IDC_INTERPOLATE 1011 +#define IDC_SRATE 1012 +#define IDC_OUTPUT 1013 +#define IDC_BUFFER 1014 +#define IDC_BUFFERS_SLIDER 1014 +#define IDC_BSIZE 1016 +#define IDC_BCOUNT 1018 +#define IDC_TEXT 1019 +#define IDC_MSGKEY 1020 +#define IDC_MSGDMA 1021 +#define IDC_MSGADMA 1022 +#define IDC_MSGVOICE 1023 +#define IDC_MSGSHOW 1024 +#define IDC_SPEEDLIMIT 1025 +#define IDC_OUTCONF 1028 +#define IDC_DSP_ENABLE 1029 +#define IDC_TS_ENABLE 1030 +#define IDC_DS_DEVICE 1032 +#define IDC_SLIDER1 1033 +#define IDC_LEFT_GAIN_SLIDER 1033 +#define IDC_SLIDER2 1034 +#define IDC_CENTER_GAIN_SLIDER 1034 +#define IDC_SLIDER3 1035 +#define IDC_RIGHT_GAIN_SLIDER 1035 +#define IDC_EDIT1 1036 +#define IDC_LEFT_GAIN_EDIT 1036 +#define IDC_BUTTON1 1037 +#define IDC_SHOW_DEBUG 1037 +#define IDC_DBG_OVERRUNS 1038 +#define IDC_SLIDER4 1039 +#define IDC_DBG_CACHE 1039 +#define IDC_RLEFT_GAIN_SLIDER 1039 +#define IDC_SLIDER5 1040 +#define IDC_DEBUG_GROUP 1040 +#define IDC_LFE_SLIDER 1040 +#define IDC_SLIDER6 1041 +#define IDC_LATENCY_SLIDER 1041 +#define IDC_RRIGHT_GAIN_SLIDER 1041 +#define IDC_SLIDER7 1042 +#define IDC_LATENCY_LABEL 1042 +#define ICD_LR_CENTER_SLIDER 1042 +#define IDC_LR_CENTER_SLIDER 1042 +#define IDC_EDIT2 1043 +#define IDC_CENTER_GAIN_EDIT 1043 +#define IDC_EDIT3 1044 +#define IDC_SPEEDLIMIT_RUNTIME_TOGGLE 1044 +#define IDC_RIGHT_GAIN_EDIT 1044 +#define IDC_EDIT4 1045 +#define IDC_RLEFT_GAIN_EDIT 1045 +#define IDC_EDIT5 1046 +#define IDC_LFE_EDIT 1046 +#define IDC_EDIT6 1047 +#define IDC_VOLBOOST 1047 +#define IDC_RRIGHT_GAIN_EDIT 1047 +#define IDC_EDIT7 1048 +#define IDC_LR_CENTER_EDIT 1048 +#define IDC_LATENCY_LABEL2 1049 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 110 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1048 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/spu2ghz/src/Win32/vsprops/pcsx2_plugin_common.vsprops b/plugins/spu2ghz/src/Win32/vsprops/pcsx2_plugin_common.vsprops new file mode 100644 index 0000000000..086133a60a --- /dev/null +++ b/plugins/spu2ghz/src/Win32/vsprops/pcsx2_plugin_common.vsprops @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/plugins/spu2ghz/src/Win32/vsprops/postBuild.tmpl b/plugins/spu2ghz/src/Win32/vsprops/postBuild.tmpl new file mode 100644 index 0000000000..b0f9fb472f --- /dev/null +++ b/plugins/spu2ghz/src/Win32/vsprops/postBuild.tmpl @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%\%3-r$WCREV$$WCMODS?m:$%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/spu2ghz/src/Win32/vsprops/postBuild.unknown b/plugins/spu2ghz/src/Win32/vsprops/postBuild.unknown new file mode 100644 index 0000000000..360b05cad5 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/vsprops/postBuild.unknown @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%%3%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/spu2ghz/src/Win32/vsprops/preBuild.cmd b/plugins/spu2ghz/src/Win32/vsprops/preBuild.cmd new file mode 100644 index 0000000000..fea16bd143 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/vsprops/preBuild.cmd @@ -0,0 +1,20 @@ +@echo off + +rem Usage: preBuild.cmd ProjectSrcDir VspropsDir +rem +rem ProjectSrcDir - $(ProjectDir)\.. - Directory of project source code. +rem VspropsDir - $(PrjectDir)\vsprops - Directory of this script and its counterparts. + +SubWCRev.exe %1 %2\svnrev_template.h %1\svnrev.h +if not ERRORLEVEL 0 ( + echo Automatic revision update unavailable, using generic template instead. + echo You can safely ignore this message - see svnrev.h for details. + copy /Y %2\svnrev_unknown.h %1\svnrev.h + copy /Y %2\postBuild.unknown %2\postBuild.cmd +) else ( + SubWCRev.exe %1 %2\postBuild.tmpl %2\postBuild.cmd +) + +rem Clear the error level -- this allows compilation to continue if SubWCRev failed. + +set ERRORLEVEL=0 diff --git a/plugins/spu2ghz/src/Win32/vsprops/svnrev_template.h b/plugins/spu2ghz/src/Win32/vsprops/svnrev_template.h new file mode 100644 index 0000000000..afab6c4fd1 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/vsprops/svnrev_template.h @@ -0,0 +1,18 @@ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ +#define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/spu2ghz/src/Win32/vsprops/svnrev_unknown.h b/plugins/spu2ghz/src/Win32/vsprops/svnrev_unknown.h new file mode 100644 index 0000000000..a2a3703186 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/vsprops/svnrev_unknown.h @@ -0,0 +1,23 @@ +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 +#define SVN_MODS "" \ No newline at end of file diff --git a/plugins/spu2ghz/src/Win32/xaudio2out.cpp b/plugins/spu2ghz/src/Win32/xaudio2out.cpp new file mode 100644 index 0000000000..e9dff1d767 --- /dev/null +++ b/plugins/spu2ghz/src/Win32/xaudio2out.cpp @@ -0,0 +1,235 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#define _WIN32_DCOM +#include "spu2.h" +#include +#include +#include +#include +#include +#include + +class XAudio2Mod: public SndOutModule +{ +private: + static const int PacketsPerBuffer = 1; + static const int BufferSize = SndOutPacketSize * PacketsPerBuffer; + static const int BufferSizeBytes = BufferSize * 2; + + s16* qbuffer; + s32 out_num; + +#define MAX_BUFFER_COUNT 3 + + //-------------------------------------------------------------------------------------- + // Callback structure + //-------------------------------------------------------------------------------------- + class StreamingVoiceContext : public IXAudio2VoiceCallback + { + public: + SndBuffer* sndout; + IXAudio2SourceVoice* pSourceVoice; + CRITICAL_SECTION cs; + + protected: + STDMETHOD_(void, OnVoiceProcessingPassStart) () {} + STDMETHOD_(void, OnVoiceProcessingPassStart) (UINT32) { }; + STDMETHOD_(void, OnVoiceProcessingPassEnd) () {} + STDMETHOD_(void, OnStreamEnd) () {} + STDMETHOD_(void, OnBufferStart) ( void* ) {} + STDMETHOD_(void, OnBufferEnd) ( void* context ) + { + EnterCriticalSection( &cs ); + + // All of these checks are necessary because XAudio2 is wonky shizat. + if( pSourceVoice == NULL || context == NULL ) return; + + s16* qb = (s16*)context; + + for(int p=0; pReadSamples( qb ); + + XAUDIO2_BUFFER buf = {0}; + buf.AudioBytes = BufferSizeBytes; + buf.pAudioData=(BYTE*)context; + buf.pContext=context; + + pSourceVoice->SubmitSourceBuffer( &buf ); + LeaveCriticalSection( &cs ); + } + STDMETHOD_(void, OnLoopEnd) ( void* ) {} + STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) { }; + + } voiceContext; + + IXAudio2* pXAudio2; + IXAudio2MasteringVoice* pMasteringVoice; + IXAudio2SourceVoice* pSourceVoice; + + WAVEFORMATEX wfx; + +public: + + s32 Init(SndBuffer *sb) + { + HRESULT hr; + + // + // Initialize XAudio2 + // + CoInitializeEx( NULL, COINIT_MULTITHREADED ); + + UINT32 flags = 0; +#ifdef _DEBUG + flags |= XAUDIO2_DEBUG_ENGINE; +#endif + + if ( FAILED(hr = XAudio2Create( &pXAudio2, flags ) ) ) + { + SysMessage( "Failed to init XAudio2 engine: %#X\n", hr ); + CoUninitialize(); + return -1; + } + + // + // Create a mastering voice + // + if ( FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasteringVoice, 0, SampleRate ) ) ) + { + SysMessage( "Failed creating mastering voice: %#X\n", hr ); + SAFE_RELEASE( pXAudio2 ); + CoUninitialize(); + return -1; + } + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nSamplesPerSec = SampleRate; + wfx.nChannels=2; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = 2*2; + wfx.nAvgBytesPerSec = SampleRate * wfx.nBlockAlign; + wfx.cbSize=0; + + InitializeCriticalSection( &voiceContext.cs ); + EnterCriticalSection( &voiceContext.cs ); + + // + // Create an XAudio2 voice to stream this wave + // + if( FAILED(hr = pXAudio2->CreateSourceVoice( &pSourceVoice, &wfx, + XAUDIO2_VOICE_NOSRC, 1.0f, &voiceContext ) ) ) + { + SysMessage( "Error %#X creating source voice\n", hr ); + SAFE_RELEASE( pXAudio2 ); + return -1; + } + + voiceContext.pSourceVoice = pSourceVoice; + voiceContext.sndout = sb; + pSourceVoice->FlushSourceBuffers(); + pSourceVoice->Start( 0, 0 ); + + qbuffer = new s16[BufferSize*MAX_BUFFER_COUNT]; + ZeroMemory(qbuffer,BufferSizeBytes*MAX_BUFFER_COUNT); + + // Start two buffers. + // Frankly two buffers is all we should ever need since the buffer fill code + // is tied directly to the XAudio2 engine. + + { + XAUDIO2_BUFFER buf = {0}; + buf.AudioBytes = BufferSizeBytes; + buf.pContext=qbuffer; + buf.pAudioData=(BYTE*)buf.pContext; + pSourceVoice->SubmitSourceBuffer( &buf ); + } + + { + XAUDIO2_BUFFER buf = {0}; + buf.AudioBytes = BufferSizeBytes; + buf.pContext=&qbuffer[BufferSize]; + buf.pAudioData=(BYTE*)buf.pContext; + pSourceVoice->SubmitSourceBuffer( &buf ); + } + LeaveCriticalSection( &voiceContext.cs ); + + return 0; + } + + void Close() + { + EnterCriticalSection( &voiceContext.cs ); + + // Clean up? + // All XAudio2 interfaces are released when the engine is destroyed, + // but being tidy never hurt. + + // Actually it can hurt. As of DXSDK Aug 2008, doing a full cleanup causes + // XA2 on Vista to crash. Even if you copy/paste code directly from Microsoft. + // But doing no cleanup at all causes XA2 under XP to crash. So after much trial + // and error we found a happy comprimise as follows: + + if( pSourceVoice != NULL ) + pSourceVoice->DestroyVoice(); + + if( pMasteringVoice != NULL ) + pMasteringVoice->DestroyVoice(); + + SAFE_RELEASE( pXAudio2 ); + SAFE_DELETE_ARRAY( qbuffer ); + + pMasteringVoice = NULL; + voiceContext.sndout = NULL; + voiceContext.pSourceVoice = NULL; + pSourceVoice = NULL; + LeaveCriticalSection( &voiceContext.cs ); + DeleteCriticalSection( &voiceContext.cs ); + CoUninitialize(); + } + + virtual void Configure(HWND parent) + { + } + + virtual bool Is51Out() const { return false; } + + s32 Test() const + { + return 0; + } + + int GetEmptySampleCount() const + { + XAUDIO2_VOICE_STATE state; + pSourceVoice->GetState( &state ); + return state.SamplesPlayed & (BufferSize-1); + } + + const char* GetIdent() const + { + return "xaudio2"; + } + + const char* GetLongName() const + { + return "XAudio 2 (Recommended)"; + } + +} XA2; + +SndOutModule *XAudio2Out=&XA2; diff --git a/plugins/spu2ghz/src/common/PS2Edefs.h b/plugins/spu2ghz/src/common/PS2Edefs.h new file mode 100644 index 0000000000..1f65fc02b9 --- /dev/null +++ b/plugins/spu2ghz/src/common/PS2Edefs.h @@ -0,0 +1,885 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/spu2ghz/src/common/PS2Etypes.h b/plugins/spu2ghz/src/common/PS2Etypes.h new file mode 100644 index 0000000000..59be1c3de4 --- /dev/null +++ b/plugins/spu2ghz/src/common/PS2Etypes.h @@ -0,0 +1,219 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/spu2ghz/src/debug.cpp b/plugins/spu2ghz/src/debug.cpp new file mode 100644 index 0000000000..3021619dc0 --- /dev/null +++ b/plugins/spu2ghz/src/debug.cpp @@ -0,0 +1,258 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include "spu2.h" + +int crazy_debug=0; + +char s[4096]; + +FILE *spu2Log; + +void FileLog(const char *fmt, ...) { +#ifdef SPU2_LOG + int n; + va_list list; + + if(!AccessLog()) return; + if(!spu2Log) return; + + va_start(list, fmt); + n=vsprintf(s,fmt, list); + va_end(list); + + fputs(s,spu2Log); + fflush(spu2Log); + +#if 0 + if(crazy_debug) + { + fputs(s,stderr); + fflush(stderr); + } +#endif +#endif +} + +void ConLog(const char *fmt, ...) { +#ifdef SPU2_LOG + int n; + va_list list; + + if(!MsgToConsole()) return; + + va_start(list, fmt); + n=vsprintf(s,fmt, list); + va_end(list); + + fputs(s,stderr); + fflush(stderr); + + if(spu2Log) + { + fputs(s,spu2Log); + fflush(spu2Log); + } +#endif +} + +void DoFullDump() { +#ifdef SPU2_LOG + FILE *dump; + u8 c=0, v=0; + + if(MemDump()) { + dump=fopen(MemDumpFileName,"wb"); + if (dump) { + fwrite(_spu2mem,0x200000,1,dump); + fclose(dump); + } + } + if(RegDump()) { + dump=fopen(RegDumpFileName,"wb"); + if (dump) { + fwrite(spu2regs,0x2000,1,dump); + fclose(dump); + } + } + + if(!CoresDump()) return; + dump=fopen(CoresDumpFileName,"wt"); + if (dump) { + for(c=0;c<2;c++) { + fprintf(dump,"#### CORE %d DUMP.\n",c); + fprintf(dump,"Master Volume for Left Channel: %x\n" + " - Value: %x\n" + " - Mode: %x\n" + " - Increment: %x\n", + Cores[c].MasterL.Reg_VOL, + Cores[c].MasterL.Value, + Cores[c].MasterL.Mode, + Cores[c].MasterL.Increment); + fprintf(dump,"Master Volume for Right Channel: %x\n" + " - Value: %x\n" + " - Mode: %x\n" + " - Increment: %x\n", + Cores[c].MasterR.Reg_VOL, + Cores[c].MasterR.Value, + Cores[c].MasterR.Mode, + Cores[c].MasterR.Increment); + fprintf(dump,"Volume for External Data Input (Left Channel): %x\n",Cores[c].ExtL); + fprintf(dump,"Volume for External Data Input (Right Channel): %x\n",Cores[c].ExtR); + fprintf(dump,"Volume for Sound Data Input (Left Channel): %x\n",Cores[c].InpL); + fprintf(dump,"Volume for Sound Data Input (Right Channel): %x\n",Cores[c].InpR); + fprintf(dump,"Volume for Output from Effects (Left Channel): %x\n",Cores[c].FxL); + fprintf(dump,"Volume for Output from Effects (Right Channel): %x\n",Cores[c].FxR); + fprintf(dump,"Interrupt Address: %x\n",Cores[c].IRQA); + fprintf(dump,"DMA Transfer Start Address: %x\n",Cores[c].TSA); + fprintf(dump,"External Input to Direct Output (Left): %s\n",Cores[c].ExtDryL?"Yes":"No"); + fprintf(dump,"External Input to Direct Output (Right): %s\n",Cores[c].ExtDryR?"Yes":"No"); + fprintf(dump,"External Input to Effects (Left): %s\n",Cores[c].ExtWetL?"Yes":"No"); + fprintf(dump,"External Input to Effects (Right): %s\n",Cores[c].ExtWetR?"Yes":"No"); + fprintf(dump,"Sound Data Input to Direct Output (Left): %s\n",Cores[c].SndDryL?"Yes":"No"); + fprintf(dump,"Sound Data Input to Direct Output (Right): %s\n",Cores[c].SndDryR?"Yes":"No"); + fprintf(dump,"Sound Data Input to Effects (Left): %s\n",Cores[c].SndWetL?"Yes":"No"); + fprintf(dump,"Sound Data Input to Effects (Right): %s\n",Cores[c].SndWetR?"Yes":"No"); + fprintf(dump,"Voice Data Input to Direct Output (Left): %s\n",Cores[c].InpDryL?"Yes":"No"); + fprintf(dump,"Voice Data Input to Direct Output (Right): %s\n",Cores[c].InpDryR?"Yes":"No"); + fprintf(dump,"Voice Data Input to Effects (Left): %s\n",Cores[c].InpWetL?"Yes":"No"); + fprintf(dump,"Voice Data Input to Effects (Right): %s\n",Cores[c].InpWetR?"Yes":"No"); + fprintf(dump,"IRQ Enabled: %s\n",Cores[c].IRQEnable?"Yes":"No"); + fprintf(dump,"Effects Enabled: %s\n",Cores[c].FxEnable?"Yes":"No"); + fprintf(dump,"Mute Enabled: %s\n",Cores[c].Mute?"Yes":"No"); + fprintf(dump,"Noise Clock: %d\n",Cores[c].NoiseClk); + fprintf(dump,"DMA Bits: %d\n",Cores[c].DMABits); + fprintf(dump,"Effects Start: %x\n",Cores[c].EffectsStartA); + fprintf(dump,"Effects End: %x\n",Cores[c].EffectsEndA); + fprintf(dump,"Registers:\n"); + fprintf(dump," - PMON: %x\n",Cores[c].Regs.PMON); + fprintf(dump," - NON: %x\n",Cores[c].Regs.NON); + fprintf(dump," - VMIXL: %x\n",Cores[c].Regs.VMIXL); + fprintf(dump," - VMIXR: %x\n",Cores[c].Regs.VMIXR); + fprintf(dump," - VMIXEL: %x\n",Cores[c].Regs.VMIXEL); + fprintf(dump," - VMIXER: %x\n",Cores[c].Regs.VMIXER); + fprintf(dump," - MMIX: %x\n",Cores[c].Regs.VMIXEL); + fprintf(dump," - ENDX: %x\n",Cores[c].Regs.VMIXER); + fprintf(dump," - STATX: %x\n",Cores[c].Regs.VMIXEL); + fprintf(dump," - ATTR: %x\n",Cores[c].Regs.VMIXER); + for(v=0;v<24;v++) { + fprintf(dump,"Voice %d:\n",v); + fprintf(dump," - Volume for Left Channel: %x\n" + " - Value: %x\n" + " - Mode: %x\n" + " - Increment: %x\n", + Cores[c].Voices[v].VolumeL.Reg_VOL, + Cores[c].Voices[v].VolumeL.Value, + Cores[c].Voices[v].VolumeL.Mode, + Cores[c].Voices[v].VolumeL.Increment); + fprintf(dump," - Volume for Right Channel: %x\n" + " - Value: %x\n" + " - Mode: %x\n" + " - Increment: %x\n", + Cores[c].Voices[v].VolumeR.Reg_VOL, + Cores[c].Voices[v].VolumeR.Value, + Cores[c].Voices[v].VolumeR.Mode, + Cores[c].Voices[v].VolumeR.Increment); + fprintf(dump," - ADSR Envelope: %x & %x\n" + " - Ar: %x\n" + " - Am: %x\n" + " - Dr: %x\n" + " - Sl: %x\n" + " - Sr: %x\n" + " - Sm: %x\n" + " - Rr: %x\n" + " - Rm: %x\n" + " - Phase: %x\n" + " - Value: %x\n", + Cores[c].Voices[v].ADSR.Reg_ADSR1, + Cores[c].Voices[v].ADSR.Reg_ADSR2, + Cores[c].Voices[v].ADSR.Ar, + Cores[c].Voices[v].ADSR.Am, + Cores[c].Voices[v].ADSR.Dr, + Cores[c].Voices[v].ADSR.Sl, + Cores[c].Voices[v].ADSR.Sr, + Cores[c].Voices[v].ADSR.Sm, + Cores[c].Voices[v].ADSR.Rr, + Cores[c].Voices[v].ADSR.Rm, + Cores[c].Voices[v].ADSR.Phase, + Cores[c].Voices[v].ADSR.Value); + fprintf(dump," - Pitch: %x\n",Cores[c].Voices[v].Pitch); + fprintf(dump," - Modulated: %s\n",Cores[c].Voices[v].Modulated?"Yes":"No"); + fprintf(dump," - Source: %s\n",Cores[c].Voices[v].Noise?"Noise":"Wave"); + fprintf(dump," - Direct Output for Left Channel: %s\n",Cores[c].Voices[v].DryL?"Yes":"No"); + fprintf(dump," - Direct Output for Right Channel: %s\n",Cores[c].Voices[v].DryR?"Yes":"No"); + fprintf(dump," - Effects Output for Left Channel: %s\n",Cores[c].Voices[v].WetL?"Yes":"No"); + fprintf(dump," - Effects Output for Right Channel: %s\n",Cores[c].Voices[v].WetR?"Yes":"No"); + fprintf(dump," - Loop Start Adress: %x\n",Cores[c].Voices[v].LoopStartA); + fprintf(dump," - Sound Start Adress: %x\n",Cores[c].Voices[v].StartA); + fprintf(dump," - Next Data Adress: %x\n",Cores[c].Voices[v].NextA); + fprintf(dump," - Play Start Cycle: %d\n",Cores[c].Voices[v].PlayCycle); + fprintf(dump," - Play Status: %s\n",(Cores[c].Voices[v].ADSR.Phase>0)?"Playing":"Not Playing"); + fprintf(dump," - Block Sample: %d\n",Cores[c].Voices[v].SCurrent); + } + fprintf(dump,"#### END OF DUMP.\n\n"); + } + } + fclose(dump); + dump=fopen("logs/effects.txt","wt"); + if (dump) { + for(c=0;c<2;c++) { + fprintf(dump,"#### CORE %d EFFECTS PROCESSOR DUMP.\n",c); + + fprintf(dump," - IN_COEF_L: %x\n",Cores[c].Revb.IN_COEF_R); + fprintf(dump," - IN_COEF_R: %x\n",Cores[c].Revb.IN_COEF_L); + + fprintf(dump," - FB_ALPHA: %x\n",Cores[c].Revb.FB_ALPHA); + fprintf(dump," - FB_X: %x\n",Cores[c].Revb.FB_X); + fprintf(dump," - FB_SRC_A: %x\n",Cores[c].Revb.FB_SRC_A); + fprintf(dump," - FB_SRC_B: %x\n",Cores[c].Revb.FB_SRC_B); + + fprintf(dump," - IIR_ALPHA: %x\n",Cores[c].Revb.IIR_ALPHA); + fprintf(dump," - IIR_COEF: %x\n",Cores[c].Revb.IIR_COEF); + fprintf(dump," - IIR_SRC_A0: %x\n",Cores[c].Revb.IIR_SRC_A0); + fprintf(dump," - IIR_SRC_A1: %x\n",Cores[c].Revb.IIR_SRC_A1); + fprintf(dump," - IIR_SRC_B1: %x\n",Cores[c].Revb.IIR_SRC_B0); + fprintf(dump," - IIR_SRC_B0: %x\n",Cores[c].Revb.IIR_SRC_B1); + fprintf(dump," - IIR_DEST_A0: %x\n",Cores[c].Revb.IIR_DEST_A0); + fprintf(dump," - IIR_DEST_A1: %x\n",Cores[c].Revb.IIR_DEST_A1); + fprintf(dump," - IIR_DEST_B0: %x\n",Cores[c].Revb.IIR_DEST_B0); + fprintf(dump," - IIR_DEST_B1: %x\n",Cores[c].Revb.IIR_DEST_B1); + + fprintf(dump," - ACC_COEF_A: %x\n",Cores[c].Revb.ACC_COEF_A); + fprintf(dump," - ACC_COEF_B: %x\n",Cores[c].Revb.ACC_COEF_B); + fprintf(dump," - ACC_COEF_C: %x\n",Cores[c].Revb.ACC_COEF_C); + fprintf(dump," - ACC_COEF_D: %x\n",Cores[c].Revb.ACC_COEF_D); + fprintf(dump," - ACC_SRC_A0: %x\n",Cores[c].Revb.ACC_SRC_A0); + fprintf(dump," - ACC_SRC_A1: %x\n",Cores[c].Revb.ACC_SRC_A1); + fprintf(dump," - ACC_SRC_B0: %x\n",Cores[c].Revb.ACC_SRC_B0); + fprintf(dump," - ACC_SRC_B1: %x\n",Cores[c].Revb.ACC_SRC_B1); + fprintf(dump," - ACC_SRC_C0: %x\n",Cores[c].Revb.ACC_SRC_C0); + fprintf(dump," - ACC_SRC_C1: %x\n",Cores[c].Revb.ACC_SRC_C1); + fprintf(dump," - ACC_SRC_D0: %x\n",Cores[c].Revb.ACC_SRC_D0); + fprintf(dump," - ACC_SRC_D1: %x\n",Cores[c].Revb.ACC_SRC_D1); + + fprintf(dump," - MIX_DEST_A0: %x\n",Cores[c].Revb.MIX_DEST_A0); + fprintf(dump," - MIX_DEST_A1: %x\n",Cores[c].Revb.MIX_DEST_A1); + fprintf(dump," - MIX_DEST_B0: %x\n",Cores[c].Revb.MIX_DEST_B0); + fprintf(dump," - MIX_DEST_B1: %x\n",Cores[c].Revb.MIX_DEST_B1); + fprintf(dump,"#### END OF DUMP.\n\n"); + } + fclose(dump); + } +#endif +} diff --git a/plugins/spu2ghz/src/debug.h b/plugins/spu2ghz/src/debug.h new file mode 100644 index 0000000000..319bdcd5ed --- /dev/null +++ b/plugins/spu2ghz/src/debug.h @@ -0,0 +1,36 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#ifndef DEBUG_H_INCLUDED +#define DEBUG_H_INCLUDED + +extern FILE *spu2Log; + +void FileLog(const char *fmt, ...); +void ConLog(const char *fmt, ...); + +void DoFullDump(); + +extern int wavedump_ok; + +int wavedump_open(); +void wavedump_close(); +void wavedump_write(s16 left,s16 right); + + +#endif // DEBUG_H_INCLUDED // diff --git a/plugins/spu2ghz/src/decoder.cpp b/plugins/spu2ghz/src/decoder.cpp new file mode 100644 index 0000000000..fa4482a472 --- /dev/null +++ b/plugins/spu2ghz/src/decoder.cpp @@ -0,0 +1,385 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "spu2.h" + +extern "C" { +#include "liba52/inttypes.h" +#include "liba52/a52.h" +#include "liba52/mm_accel.h" +} + +extern u32 spdif_read_data(u8 *buff, u32 max_data); + +#define DATA_SIZE 0x100000 + +u32 use51=0; + +u8 databuffer[DATA_SIZE]; +u32 data_in_buffer; + +s32 output_buffer[0x10000][6]; +s32 output_write_cursor=0; +s32 output_read_cursor=0; +s32 output_buffer_data=0; + +int flags,srate,bitrate; + +#define CHANNEL_CENTER 1 +#define CHANNEL_STEREO 2 +#define CHANNEL_SURROUND 4 +#define CHANNEL_LFE 8 + +int sample_flags = 0; + +u32 frame_size; + +a52_state_t* ac3dec; +sample_t *decode_buffer = NULL; + +s32 data_rate=4; + +int state=0; + +FILE *fSpdifDump; + +extern u32 core; +void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR); + +union spdif_frame { // total size: 32bits + struct { + u32 preamble:4; //4 + u32 databits:24; //28 + u32 valid:1; //29 + u32 subcode:1; //30 + u32 chanstat:1; //31 + u32 parity:1; //32 // parity not including preamble + } bits; + u32 whole; +}; + +union spdif_block { + spdif_frame frames[192]; + u8 bytes [192*4]; +}; + +/* +spdif_block bbuffer[2]; +u8 *bbuff = bbuffer[0].bytes; +u32 bbuff_bytes = 0; +*/ + +bool check_frame(spdif_frame f) +{ + u32 w = f.whole>>4; + u32 t = 0; + + for(int i=0;i>28;i++) + { + t=t^(w&1); + w>>=1; + } + + return (t==0)&&(f.bits.valid); +} + +void spdif_Write(s32 data) +{ + spdif_frame f; + + f.whole=data; + + if(check_frame(f)) + { + int dec = f.bits.databits; + databuffer[data_in_buffer++]=(dec )&0xFF; + databuffer[data_in_buffer++]=(dec>> 8)&0xFF; + databuffer[data_in_buffer++]=(dec>>16)&0xFF; + } +} + +void spdif_remove_data(unsigned int bytes) +{ + if(bytes0)*-1; //1 if positive, -1 if negative, 0 otherwise + n=abs(n)+1; //make it [1..2] + s32 k=*(s32*)&n; + k=k&0x7FFFFF; + return k*sign; +} + +void spdif_update() +{ + s32 Data,Zero; + + core=0; + V_Core& thiscore( Cores[core] ); + for(int i=0;i +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#ifndef DEFS_H_INCLUDED +#define DEFS_H_INCLUDED + +typedef enum {SPU2_VOL_MODE_CONST,SPU2_VOL_MODE_PLIN,SPU2_VOL_MODE_NLIN,SPU2_VOL_MODE_PLOG,SPU2_VOL_MODE_NLOG} V_VolMode; + +typedef struct { + u16 Reg_VOL; + s16 Value; //also Reg_VOLX + s8 Increment; + s8 Mode; +} V_Volume; + +typedef struct { + u16 Reg_ADSR1; + u16 Reg_ADSR2; +//also Reg_ENVX + s32 Value; // [Air] : Ranges from 0 to 0x7fffffff (signed values are clamped to 0) +// Phase + u8 Phase; +//Attack Rate + u8 Ar; +//Attack Mode + u8 Am; +//Decay Rate + u8 Dr; +//Sustain Level + u8 Sl; +//Sustain Rate + u8 Sr; +//Sustain Mode + u8 Sm; +//Release Rate + u8 Rr; +//Release Mode + u8 Rm; +//Ready To Release + u8 Releasing; +} V_ADSR; + + +typedef struct { +// SPU2 cycle where the Playing started + u32 PlayCycle; +// Left Volume + V_Volume VolumeL; +// Right Volume + V_Volume VolumeR; +// Envelope + V_ADSR ADSR; +// Pitch (also Reg_PITCH) + s16 Pitch; +// Pitch Modulated by previous voice + s8 Modulated; +// Source (Wave/Noise) + s8 Noise; +// Direct Output for Left Channel + s8 DryL; +// Direct Output for Right Channel + s8 DryR; +// Effect Output for Left Channel + s8 WetL; +// Effect Output for Right Channel + s8 WetR; +// Loop Start Adress (also Reg_LSAH/L) + u32 LoopStartA; +// Sound Start Adress (also Reg_SSAH/L) + u32 StartA; +// Next Read Data Adress (also Reg_NAXH/L) + u32 NextA; +// Voice Decoding State + s32 Prev1; + s32 Prev2; + + s8 LoopMode; + s8 LoopFlags; + +// [Air] : Replaced loop flags read from the ADPCM header with +// a single LoopFlags value (above) -- more cache-friendly. + //s8 LoopStart; + //s8 Loop; + //s8 LoopEnd; + +// Sample pointer (19:12 bit fixed point) + s32 SP; + +// Sample pointer for Cubic Interpolation +// Cubic interpolation mixes a sample behind Linear, so that it +// can have sample data to either side of the end points from which +// to extrapolate. This SP represents that late sample position. + s32 SPc; + +// Previous sample values - used for interpolation +// [Air] : Inverted order of these members to match the access order in the +// code (might improve cache hits). + s32 PV4; + s32 PV3; + s32 PV2; + s32 PV1; + +// Last outputted audio value, used for voice modulation. + s32 OutX; + +// SBuffer now points directly to an ADPCM cache entry. + s16 *SBuffer; + +// sample position within the current decoded packet. + s32 SCurrent; + +} V_Voice; + +#ifndef PUBLIC +// ** Begin Debug-only variables section ** +// Separated from the V_Voice struct to improve cache performance of +// the Public Release build. +struct V_VoiceDebug +{ + s8 FirstBlock; + s32 SampleData; + s32 PeakX; + s32 displayPeak; + s32 lastSetStartA; + s32 lastStopReason; +}; + +struct V_CoreDebug +{ + V_VoiceDebug Voices[24]; + s32 AutoDMAPeak; +// Last Transfer Size + u32 lastsize; +}; + +// Debug tracking information - 24 voices and 2 cores. +extern V_CoreDebug DebugCores[2]; +#endif + +typedef struct { + u16 IN_COEF_L; + u16 IN_COEF_R; + u32 FB_SRC_A; + u32 FB_SRC_B; + u16 FB_ALPHA; + u16 FB_X; + u32 IIR_SRC_A0; + u32 IIR_SRC_A1; + u32 IIR_SRC_B1; + u32 IIR_SRC_B0; + u32 IIR_DEST_A0; + u32 IIR_DEST_A1; + u32 IIR_DEST_B0; + u32 IIR_DEST_B1; + u16 IIR_ALPHA; + u16 IIR_COEF; + u32 ACC_SRC_A0; + u32 ACC_SRC_A1; + u32 ACC_SRC_B0; + u32 ACC_SRC_B1; + u32 ACC_SRC_C0; + u32 ACC_SRC_C1; + u32 ACC_SRC_D0; + u32 ACC_SRC_D1; + u16 ACC_COEF_A; + u16 ACC_COEF_B; + u16 ACC_COEF_C; + u16 ACC_COEF_D; + u32 MIX_DEST_A0; + u32 MIX_DEST_A1; + u32 MIX_DEST_B0; + u32 MIX_DEST_B1; +} V_Reverb; + +typedef struct { + u16 Out; + u16 Info; + u16 Unknown1; + u16 Mode; + u16 Media; + u16 Unknown2; + u16 Protection; +} V_SPDIF; + +typedef struct { + u32 PMON; + u32 NON; + u32 VMIXL; + u32 VMIXR; + u32 VMIXEL; + u32 VMIXER; + u16 MMIX; + u32 ENDX; + u16 STATX; + u16 ATTR; + u16 _1AC; +} V_CoreRegs; + +typedef struct { +// Core Voices + V_Voice Voices[24]; +// Master Volume for Left Channel + V_Volume MasterL; +// Master Volume for Right Channel + V_Volume MasterR; +// Volume for External Data Input (Left Channel) + u16 ExtL; +// Volume for External Data Input (Right Channel) + u16 ExtR; +// Volume for Sound Data Input (Left Channel) + u16 InpL; +// Volume for Sound Data Input (Right Channel) + u16 InpR; +// Volume for Output from Effects (Left Channel) + u16 FxL; +// Volume for Output from Effects (Right Channel) + u16 FxR; +// Interrupt Address + u32 IRQA; +// DMA Transfer Start Address + u32 TSA; +// DMA Transfer Data Address (Internal...) + u32 TDA; +// External Input to Direct Output (Left) + s8 ExtDryL; +// External Input to Direct Output (Right) + s8 ExtDryR; +// External Input to Effects (Left) + s8 ExtWetL; +// External Input to Effects (Right) + s8 ExtWetR; +// Sound Data Input to Direct Output (Left) + s8 InpDryL; +// Sound Data Input to Direct Output (Right) + s8 InpDryR; +// Sound Data Input to Effects (Left) + s8 InpWetL; +// Sound Data Input to Effects (Right) + s8 InpWetR; +// Voice Data to Direct Output (Left) + s8 SndDryL; +// Voice Data to Direct Output (Right) + s8 SndDryR; +// Voice Data to Effects (Left) + s8 SndWetL; +// Voice Data to Effects (Right) + s8 SndWetR; +// Interrupt Enable + s8 IRQEnable; +// DMA related? + s8 DMABits; +// Effect Enable + s8 FxEnable; +// Noise Clock + s8 NoiseClk; +// AutoDMA Status + u16 AutoDMACtrl; +// DMA Interrupt Counter + s32 DMAICounter; +// Mute + s8 Mute; +// Input Buffer + u32 InputDataLeft; + u32 InputPos; + u32 InputDataProgress; + u8 AdmaInProgress; + +// Reverb + V_Reverb Revb; + u32 EffectsStartA; + u32 EffectsEndA; + u32 ReverbX; +// Registers + V_CoreRegs Regs; + + u8 InitDelay; + + u8 CoreEnabled; + + u8 AttrBit0; + u8 AttrBit4; + u8 AttrBit5; + + u16*DMAPtr; + u32 MADR; + u32 TADR; + + s16 ADMATempBuffer[0x1000]; + + u32 ADMAPV; + u32 ADMAPL; + u32 ADMAPR; + +} V_Core; + +extern V_Core Cores[2]; +extern V_SPDIF Spdif; + +// Output Buffer Writing Position (the same for all data); +extern s16 OutPos; +// Input Buffer Reading Position (the same for all data); +extern s16 InputPos; +// SPU Mixing Cycles ("Ticks mixed" counter) +extern u32 Cycles; +extern u8 InpBuff; +// 1b0 "hack" +extern u32 Num; + + +#endif // DEFS_H_INCLUDED // diff --git a/plugins/spu2ghz/src/dma.cpp b/plugins/spu2ghz/src/dma.cpp new file mode 100644 index 0000000000..b9e85739ea --- /dev/null +++ b/plugins/spu2ghz/src/dma.cpp @@ -0,0 +1,510 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "spu2.h" + +extern u8 callirq; + +FILE *DMA4LogFile=0; +FILE *DMA7LogFile=0; +FILE *ADMA4LogFile=0; +FILE *ADMA7LogFile=0; +FILE *ADMAOutLogFile=0; + +FILE *REGWRTLogFile[2]={0,0}; + +int packcount=0; + +u16* MBASE[2] = {0,0}; + +u16* DMABaseAddr; + +void DMALogOpen() { + if(!DMALog()) return; + DMA4LogFile=fopen(DMA4LogFileName,"wb"); + DMA7LogFile=fopen(DMA7LogFileName,"wb"); + ADMA4LogFile=fopen("logs/adma4.raw","wb"); + ADMA7LogFile=fopen("logs/adma7.raw","wb"); + ADMAOutLogFile=fopen("logs/admaOut.raw","wb"); + //REGWRTLogFile[0]=fopen("logs/RegWrite0.raw","wb"); + //REGWRTLogFile[1]=fopen("logs/RegWrite1.raw","wb"); +} +void DMA4LogWrite(void *lpData, u32 ulSize) { + if(!DMALog()) return; + if (!DMA4LogFile) return; + fwrite(lpData,ulSize,1,DMA4LogFile); +} + +void DMA7LogWrite(void *lpData, u32 ulSize) { + if(!DMALog()) return; + if (!DMA7LogFile) return; + fwrite(lpData,ulSize,1,DMA7LogFile); +} + +void ADMA4LogWrite(void *lpData, u32 ulSize) { + if(!DMALog()) return; + if (!ADMA4LogFile) return; + fwrite(lpData,ulSize,1,ADMA4LogFile); +} +void ADMA7LogWrite(void *lpData, u32 ulSize) { + if(!DMALog()) return; + if (!ADMA7LogFile) return; + fwrite(lpData,ulSize,1,ADMA7LogFile); +} +void ADMAOutLogWrite(void *lpData, u32 ulSize) { + if(!DMALog()) return; + if (!ADMAOutLogFile) return; + fwrite(lpData,ulSize,1,ADMAOutLogFile); +} + +void RegWriteLog(u32 core,u16 value) +{ + if(!DMALog()) return; + if (!REGWRTLogFile[core]) return; + fwrite(&value,2,1,REGWRTLogFile[core]); +} + +void DMALogClose() { + if(!DMALog()) return; + if (DMA4LogFile) fclose(DMA4LogFile); + if (DMA7LogFile) fclose(DMA7LogFile); + if (REGWRTLogFile[0]) fclose(REGWRTLogFile[0]); + if (REGWRTLogFile[1]) fclose(REGWRTLogFile[1]); + if (ADMA4LogFile) fclose(ADMA4LogFile); + if (ADMA7LogFile) fclose(ADMA7LogFile); + if (ADMAOutLogFile) fclose(ADMAOutLogFile); +} + + +__forceinline u16 DmaRead(u32 core) +{ + const u16 ret = (u16)spu2M_Read(Cores[core].TDA); + Cores[core].TDA++; + Cores[core].TDA&=0xfffff; + return ret; +} + +__forceinline void DmaWrite(u32 core, u16 value) +{ + spu2M_Write( Cores[core].TSA, value ); + Cores[core].TSA++; + Cores[core].TSA&=0xfffff; +} + +void AutoDMAReadBuffer(int core, int mode) //mode: 0= split stereo; 1 = do not split stereo +{ + int spos=((Cores[core].InputPos+0xff)&0x100); //starting position of the free buffer + + if(core==0) + ADMA4LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400); + else + ADMA7LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400); + + if(mode) + { + //hacky :p + + memcpy((Cores[core].ADMATempBuffer+(spos<<1)),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400); + Cores[core].MADR+=0x400; + Cores[core].InputDataLeft-=0x200; + Cores[core].InputDataProgress+=0x200; + } + else + { + memcpy((Cores[core].ADMATempBuffer+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); + //memcpy((spu2mem+0x2000+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); + Cores[core].MADR+=0x200; + Cores[core].InputDataLeft-=0x100; + Cores[core].InputDataProgress+=0x100; + + memcpy((Cores[core].ADMATempBuffer+spos+0x200),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); + //memcpy((spu2mem+0x2200+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200); + Cores[core].MADR+=0x200; + Cores[core].InputDataLeft-=0x100; + Cores[core].InputDataProgress+=0x100; + } + // See ReadInput at mixer.cpp for explanation on the commented out lines + // +} + +void StartADMAWrite(int core,u16 *pMem, u32 sz) +{ + int size=(sz)&(~511); + + if(MsgAutoDMA()) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n", + (core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); + + Cores[core].InputDataProgress=0; + if((Cores[core].AutoDMACtrl&(core+1))==0) + { + Cores[core].TSA=0x2000+(core<<10); + Cores[core].DMAICounter=size; + } + else if(size>=512) + { + Cores[core].InputDataLeft=size; + if(Cores[core].AdmaInProgress==0) + { +#ifdef PCM24_S1_INTERLEAVE + if((core==1)&&((PlayMode&8)==8)) + { + AutoDMAReadBuffer(core,1); + } + else + { + AutoDMAReadBuffer(core,0); + } +#else + if(((PlayMode&4)==4)&&(core==0)) + Cores[0].InputPos=0; + + AutoDMAReadBuffer(core,0); +#endif + + if(size==512) + Cores[core].DMAICounter=size; + } + + Cores[core].AdmaInProgress=1; + } + else + { + Cores[core].InputDataLeft=0; + Cores[core].DMAICounter=1; + } + Cores[core].TADR=Cores[core].MADR+(size<<1); +} + +void DoDMAWrite(int core,u16 *pMem,u32 size) +{ + // Perform an alignment check. + // Not really important. Everything should work regardless, + // but it could be indicative of an emulation foopah elsewhere. + +#if 0 + uptr pa = ((uptr)pMem)&7; + uptr pm = Cores[core].TSA&0x7; + + if( pa ) + { + fprintf(stderr, "* SPU2 DMA Write > Missaligned SOURCE! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size); + } + + if( pm ) + { + fprintf(stderr, "* SPU2 DMA Write > Missaligned TARGET! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size ); + } +#endif + + if(core==0) + DMA4LogWrite(pMem,size<<1); + else + DMA7LogWrite(pMem,size<<1); + + if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); + + Cores[core].TSA &= 0xfffff; + + u32 buff1end = Cores[core].TSA + size; + u32 buff2end=0; + if( buff1end > 0x100000 ) + { + buff2end = buff1end - 0x100000; + buff1end = 0x100000; + } + + const int cacheIdxStart = Cores[core].TSA / pcm_WordsPerBlock; + const int cacheIdxEnd = (buff1end+pcm_WordsPerBlock-1) / pcm_WordsPerBlock; + PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart]; + PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd]; + + do + { + cacheLine->Validated = false; + cacheLine++; + } while ( cacheLine != &cacheEnd ); + +#if 0 + // Pcm Cache Invalidation! + // It's a requirement that we mask bits for the blocks that are written to *only*, + // because doing anything else can cause the cache to fail, thanks to the progressive + // nature of the SPU2's ADPCM encoding. (the same thing that makes it impossible + // to use SSE optimizations on it). + + u8* cache = (u8*)pcm_cache_flags; + + // Step 1: Clear bits in the front remainder. + + const int pcmTSA = Cores[core].TSA / pcm_WordsPerBlock; + const int pcmTDA = buff1end / pcm_WordsPerBlock; + const int remFront = pcmTSA & 31; + const int remBack = ((buff1end+pcm_WordsPerBlock-1)/pcm_WordsPerBlock) & 31; // round up to get the end remainder + + int flagTSA = pcmTSA / 32; + + if( remFront ) + { + // need to clear some upper bits of this u32 + uint mask = (1ul< 0 ) + { + // second branch needs copied: + // It starts at the beginning of memory and moves forward to buff2end + + // endpoint cache should be irrelevant, since it's almost certainly dynamic + // memory below 0x2800 (registers and such) + //const u32 endpt2 = (buff2end + roundUp) / indexer_scalar; + //memset( pcm_cache_flags, 0, endpt2 ); + + memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 ); + + Cores[core].TDA = (buff2end+1) & 0xfffff; + + if(Cores[core].IRQEnable) + { + // Flag interrupt? + // If IRQA occurs between start and dest, flag it. + // Since the buffer wraps, the conditional might seem odd, but it works. + + if( ( Cores[core].IRQA >= Cores[core].TSA ) || + ( Cores[core].IRQA <= Cores[core].TDA ) ) + { + Spdif.Info=4<= Cores[core].TSA ) && + ( Cores[core].IRQA <= Cores[core].TDA ) ) + { + Spdif.Info=4< 0x100000 ) + { + buff2end = buff1end - 0x100000; + buff1end = 0x100000; + } + + const u32 buff1size = (buff1end-Cores[core].TSA); + memcpy( pMem, GetMemPtr( Cores[core].TSA ), buff1size*2 ); + + if( buff2end > 0 ) + { + // second branch needs cleared: + // It starts at the beginning of memory and moves forward to buff2end + + memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 ); + + Cores[core].TDA = (buff2end+0x20) & 0xfffff; + + for( int i=0; i<2; i++ ) + { + if(Cores[i].IRQEnable) + { + // Flag interrupt? + // If IRQA occurs between start and dest, flag it. + // Since the buffer wraps, the conditional might seem odd, but it works. + + if( ( Cores[i].IRQA >= Cores[core].TSA ) || + ( Cores[i].IRQA <= Cores[core].TDA ) ) + { + Spdif.Info=4<= Cores[i].TSA ) && + ( Cores[i].IRQA <= Cores[i].TDA+0x1f ) ) + { + Spdif.Info=4< +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef DMA_H_INCLUDED +#define DMA_H_INCLUDED + +void DMALogOpen(); +void DMA4LogWrite(void *lpData, u32 ulSize); +void DMA7LogWrite(void *lpData, u32 ulSize); +void DMALogClose(); + +extern void DmaWrite(u32 core, u16 data); +extern u16 DmaRead(u32 core); + +extern void AutoDMAReadBuffer(int core, int mode); + +#endif // DMA_H_INCLUDED // \ No newline at end of file diff --git a/plugins/spu2ghz/src/lowpass.cpp b/plugins/spu2ghz/src/lowpass.cpp new file mode 100644 index 0000000000..6ea46d3462 --- /dev/null +++ b/plugins/spu2ghz/src/lowpass.cpp @@ -0,0 +1,67 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "lowpass.h" +#include +#include + +void LPF_init(LPF_data*lpf,double freq, double srate) +{ + double omega = 2*freq/srate; + double g = 1.0; + + // calculating coefficients: + + double k,p,q,a; + double a0,a1,a2,a3,a4; + + k=(4.0*g-3.0)/(g+1.0); + p=1.0-0.25*k;p*=p; + + // LP: + a=1.0/(tan(0.5*omega)*(1.0+p)); + p=1.0+a; + q=1.0-a; + + a0=1.0/(k+p*p*p*p); + a1=4.0*(k+p*p*p*q); + a2=6.0*(k+p*p*q*q); + a3=4.0*(k+p*q*q*q); + a4= (k+q*q*q*q); + p=a0*(k+1.0); + + lpf->coef[0]=p; + lpf->coef[1]=4.0*p; + lpf->coef[2]=6.0*p; + lpf->coef[3]=4.0*p; + lpf->coef[4]=p; + lpf->coef[5]=-a1*a0; + lpf->coef[6]=-a2*a0; + lpf->coef[7]=-a3*a0; + lpf->coef[8]=-a4*a0; +} +double LPF(LPF_data* lpf, double in) +{ +// per sample: + + double out=lpf->coef[0]*in+lpf->d[0]; + lpf->d[0] =lpf->coef[1]*in+lpf->coef[5]*out+lpf->d[1]; + lpf->d[1] =lpf->coef[2]*in+lpf->coef[6]*out+lpf->d[2]; + lpf->d[2] =lpf->coef[3]*in+lpf->coef[7]*out+lpf->d[3]; + lpf->d[3] =lpf->coef[4]*in+lpf->coef[8]*out; +return out; +} diff --git a/plugins/spu2ghz/src/lowpass.h b/plugins/spu2ghz/src/lowpass.h new file mode 100644 index 0000000000..c0f18c5431 --- /dev/null +++ b/plugins/spu2ghz/src/lowpass.h @@ -0,0 +1,27 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#pragma once + +typedef struct IIR_data +{ + double coef[9]; + double d[4]; +} LPF_data; + +void LPF_init(LPF_data*lpf,double freq, double srate); +double LPF(LPF_data* lpf, double in); diff --git a/plugins/spu2ghz/src/mixer.cpp b/plugins/spu2ghz/src/mixer.cpp new file mode 100644 index 0000000000..716b452872 --- /dev/null +++ b/plugins/spu2ghz/src/mixer.cpp @@ -0,0 +1,1448 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +// [Air] Notes -----> +// Adding 'static' to the __forceinline methods hints to the linker that it need not +// actually include procedural versions of the methods in the DLL. Under normal circumstances +// the compiler will still generate the procedures even though they are never used (the inline +// code is used instead). Using static reduced the size of my generated .DLL by a few KB. +// (doesn't really make anything faster, but eh... whatever :) +// +#include "spu2.h" + +#include +#include +#include +#include "lowpass.h" + +extern void spdif_update(); + +void ADMAOutLogWrite(void *lpData, u32 ulSize); + +extern void VoiceStop(int core,int vc); + +double pow_2_31 = pow(2.0,31.0); + +LPF_data L,R; + +extern u32 core; + +u32 core, voice; + +extern u8 callirq; + +double srate_pv=1.0; + +extern u32 PsxRates[160]; + +static const s32 ADSR_MAX_VOL = 0x7fffffff; + +// Performs a 64-bit multiplication between two values and returns the +// high 32 bits as a result (discarding the fractional 32 bits). +// The combined fracional bits of both inputs must be 32 bits for this +// to work properly. +// +// This is meant to be a drop-in replacement for times when the 'div' part +// of a MulDiv is a constant. (example: 1<<8, or 4096, etc) +// +// [Air] Performance breakdown: This is over 10 times faster than MulDiv in +// a *worst case* scenario. It's also more accurate since it forces the +// caller to extend the inputs so that they make use of all 32 bits of +// precision. +// +static s32 __forceinline MulShr32( s32 srcval, s32 mulval ) +{ + s64 tmp = ((s64)srcval * mulval ); + return ((s32*)&tmp)[1]; + + // Performance note: Using the temp var and memory reference + // actually ends up being roughly 2x faster than using a bitshift. + // It won't fly on big endian machines though... :) +} + +static s32 __forceinline MulShr32su( s32 srcval, u32 mulval ) +{ + s64 tmp = ((s64)srcval * (s32)mulval ); + return ((s32*)&tmp)[1]; +} + + +void InitADSR() // INIT ADSR +{ + for (int i=0; i<(32+128); i++) + { + int shift=(i-32)>>2; + s64 rate=(i&3)+4; + if (shift<0) + { + rate>>=-shift; + } else + { + rate<<=shift; + } + PsxRates[i]=(int)min(rate,0x3fffffff); + } +} + +#define VOL(x) (((s32)x)) //24.8 volume + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +const s32 f[5][2] ={{ 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 }}; + +static void __forceinline XA_decode_block(s16* buffer, const s16* block, s32& prev1, s32& prev2) +{ + const s32 header = *block; + s32 shift = ((header>> 0)&0xF)+16; + s32 pred1 = f[(header>> 4)&0xF][0]; + s32 pred2 = f[(header>> 4)&0xF][1]; + + const s8* blockbytes = (s8*)&block[1]; + + for(int i=0; i<14; i++, blockbytes++) + { + s32 pcm, pcm2; + { + s32 data = ((*blockbytes)<<28) & 0xF0000000; + pcm = data>>shift; + pcm+=((pred1*prev1)+(pred2*prev2))>>6; + if(pcm> 32767) pcm= 32767; + else if(pcm<-32768) pcm=-32768; + *(buffer++) = pcm; + } + + //prev2=prev1; + //prev1=pcm; + + { + s32 data = ((*blockbytes)<<24) & 0xF0000000; + pcm2 = data>>shift; + pcm2+=((pred1*pcm)+(pred2*prev1))>>6; + if(pcm2> 32767) pcm2= 32767; + else if(pcm2<-32768) pcm2=-32768; + *(buffer++) = pcm2; + } + + prev2=pcm; + prev1=pcm2; + } +} + +static void __forceinline XA_decode_block_unsaturated(s16* buffer, const s16* block, s32& prev1, s32& prev2) +{ + const s32 header = *block; + s32 shift = ((header>> 0)&0xF)+16; + s32 pred1 = f[(header>> 4)&0xF][0]; + s32 pred2 = f[(header>> 4)&0xF][1]; + + const s8* blockbytes = (s8*)&block[1]; + + for(int i=0; i<14; i++, blockbytes++) + { + s32 pcm, pcm2; + { + s32 data = ((*blockbytes)<<28) & 0xF0000000; + pcm = data>>shift; + pcm+=((pred1*prev1)+(pred2*prev2))>>6; + // [Air] : Fast method, no saturation is performed. + *(buffer++) = pcm; + } + + { + s32 data = ((*blockbytes)<<24) & 0xF0000000; + pcm2 = data>>shift; + pcm2+=((pred1*pcm)+(pred2*prev1))>>6; + // [Air] : Fast method, no saturation is performed. + *(buffer++) = pcm2; + } + + prev2=pcm; + prev1=pcm2; + } +} + +static void __forceinline IncrementNextA( const V_Core& thiscore, V_Voice& vc ) +{ + // Important! Both cores signal IRQ when an address is read, regardless of + // which core actually reads the address. + + for( int i=0; i<2; i++ ) + { + if( Cores[i].IRQEnable && (vc.NextA==Cores[i].IRQA ) ) + { + #ifndef PUBLIC + ConLog(" * SPU2 Core %d: IRQ Called (IRQ passed).\n", i); + #endif + Spdif.Info=4<> 8; // grab loop flags from the upper byte. + + const int cacheIdx = vc.NextA / pcm_WordsPerBlock; + PcmCacheEntry& cacheLine = pcm_cache_data[cacheIdx]; + vc.SBuffer = cacheLine.Sampledata; + + if( cacheLine.Validated ) + { + // Cached block! Read from the cache directly. + // Make sure to propagate the prev1/prev2 ADPCM: + + vc.Prev1 = vc.SBuffer[27]; + vc.Prev2 = vc.SBuffer[26]; + + //ConLog( " * SPU2 : Cache Hit! NextA=0x%x, cacheIdx=0x%x\n", vc.NextA, cacheIdx ); + + #ifndef PUBLIC + g_counter_cache_hits++; + #endif + } + else + { + // Only flag the cache if it's a non-dynamic memory range. + if( vc.NextA >= SPU2_DYN_MEMLINE ) + cacheLine.Validated = true; + + #ifndef PUBLIC + if( vc.NextA < SPU2_DYN_MEMLINE ) + g_counter_cache_ignores++; + else + g_counter_cache_misses++; + #endif + + s16* sbuffer = cacheLine.Sampledata; + + // saturated decoder + XA_decode_block( sbuffer, memptr, vc.Prev1, vc.Prev2 ); + + // [Air]: Testing use of a new unsaturated decoder. (benchmark needed) + // Chances are the saturation isn't needed, but for a very few exception games. + // This is definitely faster than the above version, but is it by enough to + // merit possible lower compatibility? Especially now that games that make + // heavy use of the SPU2 via music or sfx will mostly use the cache anyway. + + //XA_decode_block_unsaturated( vc.SBuffer, memptr, vc.Prev1, vc.Prev2 ); + } + + vc.SCurrent = 0; + if( (vc.LoopFlags & XAFLAG_LOOP_START) && !vc.LoopMode ) + vc.LoopStartA = vc.NextA; + + // [Air] : Increment will get called below (change made to avoid needless code cache clutter) + //IncrementNextA( thiscore, vc ); + } + + IncrementNextA( thiscore, vc ); + +_skipIncrement: + Data = vc.SBuffer[vc.SCurrent++]; +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +const int InvExpOffsets[] = { 0,4,6,8,9,10,11,12 }; + +static void __forceinline CalculateADSR( V_Voice& vc ) +{ + V_ADSR& env(vc.ADSR); + + jASSUME( env.Phase != 0 ); + + s32 SLevel = ((s32)env.Sl)<<27; + + jASSUME( SLevel >= 0 ); + + if(env.Releasing) + { + if( env.Phase < 5) + { + env.Phase=5; + } + } + + switch (env.Phase) + { + case 1: // attack + if( env.Value == ADSR_MAX_VOL ) + { + // Already maxed out. Progress phase and nothing more: + env.Phase++; + break; + } + + if (env.Am) // pseudo exponential + { + if (env.Value<0x60000000) // below 75% + { + env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32]; + } + else // above 75% + { + env.Value+=PsxRates[(env.Ar^0x7f)-0x18+32]; + } + } + else // linear + { + env.Value+=PsxRates[(env.Ar^0x7f)-0x10+32]; + } + + if( env.Value < 0 ) + { + // We hit the ceiling. + env.Phase++; + env.Value = ADSR_MAX_VOL; + } + + break; + + case 2: // decay + { + u32 off = InvExpOffsets[(env.Value>>28)&7]; + env.Value-=PsxRates[((env.Dr^0x1f)<<2)-0x18+off+32]; + + if(env.Value <= SLevel) + { + // Clamp decay to SLevel or Zero + if (env.Value < 0) + env.Value = 0; + else + env.Value = SLevel; + + env.Phase++; + } + + break; + } + + case 3: // sustain + if (env.Sm&2) // decreasing + { + if (env.Sm&4) // exponential + { + u32 off = InvExpOffsets[(env.Value>>28)&7]; + env.Value-=PsxRates[(env.Sr^0x7f)-0x1b+off+32]; + } + else // linear + { + env.Value-=PsxRates[(env.Sr^0x7f)-0xf+32]; + } + if( env.Value <= 0 ) + { + env.Value = 0; + env.Phase++; + } + } + else // increasing + { + if (env.Sm&4) // pseudo exponential + { + if (env.Value<0x60000000) // below 75% + { + env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32]; + } + else // above 75% + { + env.Value+=PsxRates[(env.Sr^0x7f)-0x18+32]; + } + } + else + { + // linear + + env.Value+=PsxRates[(env.Sr^0x7f)-0x10+32]; + } + + if( env.Value < 0 ) + { + env.Value = ADSR_MAX_VOL; + env.Phase++; + } + } + + break; + + case 4: // sustain end + env.Value = (env.Sm&2) ? 0 : ADSR_MAX_VOL; + if(env.Value==0) + env.Phase=6; + break; + + case 5: // release + + if (env.Rm) // exponential + { + u32 off=InvExpOffsets[(env.Value>>28)&7]; + env.Value-=PsxRates[((env.Rr^0x1f)<<2)-0x18+off+32]; + } + else // linear + { + env.Value-=PsxRates[((env.Rr^0x1f)<<2)-0xc+32]; + } + + if( env.Value <= 0 ) + { + env.Value=0; + env.Phase++; + } + + break; + + case 6: // release end + env.Value=0; + break; + + jNO_DEFAULT + } + + if (env.Phase==6) { + #ifndef PUBLIC + if(MsgVoiceOff()) ConLog(" * SPU2: Voice Off by ADSR: %d \n", voice); + DebugCores[core].Voices[voice].lastStopReason = 2; + #endif + VoiceStop(core,voice); + Cores[core].Regs.ENDX|=(1<> 7; // >> 6 is more correct, but causes a few overflows +} + +static void __forceinline UpdatePitch( V_Voice& vc ) +{ + s32 pitch; + + // [Air] : re-ordered comparisons: Modulated is much more likely to be zero than voice, + // and so the way it was before it's have to check both voice and modulated values + // most of the time. Now it'll just check Modulated and short-circuit past the voice + // check (not that it amounts to much, but eh every little bit helps). + if( (vc.Modulated==0) || (voice==0) ) + pitch=vc.Pitch; + else + pitch=(vc.Pitch*(32768 + abs(Cores[core].Voices[voice-1].OutX)))>>15; + + vc.SP+=pitch; +} + +static void __forceinline GetVoiceValues_Linear(V_Core& thiscore, V_Voice& vc, s32& Value) +{ + while( vc.SP > 0 ) + { + vc.PV2=vc.PV1; + + GetNextDataBuffered( thiscore, vc, vc.PV1 ); + + vc.SP-=4096; + } + + if( vc.ADSR.Phase==0 ) + { + Value = 0; + return; + } + + CalculateADSR( vc ); + + jASSUME( vc.ADSR.Value >= 0 ); // ADSR should never be negative... + + if(Interpolation==0) + { + Value = MulShr32( vc.PV1, vc.ADSR.Value ); + } + else //if(Interpolation==1) //must be linear + { + s32 t0 = vc.PV2 - vc.PV1; + s32 t1 = vc.PV1; + Value = MulShr32( t1 - ((t0*vc.SP)>>12), vc.ADSR.Value ); + } +} + + +static void __forceinline GetVoiceValues_Cubic(V_Core& thiscore, V_Voice& vc, s32& Value) +{ + while( vc.SP > 0 ) + { + vc.PV4=vc.PV3; + vc.PV3=vc.PV2; + vc.PV2=vc.PV1; + + GetNextDataBuffered( thiscore, vc, vc.PV1 ); + vc.PV1<<=3; + vc.SPc = vc.SP&4095; // just the fractional part, please! + vc.SP-=4096; + } + + if( vc.ADSR.Phase==0 ) + { + Value = 0; + return; + } + + CalculateADSR( vc ); + + jASSUME( vc.ADSR.Value >= 0 ); // ADSR should never be negative... + + s32 z0 = vc.PV3 - vc.PV4 + vc.PV1 - vc.PV2; + s32 z1 = (vc.PV4 - vc.PV3 - z0); + s32 z2 = (vc.PV2 - vc.PV4); + + s32 mu = vc.SPc; + + s32 val = (z0 * mu) >> 12; + val = ((val + z1) * mu) >> 12; + val = ((val + z2) * mu) >> 12; + val += vc.PV2; + + Value = MulShr32( val, vc.ADSR.Value>>3 ); +} + +// [Air]: Noise values need to be mixed without going through interpolation, since it +// can wreak havoc on the noise (causing muffling or popping). +static void __forceinline __fastcall GetNoiseValues(V_Core& thiscore, V_Voice& vc, s32& Data) +{ + while(vc.SP>=4096) + { + GetNoiseValues( Data ); + vc.SP-=4096; + } + + // GetNoiseValues can't set the phase zero on us unexpectedly + // like GetVoiceValues can. Better asster just in case though.. + jASSUME( vc.ADSR.Phase != 0 ); + + CalculateADSR( vc ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +void __fastcall ReadInput(V_Core& thiscore, s32& PDataL,s32& PDataR) +{ + if((thiscore.AutoDMACtrl&(core+1))==(core+1)) + { + s32 tl,tr; + + if((core==1)&&((PlayMode&8)==8)) + { + thiscore.InputPos&=~1; + + //CDDA mode +#ifdef PCM24_S1_INTERLEAVE + *PDataL=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)))); + *PDataR=*(((s32*)(thiscore.ADMATempBuffer+(thiscore.InputPos<<1)+2))); +#else + s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]); + s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]); + PDataL=*pl; + PDataR=*pr; +#endif + + PDataL>>=4; //give 16.8 data + PDataR>>=4; + + thiscore.InputPos+=2; + if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) { + thiscore.AdmaInProgress=0; + if(thiscore.InputDataLeft>=0x200) + { + u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; + +#ifdef PCM24_S1_INTERLEAVE + AutoDMAReadBuffer(core,1); +#else + AutoDMAReadBuffer(core,0); +#endif + thiscore.AdmaInProgress=1; + + thiscore.TSA=(core<<10)+thiscore.InputPos; + + if (thiscore.InputDataLeft<0x200) + { + FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); + + #ifndef PUBLIC + if(thiscore.InputDataLeft>0) + { + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + } + #endif + thiscore.InputDataLeft=0; + thiscore.DMAICounter=1; + } + } + thiscore.InputPos&=0x1ff; + } + + } + else if((core==0)&&((PlayMode&4)==4)) + { + thiscore.InputPos&=~1; + + s32 *pl=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos]); + s32 *pr=(s32*)&(thiscore.ADMATempBuffer[thiscore.InputPos+0x200]); + PDataL=*pl; + PDataR=*pr; + + thiscore.InputPos+=2; + if(thiscore.InputPos>=0x200) { + thiscore.AdmaInProgress=0; + if(thiscore.InputDataLeft>=0x200) + { + u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; + + AutoDMAReadBuffer(core,0); + + thiscore.AdmaInProgress=1; + + thiscore.TSA=(core<<10)+thiscore.InputPos; + + if (thiscore.InputDataLeft<0x200) + { + FileLog("[%10d] Spdif AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); + + #ifndef PUBLIC + if(thiscore.InputDataLeft>0) + { + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + } + #endif + thiscore.InputDataLeft=0; + thiscore.DMAICounter=1; + } + } + thiscore.InputPos&=0x1ff; + } + + } + else + { + if((core==1)&&((PlayMode&2)!=0)) + { + tl=0; + tr=0; + } + else + { + // Using the temporary buffer because this area gets overwritten by some other code. + //*PDataL=(s32)*(s16*)(spu2mem+0x2000+(core<<10)+thiscore.InputPos); + //*PDataR=(s32)*(s16*)(spu2mem+0x2200+(core<<10)+thiscore.InputPos); + + tl=(s32)thiscore.ADMATempBuffer[thiscore.InputPos]; + tr=(s32)thiscore.ADMATempBuffer[thiscore.InputPos+0x200]; + + } + + PDataL=tl; + PDataR=tr; + + thiscore.InputPos++; + if((thiscore.InputPos==0x100)||(thiscore.InputPos>=0x200)) { + thiscore.AdmaInProgress=0; + if(thiscore.InputDataLeft>=0x200) + { + u8 k=thiscore.InputDataLeft>=thiscore.InputDataProgress; + + AutoDMAReadBuffer(core,0); + + thiscore.AdmaInProgress=1; + + thiscore.TSA=(core<<10)+thiscore.InputPos; + + if (thiscore.InputDataLeft<0x200) + { + thiscore.AutoDMACtrl |= ~3; + + #ifndef PUBLIC + FileLog("[%10d] AutoDMA%c block end.\n",Cycles, (core==0)?'4':'7'); + if(thiscore.InputDataLeft>0) + { + if(MsgAutoDMA()) ConLog("WARNING: adma buffer didn't finish with a whole block!!\n"); + } + #endif + thiscore.InputDataLeft=0; + thiscore.DMAICounter=1; + } + } + thiscore.InputPos&=0x1ff; + } + } + } + else { + PDataL=0; + PDataR=0; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +static void __forceinline __fastcall ReadInputPV(V_Core& thiscore, s32& ValL,s32& ValR) +{ + s32 DL=0, DR=0; + + u32 pitch=AutoDMAPlayRate[core]; + + if(pitch==0) pitch=48000; + + thiscore.ADMAPV+=pitch; + while(thiscore.ADMAPV>=48000) + { + ReadInput(thiscore, DL,DR); + thiscore.ADMAPV-=48000; + thiscore.ADMAPL=DL; + thiscore.ADMAPR=DR; + } + + ValL=thiscore.ADMAPL; + ValR=thiscore.ADMAPR; + + #ifndef PUBLIC + s32 InputPeak = max(abs(ValL),abs(ValR)); + if(DebugCores[core].AutoDMAPeak>= 1; + //ValR >>= 1; + +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +#define VOLFLAG_REVERSE_PHASE (1ul<<0) +#define VOLFLAG_DECREMENT (1ul<<1) +#define VOLFLAG_EXPONENTIAL (1ul<<2) +#define VOLFLAG_SLIDE_ENABLE (1ul<<3) + +static void __fastcall UpdateVolume(V_Volume& Vol) +{ + // TIMINGS ARE FAKE!!! Need to investigate. + + // [Air]: Cleaned up this code... may have broken it. Can't really + // test it here since none of my games seem to use it. If anything's + // not sounding right, we should revert the code in this method first. + + // [Air] Reverse phasing? + // Invert our value so that exponential mathematics are applied + // as if the volume were sliding the other direction. This makes + // a lot more sense than the old method's likeliness to chop off + // sound volumes to zero abruptly. + + if(Vol.Mode & VOLFLAG_REVERSE_PHASE) + { + ConLog( " *** SPU2 > Reverse Phase in progress!\n" ); + Vol.Value = 0x7fff - Vol.Value; + } + + if (Vol.Mode & VOLFLAG_DECREMENT) + { + // Decrement + + if(Vol.Mode & VOLFLAG_EXPONENTIAL) + { + ConLog( " *** SPU2 > Exponential Volume Slide Down!\n" ); + Vol.Value *= Vol.Increment >> 7; + Vol.Value-=((32768*5)>>(Vol.Increment)); + } + else + { + Vol.Value-=Vol.Increment; + } + + if (Vol.Value<0) + { + Vol.Value = 0; + Vol.Mode=0; // disable slide + } + } + else + { + //ConLog( " *** SPU2 > Volflag > Increment!\n" ); + // Increment + if(Vol.Mode & VOLFLAG_EXPONENTIAL) + { + ConLog( " *** SPU2 > Exponential Volume Slide Up!\n" ); + int T = Vol.Increment>>(Vol.Value>>12); + Vol.Value+=T; + } + else + { + Vol.Value+=Vol.Increment; + } + + if( Vol.Value > 0x7fff ) + { + Vol.Value = 0x7fff; + Vol.Mode=0; // disable slide + } + } + + // Reverse phasing + // Invert the value back into output form: + if(Vol.Mode & VOLFLAG_REVERSE_PHASE) Vol.Value = 0x7fff-Vol.Value; + + //Vol.Value=NVal; +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +static s32 __forceinline clamp(s32 x) +{ + if (x>0x00ffffff) return 0x00ffffff; + if (x<0xff000000) return 0xff000000; + return x; +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +static void DoReverb( V_Core& thiscore, s32& OutL, s32& OutR, s32 InL, s32 InR) +{ + static s32 INPUT_SAMPLE_L,INPUT_SAMPLE_R; + static s32 OUTPUT_SAMPLE_L,OUTPUT_SAMPLE_R; + + if(!(thiscore.FxEnable&&EffectsEnabled)) + { + OUTPUT_SAMPLE_L=0; + OUTPUT_SAMPLE_R=0; + } + else if((Cycles&1)==0) + { + INPUT_SAMPLE_L=InL; + INPUT_SAMPLE_R=InR; + } + else + { +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + s32 IIR_INPUT_A0,IIR_INPUT_A1,IIR_INPUT_B0,IIR_INPUT_B1; + s32 ACC0,ACC1; + s32 FB_A0,FB_A1,FB_B0,FB_B1; + s32 buffsize=thiscore.EffectsEndA-thiscore.EffectsStartA+1; + + if(buffsize<0) + { + buffsize = thiscore.EffectsEndA; + thiscore.EffectsEndA=thiscore.EffectsStartA; + thiscore.EffectsStartA=buffsize; + buffsize=thiscore.EffectsEndA-thiscore.EffectsStartA+1; + } + + //filter the 2 samples (prev then current) + LowPass(INPUT_SAMPLE_L, INPUT_SAMPLE_R); + LowPass(InL, InR); + + INPUT_SAMPLE_L=(INPUT_SAMPLE_L+InL)>>9; + INPUT_SAMPLE_R=(INPUT_SAMPLE_R+InR)>>9; + +#define BUFFER(x) ((s32)(*GetMemPtr(thiscore.EffectsStartA + ((thiscore.ReverbX + buffsize-((x)<<2))%buffsize)))) +#define SBUFFER(x) (*GetMemPtr(thiscore.EffectsStartA + ((thiscore.ReverbX + buffsize-((x)<<2))%buffsize))) + + thiscore.ReverbX=((thiscore.ReverbX + 4)%buffsize); + + IIR_INPUT_A0 = (BUFFER(thiscore.Revb.IIR_SRC_A0) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_L * thiscore.Revb.IN_COEF_L)>>16; + IIR_INPUT_A1 = (BUFFER(thiscore.Revb.IIR_SRC_A1) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_R * thiscore.Revb.IN_COEF_R)>>16; + IIR_INPUT_B0 = (BUFFER(thiscore.Revb.IIR_SRC_B0) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_L * thiscore.Revb.IN_COEF_L)>>16; + IIR_INPUT_B1 = (BUFFER(thiscore.Revb.IIR_SRC_B1) * thiscore.Revb.IIR_COEF + INPUT_SAMPLE_R * thiscore.Revb.IN_COEF_R)>>16; + + SBUFFER(thiscore.Revb.IIR_DEST_A0 + 4) = clamp((IIR_INPUT_A0 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_A0) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); + SBUFFER(thiscore.Revb.IIR_DEST_A1 + 4) = clamp((IIR_INPUT_A1 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_A1) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); + SBUFFER(thiscore.Revb.IIR_DEST_B0 + 4) = clamp((IIR_INPUT_B0 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_B0) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); + SBUFFER(thiscore.Revb.IIR_DEST_B1 + 4) = clamp((IIR_INPUT_B1 * thiscore.Revb.IIR_ALPHA + BUFFER(thiscore.Revb.IIR_DEST_B1) * (65535 - thiscore.Revb.IIR_ALPHA))>>16); + + ACC0 = (s32)(BUFFER(thiscore.Revb.ACC_SRC_A0) * thiscore.Revb.ACC_COEF_A + + BUFFER(thiscore.Revb.ACC_SRC_B0) * thiscore.Revb.ACC_COEF_B + + BUFFER(thiscore.Revb.ACC_SRC_C0) * thiscore.Revb.ACC_COEF_C + + BUFFER(thiscore.Revb.ACC_SRC_D0) * thiscore.Revb.ACC_COEF_D)>>16; + ACC1 = (s32)(BUFFER(thiscore.Revb.ACC_SRC_A1) * thiscore.Revb.ACC_COEF_A + + BUFFER(thiscore.Revb.ACC_SRC_B1) * thiscore.Revb.ACC_COEF_B + + BUFFER(thiscore.Revb.ACC_SRC_C1) * thiscore.Revb.ACC_COEF_C + + BUFFER(thiscore.Revb.ACC_SRC_D1) * thiscore.Revb.ACC_COEF_D)>>16; + + FB_A0 = BUFFER(thiscore.Revb.MIX_DEST_A0 - thiscore.Revb.FB_SRC_A); + FB_A1 = BUFFER(thiscore.Revb.MIX_DEST_A1 - thiscore.Revb.FB_SRC_A); + FB_B0 = BUFFER(thiscore.Revb.MIX_DEST_B0 - thiscore.Revb.FB_SRC_B); + FB_B1 = BUFFER(thiscore.Revb.MIX_DEST_B1 - thiscore.Revb.FB_SRC_B); + + SBUFFER(thiscore.Revb.MIX_DEST_A0) = clamp((ACC0 - FB_A0 * thiscore.Revb.FB_ALPHA)>>16); + SBUFFER(thiscore.Revb.MIX_DEST_A1) = clamp((ACC1 - FB_A1 * thiscore.Revb.FB_ALPHA)>>16); + SBUFFER(thiscore.Revb.MIX_DEST_B0) = clamp(((thiscore.Revb.FB_ALPHA * ACC0) - FB_A0 * (65535 - thiscore.Revb.FB_ALPHA) - FB_B0 * thiscore.Revb.FB_X)>>16); + SBUFFER(thiscore.Revb.MIX_DEST_B1) = clamp(((thiscore.Revb.FB_ALPHA * ACC1) - FB_A1 * (65535 - thiscore.Revb.FB_ALPHA) - FB_B1 * thiscore.Revb.FB_X)>>16); + + OUTPUT_SAMPLE_L=clamp((BUFFER(thiscore.Revb.MIX_DEST_A0)+BUFFER(thiscore.Revb.MIX_DEST_B0))>>2); + OUTPUT_SAMPLE_R=clamp((BUFFER(thiscore.Revb.MIX_DEST_B1)+BUFFER(thiscore.Revb.MIX_DEST_B1))>>2); + } + OutL=OUTPUT_SAMPLE_L; + OutR=OUTPUT_SAMPLE_R; +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +// writes a signed value to the SPU2 ram +// Performs no cache invalidation -- use only for dynamic memory ranges +// of the SPU2 (between 0x0000 and SPU2_DYN_MEMLINE) +static __forceinline void spu2M_WriteFast( u32 addr, s16 value ) +{ + // throw an assertion if the memory range is invalid: + jASSUME( addr < SPU2_DYN_MEMLINE ); + *GetMemPtr( addr ) = value; +} + + +static __forceinline void MixVoice( V_Core& thiscore, V_Voice& vc, s32& VValL, s32& VValR ) +{ + s32 Value=0; + + VValL=0; + VValR=0; + + // [Air] : Most games don't use much volume slide effects. So only + // call the UpdateVolume methods when needed by checking the flag + // outside the method here... + + if( vc.VolumeL.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume( vc.VolumeL ); + if( vc.VolumeR.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume( vc.VolumeR ); + + if (vc.ADSR.Phase>0) + { + UpdatePitch( vc ); + + if( vc.Noise ) + GetNoiseValues( thiscore, vc, Value ); + else + { + if( Interpolation == 2 ) + GetVoiceValues_Cubic( thiscore, vc, Value ); + else + GetVoiceValues_Linear( thiscore, vc, Value ); + } + + // Record the output (used for modulation effects) + vc.OutX = Value; + + #ifndef PUBLIC + DebugCores[core].Voices[voice].displayPeak = max(DebugCores[core].Voices[voice].displayPeak,abs(Value)); + #endif + + VValL=ApplyVolume(Value,(vc.VolumeL.Value)); + VValR=ApplyVolume(Value,(vc.VolumeR.Value)); + } + + if (voice==1) spu2M_WriteFast( 0x400 + (core<<12) + OutPos, (s16)Value ); + else if (voice==3) spu2M_WriteFast( 0x600 + (core<<12) + OutPos, (s16)Value ); + +} + + +static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR) +{ + s32 RVL,RVR; + s32 SDL=0,SDR=0; + s32 SWL=0,SWR=0; + + V_Core& thiscore( Cores[core] ); + + for (voice=0;voice<24;voice++) + { + s32 VValL,VValR; + + V_Voice& vc( thiscore.Voices[voice] ); + MixVoice( thiscore, vc, VValL, VValR ); + + SDL += VValL * vc.DryL; + SDR += VValR * vc.DryR; + SWL += VValL * vc.WetL; + SWR += VValR * vc.WetR; + } + + //Write To Output Area + spu2M_WriteFast( 0x1000 + (core<<12) + OutPos, (s16)(SDL>>16) ); + spu2M_WriteFast( 0x1200 + (core<<12) + OutPos, (s16)(SDR>>16) ); + spu2M_WriteFast( 0x1400 + (core<<12) + OutPos, (s16)(SWL>>16) ); + spu2M_WriteFast( 0x1600 + (core<<12) + OutPos, (s16)(SWR>>16) ); + + s32 TDL,TDR; + + // Mix in the Input data + // divide by 3 fixes some volume problems. + TDL = OutL * thiscore.InpDryL; + TDR = OutR * thiscore.InpDryR; + + // Mix in the Voice data + TDL += SDL * thiscore.SndDryL; + TDR += SDR * thiscore.SndDryR; + + // Mix in the External (nothing/core0) data + TDL += ExtL * thiscore.ExtDryL; + TDR += ExtR * thiscore.ExtDryR; + + if(EffectsEnabled) + { + s32 TWL=0,TWR=0; + + // Mix Input, Voice, and External data: + TWL = OutL * thiscore.InpWetL; + TWR = OutR * thiscore.InpWetR; + TWL += SWL * thiscore.SndWetL; + TWR += SWR * thiscore.SndWetR; + TWL += ExtL * thiscore.ExtWetL; + TWR += ExtR * thiscore.ExtWetR; + + //Apply Effects + DoReverb( thiscore, RVL,RVR,TWL>>16,TWR>>16); + + TWL=ApplyVolume(RVL,VOL(thiscore.FxL)); + TWR=ApplyVolume(RVR,VOL(thiscore.FxR)); + + //Mix Wet,Dry + OutL=(TDL + TWL); + OutR=(TDR + TWR); + } + else + { + OutL = TDL; + OutR = TDR; + } + + //Apply Master Volume + if( thiscore.MasterL.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume(thiscore.MasterL); + if( thiscore.MasterR.Mode & VOLFLAG_SLIDE_ENABLE ) UpdateVolume(thiscore.MasterR); + + if (thiscore.Mute==0) + { + OutL = MulShr32( OutL, ((s32)thiscore.MasterL.Value)<<16 ); + OutR = MulShr32( OutR, ((s32)thiscore.MasterR.Value)<<16 ); + } + else + { + OutL=0; + OutR=0; + } +} + +// used to throttle the output rate of cache stat reports +static int p_cachestat_counter=0; + +void __fastcall Mix() +{ + s32 ExtL=0, ExtR=0, OutL, OutR; + + // **** CORE ZERO **** + + core=0; + if( (PlayMode&4) != 4 ) + { + // get input data from input buffers + ReadInputPV(Cores[0], ExtL, ExtR); + } + + MixCore( ExtL, ExtR, 0, 0 ); + + if( PlayMode & 4 ) + { + ExtL=0; + ExtR=0; + } + + // Commit Core 0 output to ram before mixing Core 1: + ExtL>>=14; + ExtR>>=14; + spu2M_WriteFast( 0x800 + OutPos, ExtL>>3 ); + spu2M_WriteFast( 0xA00 + OutPos, ExtR>>3 ); + + // **** CORE ONE **** + + core=1; + if( (PlayMode&8) != 8 ) + { + ReadInputPV(Cores[1], OutL, OutR); // get input data from input buffers + } + + // Apply volume to the external (Core 0) input data. + + MixCore( OutL, OutR, ExtL*Cores[1].ExtL, ExtR*Cores[1].ExtR ); + + if( PlayMode & 8 ) + { + ReadInput(Cores[1], OutL, OutR); + } + +#ifndef PUBLIC + static s32 Peak0,Peak1; + static s32 PCount; + + Peak0 = max(Peak0,max(ExtL,ExtR)); + Peak1 = max(Peak1,max(OutL,OutR)); +#endif + + // Update spdif (called each sample) + if(PlayMode&4) + { + spdif_update(); + } + + // AddToBuffer + SndWrite(OutL, OutR); //ExtL,ExtR); + OutPos++; + if (OutPos>=0x200) OutPos=0; + +#ifndef PUBLIC + // [TODO]: Create an INI option to enable/disable this particular log. + p_cachestat_counter++; + if(p_cachestat_counter > (48000*10) ) + { + p_cachestat_counter = 0; + if( MsgCache() ) ConLog( " * SPU2 > CacheStats > Hits: %d Misses: %d Ignores: %d\n", + g_counter_cache_hits, + g_counter_cache_misses, + g_counter_cache_ignores ); + + g_counter_cache_hits = + g_counter_cache_misses = + g_counter_cache_ignores = 0; + } +#endif +} + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // +u32 PsxRates[160]={ + + //for +Lin: PsxRates[value+8] + //for -Lin: PsxRates[value+7] + + 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, + 0xD744FCCB,0xB504F334,0x9837F052,0x80000000,0x6BA27E65,0x5A82799A,0x4C1BF829,0x40000000, + 0x35D13F33,0x2D413CCD,0x260DFC14,0x20000000,0x1AE89F99,0x16A09E66,0x1306FE0A,0x10000000, + 0x0D744FCD,0x0B504F33,0x09837F05,0x08000000,0x06BA27E6,0x05A8279A,0x04C1BF83,0x04000000, + 0x035D13F3,0x02D413CD,0x0260DFC1,0x02000000,0x01AE89FA,0x016A09E6,0x01306FE1,0x01000000, + 0x00D744FD,0x00B504F3,0x009837F0,0x00800000,0x006BA27E,0x005A827A,0x004C1BF8,0x00400000, + 0x0035D13F,0x002D413D,0x00260DFC,0x00200000,0x001AE8A0,0x0016A09E,0x001306FE,0x00100000, + 0x000D7450,0x000B504F,0x0009837F,0x00080000,0x0006BA28,0x0005A828,0x0004C1C0,0x00040000, + 0x00035D14,0x0002D414,0x000260E0,0x00020000,0x0001AE8A,0x00016A0A,0x00013070,0x00010000, + 0x0000D745,0x0000B505,0x00009838,0x00008000,0x00006BA2,0x00005A82,0x00004C1C,0x00004000, + 0x000035D1,0x00002D41,0x0000260E,0x00002000,0x00001AE9,0x000016A1,0x00001307,0x00001000, + 0x00000D74,0x00000B50,0x00000983,0x00000800,0x000006BA,0x000005A8,0x000004C2,0x00000400, + 0x0000035D,0x000002D4,0x00000261,0x00000200,0x000001AF,0x0000016A,0x00000130,0x00000100, + 0x000000D7,0x000000B5,0x00000098,0x00000080,0x0000006C,0x0000005B,0x0000004C,0x00000040, + 0x00000036,0x0000002D,0x00000026,0x00000020,0x0000001B,0x00000017,0x00000013,0x00000010, + 0x0000000D,0x0000000B,0x0000000A,0x00000008,0x00000007,0x00000006,0x00000005,0x00000004, + 0x00000003,0x00000003,0x00000002,0x00000002,0x00000002,0x00000001,0x00000001,0x00000000, + + //128+8 + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, +}; + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// // + +/* +----------------------------------------------------------------------------- +PSX reverb hardware notes +by Neill Corlett +----------------------------------------------------------------------------- + +Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway +yadda yadda. + +----------------------------------------------------------------------------- + +Basics +------ + +- The reverb buffer is 22khz 16-bit mono PCM. +- It starts at the reverb address given by 1DA2, extends to + the end of sound RAM, and wraps back to the 1DA2 address. + +Setting the address at 1DA2 resets the current reverb work address. + +This work address ALWAYS increments every 1/22050 sec., regardless of +whether reverb is enabled (bit 7 of 1DAA set). + +And the contents of the reverb buffer ALWAYS play, scaled by the +"reverberation depth left/right" volumes (1D84/1D86). +(which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0) + +----------------------------------------------------------------------------- + +Register names +-------------- + +These are probably not their real names. +These are probably not even correct names. +We will use them anyway, because we can. + +1DC0: FB_SRC_A (offset) +1DC2: FB_SRC_B (offset) +1DC4: IIR_ALPHA (coef.) +1DC6: ACC_COEF_A (coef.) +1DC8: ACC_COEF_B (coef.) +1DCA: ACC_COEF_C (coef.) +1DCC: ACC_COEF_D (coef.) +1DCE: IIR_COEF (coef.) +1DD0: FB_ALPHA (coef.) +1DD2: FB_X (coef.) +1DD4: IIR_DEST_A0 (offset) +1DD6: IIR_DEST_A1 (offset) +1DD8: ACC_SRC_A0 (offset) +1DDA: ACC_SRC_A1 (offset) +1DDC: ACC_SRC_B0 (offset) +1DDE: ACC_SRC_B1 (offset) +1DE0: IIR_SRC_A0 (offset) +1DE2: IIR_SRC_A1 (offset) +1DE4: IIR_DEST_B0 (offset) +1DE6: IIR_DEST_B1 (offset) +1DE8: ACC_SRC_C0 (offset) +1DEA: ACC_SRC_C1 (offset) +1DEC: ACC_SRC_D0 (offset) +1DEE: ACC_SRC_D1 (offset) +1DF0: IIR_SRC_B1 (offset) +1DF2: IIR_SRC_B0 (offset) +1DF4: MIX_DEST_A0 (offset) +1DF6: MIX_DEST_A1 (offset) +1DF8: MIX_DEST_B0 (offset) +1DFA: MIX_DEST_B1 (offset) +1DFC: IN_COEF_L (coef.) +1DFE: IN_COEF_R (coef.) + +The coefficients are signed fractional values. +-32768 would be -1.0 + 32768 would be 1.0 (if it were possible... the highest is of course 32767) + +The offsets are (byte/8) offsets into the reverb buffer. +i.e. you multiply them by 8, you get byte offsets. +You can also think of them as (samples/4) offsets. +They appear to be signed. They can be negative. +None of the documented presets make them negative, though. + +Yes, 1DF0 and 1DF2 appear to be backwards. Not a typo. + +----------------------------------------------------------------------------- + +What it does +------------ + +We take all reverb sources: +- regular channels that have the reverb bit on +- cd and external sources, if their reverb bits are on +and mix them into one stereo 44100hz signal. + +Lowpass/downsample that to 22050hz. The PSX uses a proper bandlimiting +algorithm here, but I haven't figured out the hysterically exact specifics. +I use an 8-tap filter with these coefficients, which are nice but probably +not the real ones: + +0.037828187894 +0.157538631280 +0.321159685278 +0.449322115345 +0.449322115345 +0.321159685278 +0.157538631280 +0.037828187894 + +So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz. + +* IN MY EMULATION, I divide these by 2 to make it clip less. + (and of course the L/R output coefficients are adjusted to compensate) + The real thing appears to not do this. + +At every 22050hz tick: +- If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb + steady-state algorithm described below +- AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer + (This part may not be exactly right and I guessed at the coefs. TODO: check later.) + L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0]) + R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1]) +- Advance the current buffer position by 1 sample + +The wet out L and R are then upsampled to 44100hz and played at the +"reverberation depth left/right" (1D84/1D86) volume, independent of the main +volume. + +----------------------------------------------------------------------------- + +Reverb steady-state +------------------- + +The reverb steady-state algorithm is fairly clever, and of course by +"clever" I mean "batshit insane". + +buffer[x] is relative to the current buffer position, not the beginning of +the buffer. Note that all buffer offsets must wrap around so they're +contained within the reverb work area. + +Clipping is performed at the end... maybe also sooner, but definitely at +the end. + +IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; +IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; +IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L; +IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R; + +IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA); +IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA); +IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA); +IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA); + +buffer[IIR_DEST_A0 + 1sample] = IIR_A0; +buffer[IIR_DEST_A1 + 1sample] = IIR_A1; +buffer[IIR_DEST_B0 + 1sample] = IIR_B0; +buffer[IIR_DEST_B1 + 1sample] = IIR_B1; + +ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A + + buffer[ACC_SRC_B0] * ACC_COEF_B + + buffer[ACC_SRC_C0] * ACC_COEF_C + + buffer[ACC_SRC_D0] * ACC_COEF_D; +ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A + + buffer[ACC_SRC_B1] * ACC_COEF_B + + buffer[ACC_SRC_C1] * ACC_COEF_C + + buffer[ACC_SRC_D1] * ACC_COEF_D; + +FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A]; +FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A]; +FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B]; +FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B]; + +buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA; +buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA; +buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X; +buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X; + +----------------------------------------------------------------------------- +*/ diff --git a/plugins/spu2ghz/src/mixer.h b/plugins/spu2ghz/src/mixer.h new file mode 100644 index 0000000000..f92c947d60 --- /dev/null +++ b/plugins/spu2ghz/src/mixer.h @@ -0,0 +1,26 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef MIXER_H_INCLUDED +#define MIXER_H_INCLUDED + +void __fastcall Mix(); + +void __fastcall LogVolInit(); +void __fastcall LogVolClose(); + +#endif // MIXER_H_INCLUDED // diff --git a/plugins/spu2ghz/src/regs.h b/plugins/spu2ghz/src/regs.h new file mode 100644 index 0000000000..dc53bb418e --- /dev/null +++ b/plugins/spu2ghz/src/regs.h @@ -0,0 +1,184 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef REGS_H_INCLUDED +#define REGS_H_INCLUDED + +#define SPU2_CORE0 0x00000000 +#define SPU2_CORE1 0x00000400 + +#define SPU2_VP(voice) ((voice) * 16) +#define SPU2_VA(voice) ((voice) * 12) + +#define REG_VP_VOLL 0x0000 // Voice Volume Left +#define REG_VP_VOLR 0x0002 // Voice Volume Right +#define REG_VP_PITCH 0x0004 // Pitch +#define REG_VP_ADSR1 0x0006 // Envelope 1 (Attack-Decay-Sustain-Release) +#define REG_VP_ADSR2 0x0008 // Envelope 2 (Attack-Decay-Sustain-Release) +#define REG_VP_ENVX 0x000A // Current Envelope +#define REG_VP_VOLXL 0x000C // Current Voice Volume Left +#define REG_VP_VOLXR 0x000E // Current Voice Volume Right + +// .. repeated for each voice .. + +#define REG_S_PMON 0x0180 // Pitch Modulation Spec. +#define REG_S_NON 0x0184 // Alloc Noise Generator +#define REG_S_VMIXL 0x0188 // Voice Output Mix Left (Dry) +#define REG_S_VMIXEL 0x018C // Voice Output Mix Left (Wet) +#define REG_S_VMIXR 0x0190 // Voice Output Mix Right (Dry) +#define REG_S_VMIXER 0x0194 // Voice Output Mix Right (Wet) + +#define REG_P_MMIX 0x0198 // Output Spec. After Voice Mix +#define REG_C_ATTR 0x019A // Core X Attrib +#define REG_A_IRQA 0x019C // Interrupt Address Spec. + +#define REG_S_KON 0x01A0 // Key On 0/1 +#define REG_S_KOFF 0x01A4 // Key Off 0/1 + +#define REG_A_TSA 0x01A8 // Transfer starting address +#define REG__1AC 0x01AC // Transfer data +#define REG__1AE 0x01AE +#define REG_S_ADMAS 0x01B0 // AutoDMA Status + +// 1b2, 1b4, 1b6, 1b8, 1ba, 1bc, 1be are unknown + +#define REG_VA_SSA 0x01C0 // Waveform data starting address +#define REG_VA_LSAX 0x01C4 // Loop point address +#define REG_VA_NAX 0x01C8 // Waveform data that should be read next + +// .. repeated for each voice .. + +#define REG_A_ESA 0x02E0 //Address: Top address of working area for effects processing +#define R_FB_SRC_A 0x02E4 // Feedback Source A +#define R_FB_SRC_B 0x02E8 // Feedback Source B +#define R_IIR_DEST_A0 0x02EC +#define R_IIR_DEST_A1 0x02F0 +#define R_ACC_SRC_A0 0x02F4 +#define R_ACC_SRC_A1 0x02F8 +#define R_ACC_SRC_B0 0x02FC +#define R_ACC_SRC_B1 0x0300 +#define R_IIR_SRC_A0 0x0304 +#define R_IIR_SRC_A1 0x0308 +#define R_IIR_DEST_B0 0x030C +#define R_IIR_DEST_B1 0x0310 +#define R_ACC_SRC_C0 0x0314 +#define R_ACC_SRC_C1 0x0318 +#define R_ACC_SRC_D0 0x031C +#define R_ACC_SRC_D1 0x0320 +#define R_IIR_SRC_B1 0x0324 +#define R_IIR_SRC_B0 0x0328 +#define R_MIX_DEST_A0 0x032C +#define R_MIX_DEST_A1 0x0330 +#define R_MIX_DEST_B0 0x0334 +#define R_MIX_DEST_B1 0x0338 +#define REG_A_EEA 0x033C // Address: End address of working area for effects processing (upper part of address only!) + +#define REG_S_ENDX 0x0340 // End Point passed flag + +#define REG_P_STATX 0x0344 // Status register? + +// 0x346 .. 0x3fe are unknown (unused?) + +// core 1 has the same registers with 0x400 added. +// core 1 ends at 0x746 + +// 0x746 .. 0x75e are unknown + +// "Different" register area + +#define REG_P_MVOLL 0x0760 // Master Volume Left +#define REG_P_MVOLR 0x0762 // Master Volume Right +#define REG_P_EVOLL 0x0764 // Effect Volume Left +#define REG_P_EVOLR 0x0766 // Effect Volume Right +#define REG_P_AVOLL 0x0768 // Core External Input Volume Left (Only Core 1) +#define REG_P_AVOLR 0x076A // Core External Input Volume Right (Only Core 1) +#define REG_P_BVOLL 0x076C // Sound Data Volume Left +#define REG_P_BVOLR 0x076E // Sound Data Volume Right +#define REG_P_MVOLXL 0x0770 // Current Master Volume Left +#define REG_P_MVOLXR 0x0772 // Current Master Volume Right + +#define R_IIR_ALPHA 0x0774 //IIR alpha (% used) +#define R_ACC_COEF_A 0x0776 +#define R_ACC_COEF_B 0x0778 +#define R_ACC_COEF_C 0x077A +#define R_ACC_COEF_D 0x077C +#define R_IIR_COEF 0x077E +#define R_FB_ALPHA 0x0780 //feedback alpha (% used) +#define R_FB_X 0x0782 //feedback +#define R_IN_COEF_L 0x0784 +#define R_IN_COEF_R 0x0786 + +// values repeat for core1 + +// End OF "Different" register area + +// SPDIF interface +#define SPDIF_OUT 0x07C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass +#define IRQINFO 0x07C2 +#define SPDIF_MODE 0x07C6 +#define SPDIF_MEDIA 0x07C8 // SPDIF Media: 'CD'/DVD +#define SPDIF_COPY 0x07CC // SPDIF Copy Protection + + +/********************************************************************* +Core attributes (SD_C) + bit 1 - Unknown (this bit is sometimes set) + bit 2..3 - Unknown (usually never set) + bit 4..5 - DMA related + bit 6 - IRQ? DMA mode? wtf? + bit 7 - effect enable (reverb enable) + bit 8 - IRQ enable? + bit 9..14 - noise clock + bit 15 - mute + bit 16 - reset + +*********************************************************************/ + +#define SPDIF_OUT_OFF 0x0000 //no spdif output +#define SPDIF_OUT_PCM 0x0020 //encode spdif from spu2 pcm output +#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing + +#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data +#define SPDIF_MODE_BYPASS_PCM 0x0000 //bypass mode for pcm data (using analog output) + +#define SPDIF_MODE_MEDIA_CD 0x0800 //source media is a CD +#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD + +#define SPDIF_MEDIA_CDVD 0x0200 +#define SPDIF_MEDIA_400 0x0000 + +#define SPDIF_COPY_NORMAL 0x0000 // spdif stream is not protected +#define SPDIF_COPY_PROHIBIT 0x8000 // spdif stream can't be copied + +/********************************************************************/ + +#define VOICE_PARAM_VOLL 0x0 // Voice Volume Left +#define VOICE_PARAM_VOLR 0x2 // Voice Volume Right +#define VOICE_PARAM_PITCH 0x4 // Pitch +#define VOICE_PARAM_ADSR1 0x6 // Envelope 1 (Attack-Delay-Sustain-Release) +#define VOICE_PARAM_ADSR2 0x8 // Envelope 2 (Attack-Delay-Sustain-Release) +#define VOICE_PARAM_ENVX 0xA // Current Envelope +#define VOICE_PARAM_VOLXL 0xC // Current Voice Volume Left +#define VOICE_PARAM_VOLXR 0xE // Current Voice Volume Right + +/********************************************************************/ + +#define VOICE_ADDR_SSA 0x0 // Waveform data starting address +#define VOICE_ADDR_LSAX 0x4 // Loop point address +#define VOICE_ADDR_NAX 0x8 // Waveform data that should be read next + +#endif // REGS_H_INCLUDED // \ No newline at end of file diff --git a/plugins/spu2ghz/src/regtable.h b/plugins/spu2ghz/src/regtable.h new file mode 100644 index 0000000000..ea962fe19c --- /dev/null +++ b/plugins/spu2ghz/src/regtable.h @@ -0,0 +1,308 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#define U16P(x) ((u16*)&(x)) + +#define PCORE(c,p) \ + U16P(Cores[c].##p) + +#define PVCP(c,v,p) \ + PCORE(c,Voices[v].##p) + +#define PVC(c,v) \ + PVCP(c,v,VolumeL.Reg_VOL), \ + PVCP(c,v,VolumeR.Reg_VOL), \ + PVCP(c,v,Pitch), \ + PVCP(c,v,ADSR.Reg_ADSR1), \ + PVCP(c,v,ADSR.Reg_ADSR2), \ + PVCP(c,v,ADSR.Value)+1, \ + PVCP(c,v,VolumeL.Value), \ + PVCP(c,v,VolumeR.Value) + +#define PVCA(c,v) \ + PVCP(c,v,StartA)+1, \ + PVCP(c,v,StartA), \ + PVCP(c,v,LoopStartA)+1, \ + PVCP(c,v,LoopStartA), \ + PVCP(c,v,NextA)+1, \ + PVCP(c,v,NextA) + +#define PRAW(a) \ + ((u16*)NULL) + +#define PREVB_REG(c,n) \ + PCORE(c,Revb.##n)+1, \ + PCORE(c,Revb.##n) + +const u16 zero=0; + +#pragma pack(push,1) +u16* /*const*/ regtable[] = { + // Voice Params: 8 params, 24 voices = 0x180 bytes + PVC(0, 0),PVC(0, 1),PVC(0, 2),PVC(0, 3),PVC(0, 4),PVC(0, 5), + PVC(0, 6),PVC(0, 7),PVC(0, 8),PVC(0, 9),PVC(0,10),PVC(0,11), + PVC(0,12),PVC(0,13),PVC(0,14),PVC(0,15),PVC(0,16),PVC(0,17), + PVC(0,18),PVC(0,19),PVC(0,20),PVC(0,21),PVC(0,22),PVC(0,23), + + PCORE(0,Regs.PMON), + PCORE(0,Regs.PMON)+1, + PCORE(0,Regs.NON), + PCORE(0,Regs.NON)+1, + PCORE(0,Regs.VMIXL), + PCORE(0,Regs.VMIXL)+1, + PCORE(0,Regs.VMIXEL), + PCORE(0,Regs.VMIXEL)+1, + PCORE(0,Regs.VMIXR), + PCORE(0,Regs.VMIXR)+1, + PCORE(0,Regs.VMIXER), + PCORE(0,Regs.VMIXER)+1, + PCORE(0,Regs.MMIX), + + PCORE(0,Regs.ATTR), + + PCORE(0,IRQA)+1, + PCORE(0,IRQA), + + U16P(zero), + U16P(zero), + U16P(zero), + U16P(zero), + + PCORE(0,TSA)+1, + PCORE(0,TSA), + + PRAW(0x1ac), PRAW(0x1ae), + + PCORE(0,AutoDMACtrl), + + PRAW(0x1b2), PRAW(0x1b4), PRAW(0x1b6), PRAW(0x1b8), PRAW(0x1ba), PRAW(0x1bc), PRAW(0x1be), // unknown + + // Voice Addresses + PVCA(0, 0),PVCA(0, 1),PVCA(0, 2),PVCA(0, 3),PVCA(0, 4),PVCA(0, 5), + PVCA(0, 6),PVCA(0, 7),PVCA(0, 8),PVCA(0, 9),PVCA(0,10),PVCA(0,11), + PVCA(0,12),PVCA(0,13),PVCA(0,14),PVCA(0,15),PVCA(0,16),PVCA(0,17), + PVCA(0,18),PVCA(0,19),PVCA(0,20),PVCA(0,21),PVCA(0,22),PVCA(0,23), + + PCORE(0,EffectsStartA)+1, + PCORE(0,EffectsStartA), + + PREVB_REG(0,FB_SRC_A), + PREVB_REG(0,FB_SRC_B), + PREVB_REG(0,IIR_SRC_A0), + PREVB_REG(0,IIR_SRC_A1), + PREVB_REG(0,IIR_SRC_B1), + PREVB_REG(0,IIR_SRC_B0), + PREVB_REG(0,IIR_DEST_A0), + PREVB_REG(0,IIR_DEST_A1), + PREVB_REG(0,IIR_DEST_B0), + PREVB_REG(0,IIR_DEST_B1), + PREVB_REG(0,ACC_SRC_A0), + PREVB_REG(0,ACC_SRC_A1), + PREVB_REG(0,ACC_SRC_B0), + PREVB_REG(0,ACC_SRC_B1), + PREVB_REG(0,ACC_SRC_C0), + PREVB_REG(0,ACC_SRC_C1), + PREVB_REG(0,ACC_SRC_D0), + PREVB_REG(0,ACC_SRC_D1), + PREVB_REG(0,MIX_DEST_A0), + PREVB_REG(0,MIX_DEST_A1), + PREVB_REG(0,MIX_DEST_B0), + PREVB_REG(0,MIX_DEST_B1), + + PCORE(0,EffectsEndA)+1, + U16P(zero), + + PCORE(0,Regs.ENDX), + PCORE(0,Regs.ENDX)+1, + PCORE(0,Regs.STATX), + + //0x346 here + PRAW(0x346), + PRAW(0x348),PRAW(0x34A),PRAW(0x34C),PRAW(0x34E), + PRAW(0x350),PRAW(0x352),PRAW(0x354),PRAW(0x356), + PRAW(0x358),PRAW(0x35A),PRAW(0x35C),PRAW(0x35E), + PRAW(0x360),PRAW(0x362),PRAW(0x364),PRAW(0x366), + PRAW(0x368),PRAW(0x36A),PRAW(0x36C),PRAW(0x36E), + PRAW(0x370),PRAW(0x372),PRAW(0x374),PRAW(0x376), + PRAW(0x378),PRAW(0x37A),PRAW(0x37C),PRAW(0x37E), + PRAW(0x380),PRAW(0x382),PRAW(0x384),PRAW(0x386), + PRAW(0x388),PRAW(0x38A),PRAW(0x38C),PRAW(0x38E), + PRAW(0x390),PRAW(0x392),PRAW(0x394),PRAW(0x396), + PRAW(0x398),PRAW(0x39A),PRAW(0x39C),PRAW(0x39E), + PRAW(0x3A0),PRAW(0x3A2),PRAW(0x3A4),PRAW(0x3A6), + PRAW(0x3A8),PRAW(0x3AA),PRAW(0x3AC),PRAW(0x3AE), + PRAW(0x3B0),PRAW(0x3B2),PRAW(0x3B4),PRAW(0x3B6), + PRAW(0x3B8),PRAW(0x3BA),PRAW(0x3BC),PRAW(0x3BE), + PRAW(0x3C0),PRAW(0x3C2),PRAW(0x3C4),PRAW(0x3C6), + PRAW(0x3C8),PRAW(0x3CA),PRAW(0x3CC),PRAW(0x3CE), + PRAW(0x3D0),PRAW(0x3D2),PRAW(0x3D4),PRAW(0x3D6), + PRAW(0x3D8),PRAW(0x3DA),PRAW(0x3DC),PRAW(0x3DE), + PRAW(0x3E0),PRAW(0x3E2),PRAW(0x3E4),PRAW(0x3E6), + PRAW(0x3E8),PRAW(0x3EA),PRAW(0x3EC),PRAW(0x3EE), + PRAW(0x3F0),PRAW(0x3F2),PRAW(0x3F4),PRAW(0x3F6), + PRAW(0x3F8),PRAW(0x3FA),PRAW(0x3FC),PRAW(0x3FE), + + //AND... we reached 0x400! + // Voice Params: 8 params, 24 voices = 0x180 bytes + PVC(1, 0),PVC(1, 1),PVC(1, 2),PVC(1, 3),PVC(1, 4),PVC(1, 5), + PVC(1, 6),PVC(1, 7),PVC(1, 8),PVC(1, 9),PVC(1,10),PVC(1,11), + PVC(1,12),PVC(1,13),PVC(1,14),PVC(1,15),PVC(1,16),PVC(1,17), + PVC(1,18),PVC(1,19),PVC(1,20),PVC(1,21),PVC(1,22),PVC(1,23), + + PCORE(1,Regs.PMON), + PCORE(1,Regs.PMON)+1, + PCORE(1,Regs.NON), + PCORE(1,Regs.NON)+1, + PCORE(1,Regs.VMIXL), + PCORE(1,Regs.VMIXL)+1, + PCORE(1,Regs.VMIXEL), + PCORE(1,Regs.VMIXEL)+1, + PCORE(1,Regs.VMIXR), + PCORE(1,Regs.VMIXR)+1, + PCORE(1,Regs.VMIXER), + PCORE(1,Regs.VMIXER)+1, + PCORE(1,Regs.MMIX), + + PCORE(1,Regs.ATTR), + + PCORE(1,IRQA)+1, + PCORE(1,IRQA), + + U16P(zero), + U16P(zero), + U16P(zero), + U16P(zero), + + PCORE(1,TSA)+1, + PCORE(1,TSA), + + PRAW(0x5ac), PRAW(0x5ae), + + PCORE(1,AutoDMACtrl), + + PRAW(0x5b2), PRAW(0x5b4), PRAW(0x5b6), PRAW(0x5b8), PRAW(0x5ba), PRAW(0x5bc), PRAW(0x5be), // unknown + + // Voice Addresses + PVCA(1, 0),PVCA(1, 1),PVCA(1, 2),PVCA(1, 3),PVCA(1, 4),PVCA(1, 5), + PVCA(1, 6),PVCA(1, 7),PVCA(1, 8),PVCA(1, 9),PVCA(1,10),PVCA(1,11), + PVCA(1,12),PVCA(1,13),PVCA(1,14),PVCA(1,15),PVCA(1,16),PVCA(1,17), + PVCA(1,18),PVCA(1,19),PVCA(1,20),PVCA(1,21),PVCA(1,22),PVCA(1,23), + + PCORE(1,EffectsStartA)+1, + PCORE(1,EffectsStartA), + + PREVB_REG(1,FB_SRC_A), + PREVB_REG(1,FB_SRC_B), + PREVB_REG(1,IIR_SRC_A0), + PREVB_REG(1,IIR_SRC_A1), + PREVB_REG(1,IIR_SRC_B1), + PREVB_REG(1,IIR_SRC_B0), + PREVB_REG(1,IIR_DEST_A0), + PREVB_REG(1,IIR_DEST_A1), + PREVB_REG(1,IIR_DEST_B0), + PREVB_REG(1,IIR_DEST_B1), + PREVB_REG(1,ACC_SRC_A0), + PREVB_REG(1,ACC_SRC_A1), + PREVB_REG(1,ACC_SRC_B0), + PREVB_REG(1,ACC_SRC_B1), + PREVB_REG(1,ACC_SRC_C0), + PREVB_REG(1,ACC_SRC_C1), + PREVB_REG(1,ACC_SRC_D0), + PREVB_REG(1,ACC_SRC_D1), + PREVB_REG(1,MIX_DEST_A0), + PREVB_REG(1,MIX_DEST_A1), + PREVB_REG(1,MIX_DEST_B0), + PREVB_REG(1,MIX_DEST_B1), + + PCORE(1,EffectsEndA)+1, + U16P(zero), + + PCORE(1,Regs.ENDX), + PCORE(1,Regs.ENDX)+1, + PCORE(1,Regs.STATX), + + PRAW(0x746), + PRAW(0x748),PRAW(0x74A),PRAW(0x74C),PRAW(0x74E), + PRAW(0x750),PRAW(0x752),PRAW(0x754),PRAW(0x756), + PRAW(0x758),PRAW(0x75A),PRAW(0x75C),PRAW(0x75E), + + //0x760: weird area + PCORE(0,MasterL.Reg_VOL), + PCORE(0,MasterR.Reg_VOL), + PCORE(0,FxL), + PCORE(0,FxR), + PCORE(0,ExtL), + PCORE(0,ExtR), + PCORE(0,InpL), + PCORE(0,InpR), + PCORE(0,MasterL.Value), + PCORE(0,MasterR.Value), + PCORE(0,Revb.IIR_ALPHA), + PCORE(0,Revb.ACC_COEF_A), + PCORE(0,Revb.ACC_COEF_B), + PCORE(0,Revb.ACC_COEF_C), + PCORE(0,Revb.ACC_COEF_D), + PCORE(0,Revb.IIR_COEF), + PCORE(0,Revb.FB_ALPHA), + PCORE(0,Revb.FB_X), + PCORE(0,Revb.IN_COEF_L), + PCORE(0,Revb.IN_COEF_R), + + PCORE(1,MasterL.Reg_VOL), + PCORE(1,MasterR.Reg_VOL), + PCORE(1,FxL), + PCORE(1,FxR), + PCORE(1,ExtL), + PCORE(1,ExtR), + PCORE(1,InpL), + PCORE(1,InpR), + PCORE(1,MasterL.Value), + PCORE(1,MasterR.Value), + PCORE(1,Revb.IIR_ALPHA), + PCORE(1,Revb.ACC_COEF_A), + PCORE(1,Revb.ACC_COEF_B), + PCORE(1,Revb.ACC_COEF_C), + PCORE(1,Revb.ACC_COEF_D), + PCORE(1,Revb.IIR_COEF), + PCORE(1,Revb.FB_ALPHA), + PCORE(1,Revb.FB_X), + PCORE(1,Revb.IN_COEF_L), + PCORE(1,Revb.IN_COEF_R), + + PRAW(0x7B0),PRAW(0x7B2),PRAW(0x7B4),PRAW(0x7B6), + PRAW(0x7B8),PRAW(0x7BA),PRAW(0x7BC),PRAW(0x7BE), + + // SPDIF interface + U16P(Spdif.Out), + U16P(Spdif.Info), + U16P(Spdif.Unknown1), + U16P(Spdif.Mode), + U16P(Spdif.Media), + U16P(Spdif.Unknown2), + U16P(Spdif.Protection), + + PRAW(0x7CE), + PRAW(0x7D0),PRAW(0x7D2),PRAW(0x7D4),PRAW(0x7D6), + PRAW(0x7D8),PRAW(0x7DA),PRAW(0x7DC),PRAW(0x7DE), + PRAW(0x7E0),PRAW(0x7E2),PRAW(0x7E4),PRAW(0x7E6), + PRAW(0x7E8),PRAW(0x7EA),PRAW(0x7EC),PRAW(0x7EE), + PRAW(0x7F0),PRAW(0x7F2),PRAW(0x7F4),PRAW(0x7F6), + PRAW(0x7F8),PRAW(0x7FA),PRAW(0x7FC),PRAW(0x7FE), + + U16P(zero) +}; diff --git a/plugins/spu2ghz/src/sndout.cpp b/plugins/spu2ghz/src/sndout.cpp new file mode 100644 index 0000000000..f63e5acb7d --- /dev/null +++ b/plugins/spu2ghz/src/sndout.cpp @@ -0,0 +1,892 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +// [TODO] : The layout of this code file is now a complete hackish mess after +// numerous timestretch-related additions. The whole thing should really be +// rethought and redone at this point. + +#include "spu2.h" +#include "SoundTouch/SoundTouch.h" +#include "SoundTouch/WavFile.h" + +#include + +static int ts_stats_stretchblocks = 0; +static int ts_stats_normalblocks = 0; +static int ts_stats_logcounter = 0; + +class NullOutModule: public SndOutModule +{ +public: + s32 Init(SndBuffer *) { return 0; } + void Close() { } + s32 Test() const { return 0; } + void Configure(HWND parent) { } + bool Is51Out() const { return false; } + int GetEmptySampleCount() const { return 0; } + + const char* GetIdent() const + { + return "nullout"; + } + + const char* GetLongName() const + { + return "No Sound (Emulate SPU2 only)"; + } + +} NullOut; + +SndOutModule* mods[]= +{ + &NullOut, + WaveOut, + DSoundOut, + //DSound51Out, + //ASIOOut, + XAudio2Out, + NULL // signals the end of our list +}; + +int FindOutputModuleById( const char* omodid ) +{ + int modcnt = 0; + while( mods[modcnt] != NULL ) + { + if( strcmp( mods[modcnt]->GetIdent(), omodid ) == 0 ) + break; + ++modcnt; + } + return modcnt; +} + + +// Overall master volume shift. +// Converts the mixer's 32 bit value into a 16 bit value. +int SndOutVolumeShift = SndOutVolumeShiftBase + 1; + +static __forceinline s16 SndScaleVol( s32 inval ) +{ + return inval >> SndOutVolumeShift; +} + + +// records last buffer status (fill %, range -100 to 100, with 0 being 50% full) +float lastPct; +float lastEmergencyAdj; + +float cTempo=1; +float eTempo = 1; +int freezeTempo = 0; + +soundtouch::SoundTouch* pSoundTouch=NULL; + + +//usefull when timestretch isn't available +//#define DYNAMIC_BUFFER_LIMITING + +class SndBufferImpl: public SndBuffer +{ +private: + s32 *buffer; + s32 size; + s32 rpos; + s32 wpos; + s32 data; + + // data prediction amount, used to "commit" data that hasn't + // finished timestretch processing. + s32 predictData; + + bool pw; + + bool underrun_freeze; + HANDLE hSyncEvent; + CRITICAL_SECTION cs; + +protected: + int GetAlignedBufferSize( int comp ) + { + return (comp + SndOutPacketSize-1) & ~(SndOutPacketSize-1); + } + +public: + SndBufferImpl( float latencyMS ) + { + rpos=0; + wpos=0; + data=0; + size=GetAlignedBufferSize( (int)(latencyMS * SampleRate / 500.0f ) ); + buffer = new s32[size]; + pw=false; + underrun_freeze = false; + predictData = 0; + +#ifdef DYNAMIC_BUFFER_LIMITING + overflows=0; + underflows=0; + writewaits=0; + buffer_limit=size; +#endif + InitializeCriticalSection(&cs); + hSyncEvent = CreateEvent(NULL,FALSE,FALSE,NULL); + } + + virtual ~SndBufferImpl() + { + pw=false; + PulseEvent(hSyncEvent); + Sleep(10); + EnterCriticalSection(&cs); + LeaveCriticalSection(&cs); + DeleteCriticalSection(&cs); + CloseHandle(hSyncEvent); + delete buffer; + } + + virtual void WriteSamples(s32 *bData, int nSamples) + { + EnterCriticalSection(&cs); + int free = size-data; + predictData = 0; + + jASSUME( data <= size ); + + if( pw && ( free < nSamples ) ) + { + // Wait for a ReadSamples to pull some stuff out of the buffer. + // One SyncEvent will do the trick. + ResetEvent( hSyncEvent ); + LeaveCriticalSection(&cs); + WaitForSingleObject(hSyncEvent,20); + EnterCriticalSection(&cs); + } + + // Problem: + // If the SPU2 gets out of sync with the SndOut device, the writepos of the + // circular buffer will overtake the readpos, leading to a prolonged period + // of hopscotching read/write accesses (ie, lots of staticy crap sound for + // several seconds). + // + // Compromise: + // When an overrun occurs, we adapt by discarding a portion of the buffer. + // The older portion of the buffer is discarded rather than incoming data, + // so that the overall audio synchronization is better. + + if( free < nSamples ) + { + // Buffer overrun! + // Dump samples from the read portion of the buffer instead of dropping + // the newly written stuff. + + s32 comp; + + if( timeStretchEnabled ) + { + // If we overran it means the timestretcher failed. We need to speed + // up audio playback. + cTempo += cTempo * 0.12f; + eTempo += eTempo * 0.40f; + if( eTempo > 7.5f ) eTempo = 7.5f; + pSoundTouch->setTempo( eTempo ); + + // Throw out just a little bit (two packets worth) to help + // give the TS some room to work: + + comp = SndOutPacketSize*2; + } + else + { + // Toss half the buffer plus whatever's being written anew: + comp = GetAlignedBufferSize( (size + nSamples ) / 2 ); + if( comp > (size-SndOutPacketSize) ) comp = size-SndOutPacketSize; + } + + data-=comp; + rpos=(rpos+comp)%size; + if( MsgOverruns() ) + ConLog(" * SPU2 > Overrun Compensation (%d packets tossed)\n", comp / SndOutPacketSize ); + lastPct = 0.0; // normalize the timestretcher + } + + // copy in two phases, since there's a chance the packet + // wraps around the buffer (it'd be nice to deal in packets only, but + // the timestretcher and DSP options require flexibility). + + const int endPos = wpos + nSamples; + const int secondCopyLen = endPos - size; + s32* wposbuffer = &buffer[wpos]; + + data += nSamples; + if( secondCopyLen > 0 ) + { + nSamples -= secondCopyLen; + memcpy( buffer, &bData[nSamples], secondCopyLen * sizeof( *bData ) ); + wpos = secondCopyLen; + } + else + wpos += nSamples; + + memcpy( wposbuffer, bData, nSamples * sizeof( *bData ) ); + + LeaveCriticalSection(&cs); + } + + protected: + // Returns TRUE if there is data to be output, or false if no data + // is available to be copied. + bool CheckUnderrunStatus( int& nSamples, int& quietSampleCount ) + { + quietSampleCount = 0; + if( underrun_freeze ) + { + int toFill = (int)(size * ( timeStretchEnabled ? 0.1f : 0.50f ) ); + toFill = GetAlignedBufferSize( toFill ); + + // toFill is now aligned to a SndOutPacket + + if( data < toFill ) + { + quietSampleCount = nSamples; + return false; + } + + underrun_freeze = false; + if( MsgOverruns() ) + ConLog(" * SPU2 > Underrun compensation (%d packets buffered)\n", toFill / SndOutPacketSize ); + lastPct = 0.0; // normalize timestretcher + } + else if( data < nSamples ) + { + nSamples = data; + quietSampleCount = SndOutPacketSize - data; + underrun_freeze = true; + + if( timeStretchEnabled ) + { + // timeStretcher failed it's job. We need to slow down the audio some. + + cTempo -= (cTempo * 0.12f); + eTempo -= (eTempo * 0.30f); + if( eTempo < 0.1f ) eTempo = 0.1f; + pSoundTouch->setTempo( eTempo ); + } + + return nSamples != 0; + } + + return true; + } + + public: + void ReadSamples( s16* bData ) + { + int nSamples = SndOutPacketSize; + + EnterCriticalSection(&cs); + + // Problem: + // If the SPU2 gets even the least bit out of sync with the SndOut device, + // the readpos of the circular buffer will overtake the writepos, + // leading to a prolonged period of hopscotching read/write accesses (ie, + // lots of staticy crap sound for several seconds). + // + // Fix: + // If the read position overtakes the write position, abort the + // transfer immediately and force the SndOut driver to wait until + // the read buffer has filled up again before proceeding. + // This will cause one brief hiccup that can never exceed the user's + // set buffer length in duration. + + int quietSamples; + if( CheckUnderrunStatus( nSamples, quietSamples ) ) + { + jASSUME( nSamples <= SndOutPacketSize ); + + // [Air] [TODO]: This loop is probably a candidiate for SSE2 optimization. + + const int endPos = rpos + nSamples; + const int secondCopyLen = endPos - size; + const s32* rposbuffer = &buffer[rpos]; + + data -= nSamples; + + if( secondCopyLen > 0 ) + { + nSamples -= secondCopyLen; + for( int i=0; i 0 ) + { + nSamples -= secondCopyLen; + memcpy( &bData[nSamples], buffer, secondCopyLen * sizeof( *bData ) ); + rpos = secondCopyLen; + } + else + rpos += nSamples; + + memcpy( bData, &buffer[oldrpos], nSamples * sizeof( *bData ) ); + } + + // If quietSamples != 0 it means we have an underrun... + // Let's just dull out some silence, because that's usually the least + // painful way of dealing with underruns: + memset( bData, 0, quietSamples * sizeof(*bData) ); + PulseEvent(hSyncEvent); + LeaveCriticalSection(&cs); + } + + void PredictDataWrite( int samples ) + { + predictData += samples; + } + + virtual void PauseOnWrite(bool doPause) { pw = doPause; } + + // Calculate the buffer status percentage. + // Returns range from -1.0 to 1.0 + // 1.0 = buffer overflow! + // 0.0 = buffer nominal (50% full) + // -1.0 = buffer underflow! + float GetStatusPct() + { + EnterCriticalSection(&cs); + + // Get the buffer status of the output driver too, so that we can + // obtain a more accurate overall buffer status. + + int drvempty = mods[OutputModule]->GetEmptySampleCount(); // / 2; + + //ConLog( "Data %d >>> driver: %d predict: %d\n", data, drvempty, predictData ); + + float result = (float)(data + predictData - drvempty) - (size/2); + result /= (size/2); + LeaveCriticalSection(&cs); + return result; + } + +}; + +SndBufferImpl *sndBuffer=NULL; + +s32* sndTempBuffer=NULL; +s32 sndTempProgress=NULL; +s16* sndTempBuffer16=NULL; + +void UpdateTempoChange() +{ + if( --freezeTempo > 0 ) + { + return; + } + + float statusPct = sndBuffer->GetStatusPct(); + float pctChange = statusPct - lastPct; + + float tempoChange; + float emergencyAdj = 0; + float newcee = cTempo; // workspace var. for cTempo + + // IMPORTANT! + // If you plan to tweak these values, make sure you're using a release build + // OUTSIDE THE DEBUGGER to test it! The Visual Studio debugger can really cause + // erratic behavior in the audio buffers, and makes the timestretcher seem a + // lot more inconsistent than it really is. + + // We have two factors. + // * Distance from nominal buffer status (50% full) + // * The change from previous update to this update. + + // Prediction based on the buffer change: + // (linear seems to work better here) + + tempoChange = pctChange * 0.75f; + + if( statusPct * tempoChange < 0.0f ) + { + // only apply tempo change if it is in synch with the buffer status. + // In other words, if the buffer is high (over 0%), and is decreasing, + // ignore it. It'll just muck things up. + + tempoChange = 0; + } + + // Sudden spikes in framerate can cause the nominal buffer status + // to go critical, in which case we have to enact an emergency + // stretch. The following cubic formulas do that. Values near + // the extremeites give much larger results than those near 0. + // And the value is added only this time, and does not accumulate. + // (otherwise a large value like this would cause problems down the road) + + // Constants: + // Weight - weights the statusPct's "emergency" consideration. + // higher values here will make the buffer perform more drastic + // compensations at the outter edges of the buffer (at -75 or +75% + // or beyond, for example). + + // Range - scales the adjustment to the given range (more or less). + // The actual range is dependent on the weight used, so if you increase + // Weight you'll usually want to decrease Range somewhat to compensate. + + // Prediction based on the buffer fill status: + + const float statusWeight = 2.99f; + const float statusRange = 0.068f; + + // "non-emergency" deadzone: In this area stretching will be strongly discouraged. + // Note: due tot he nature of timestretch latency, it's always a wee bit harder to + // cope with low fps (underruns) tha it is high fps (overruns). So to help out a + // little, the low-end portions of this check are less forgiving than the high-sides. + + if( cTempo < 0.965f || cTempo > 1.060f || + pctChange < -0.38f || pctChange > 0.54f || + statusPct < -0.32f || statusPct > 0.39f || + eTempo < 0.89f || eTempo > 1.19f ) + { + emergencyAdj = ( pow( statusPct*statusWeight, 3.0f ) * statusRange); + } + + // Smooth things out by factoring our previous adjustment into this one. + // It helps make the system 'feel' a little smarter by giving it at least + // one packet worth of history to help work off of: + + emergencyAdj = (emergencyAdj * 0.75f) + (lastEmergencyAdj * 0.25f ); + + lastEmergencyAdj = emergencyAdj; + lastPct = statusPct; + + // Accumulate a fraction of the tempo change into the tempo itself. + // This helps the system run "smarter" to games that run consistently + // fast or slow by altering the base tempo to something closer to the + // game's active speed. In tests most games normalize within 2 seconds + // at 100ms latency, which is pretty good (larger buffers normalize even + // quicker). + + newcee += newcee * (tempoChange+emergencyAdj) * 0.03f; + + // Apply tempoChange as a scale of cTempo. That way the effect is proportional + // to the current tempo. (otherwise tempos rate of change at the extremes would + // be too drastic) + + float newTempo = newcee + ( emergencyAdj * cTempo ); + + // ... and as a final optimization, only stretch if the new tempo is outside + // a nominal threshold. Keep this threshold check small, because it could + // cause some serious side effects otherwise. (enlarging the cTempo check above + // is usually better/safer) + if( newTempo < 0.970f || newTempo > 1.045f ) + { + cTempo = (float)newcee; + + if( newTempo < 0.10f ) newTempo = 0.10f; + else if( newTempo > 10.0f ) newTempo = 10.0f; + + if( cTempo < 0.15f ) cTempo = 0.15f; + else if( cTempo > 7.5f ) cTempo = 7.5f; + + pSoundTouch->setTempo( eTempo = (float)newTempo ); + ts_stats_stretchblocks++; + + /*ConLog(" * SPU2: [Nominal %d%%] [Emergency: %d%%] (baseTempo: %d%% ) (newTempo: %d%%) (buffer: %d%%)\n", + //(relation < 0.0) ? "Normalize" : "", + (int)(tempoChange * 100.0 * 0.03), + (int)(emergencyAdj * 100.0), + (int)(cTempo * 100.0), + (int)(newTempo * 100.0), + (int)(statusPct * 100.0) + );*/ + } + else + { + // Nominal operation -- turn off stretching. + // note: eTempo 'slides' toward 1.0 for smoother audio and better + // protection against spikes. + if( cTempo != 1.0f ) + { + cTempo = 1.0f; + eTempo = ( 1.0f + eTempo ) * 0.5f; + pSoundTouch->setTempo( eTempo ); + } + else + { + if( eTempo != cTempo ) + pSoundTouch->setTempo( eTempo=cTempo ); + ts_stats_normalblocks++; + } + } +} + + +void soundtouchInit() +{ + pSoundTouch = new soundtouch::SoundTouch(); + pSoundTouch->setSampleRate(SampleRate); + pSoundTouch->setChannels(2); + + pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 0); + pSoundTouch->setSetting(SETTING_USE_AA_FILTER, 0); + pSoundTouch->setTempo(1); + + // some timestretch management vars: + + cTempo = 1.0; + eTempo = 1.0; + lastPct = 0; + lastEmergencyAdj = 0; + + // just freeze tempo changes for a while at startup. + // the driver buffers are bogus anyway. + freezeTempo = 8; +} + +static void _sndInitFail() +{ + // If a failure occurs, just initialize the NoSound driver. This'll allow + // the game to emulate properly (hopefully), albeit without sound. + OutputModule = FindOutputModuleById( NullOut.GetIdent() ); + mods[OutputModule]->Init( sndBuffer ); +} + +s32 SndInit() +{ + if( mods[OutputModule] == NULL ) + { + _sndInitFail(); + return 0; + } + + // initialize sound buffer + // Buffer actually attempts to run ~50%, so allocate near double what + // the requested latency is: + + try + { + sndBuffer = new SndBufferImpl( SndOutLatencyMS * (timeStretchEnabled ? 2.0f : 1.5f) ); + sndTempBuffer = new s32[SndOutPacketSize]; + sndTempBuffer16 = new s16[SndOutPacketSize]; + } + catch( std::bad_alloc& ) + { + // out of memory exception (most likely) + + SysMessage( "Out of memory error occured while initializing SPU2." ); + _sndInitFail(); + return 0; + } + + // clear buffers! + // Fixes loopy sounds on emu resets. + memset( sndTempBuffer, 0, sizeof(s32) * SndOutPacketSize ); + memset( sndTempBuffer16, 0, sizeof(s16) * SndOutPacketSize ); + + sndTempProgress = 0; + + soundtouchInit(); // initializes the timestretching + + if(LimitMode!=0) + { + sndBuffer->PauseOnWrite(true); + } + + // some crap + spdif_set51(mods[OutputModule]->Is51Out()); + + // initialize module + if( mods[OutputModule]->Init(sndBuffer) == -1 ) + { + _sndInitFail(); + } + + return 0; +} + +void SndClose() +{ + mods[OutputModule]->Close(); + + SAFE_DELETE_OBJ( sndBuffer ); + SAFE_DELETE_ARRAY( sndTempBuffer ); + SAFE_DELETE_ARRAY( sndTempBuffer16 ); + SAFE_DELETE_OBJ( pSoundTouch ); +} + +void SndUpdateLimitMode() +{ + //sndBuffer->PauseOnWrite(LimitMode!=0); + + if(LimitMode!=0) { + timeStretchEnabled = true; + //printf(" * SPU2 limiter is now ON.\n"); + printf(" * SPU2 timestretch is now ON.\n"); + } + else { + //printf(" * SPU2 limiter is now OFF.\n"); + printf(" * SPU2 timestretch is now OFF.\n"); + timeStretchEnabled = false; + } + +} + + +s32 SndWrite(s32 ValL, s32 ValR) +{ + #ifndef PUBLIC + if(WaveLog() && wavedump_ok) + { + wavedump_write(SndScaleVol(ValL),SndScaleVol(ValR)); + } + #endif + + if(recording!=0) + RecordWrite(SndScaleVol(ValL),SndScaleVol(ValR)); + + if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p + return 0; + + sndTempBuffer[sndTempProgress++] = ValL; + sndTempBuffer[sndTempProgress++] = ValR; + + // If we haven't accumulated a full packet yet, do nothing more: + if(sndTempProgress < SndOutPacketSize) return 1; + + if(dspPluginEnabled) + { + for(int i=0;i>1)<<1; + + for(int i=0;iPredictDataWrite( (int)( sndTempProgress / eTempo ) ); + for(int i=0;iputSamples((float*)sndTempBuffer, sndTempProgress>>1); + + while( ( sndTempProgress = pSoundTouch->receiveSamples((float*)sndTempBuffer, sndTempProgress>>1)<<1 ) != 0 ) + { + // [Air] [TODO] : Implement an SSE downsampler to int. + for(int i=0;iWriteSamples(sndTempBuffer, sndTempProgress); + progress = true; + } + + UpdateTempoChange(); + + if( MsgOverruns() ) + { + if( progress ) + { + if( ++ts_stats_logcounter > 300 ) + { + ts_stats_logcounter = 0; + ConLog( " * SPU2 > Timestretch Stats > %d%% of packets stretched.\n", + ( ts_stats_stretchblocks * 100 ) / ( ts_stats_normalblocks + ts_stats_stretchblocks ) ); + ts_stats_normalblocks = 0; + ts_stats_stretchblocks = 0; + } + } + } + } + else + { + sndBuffer->WriteSamples(sndTempBuffer, sndTempProgress); + sndTempProgress=0; + } + + return 1; +} + +s32 SndTest() +{ + if( mods[OutputModule] == NULL ) + return -1; + + return mods[OutputModule]->Test(); +} + +void SndConfigure(HWND parent, u32 module ) +{ + if( mods[module] == NULL ) + return; + + mods[module]->Configure(parent); +} + +#if 0 +////////////////////////////////////////////////////////////// +// Basic Timestretcher (50% to 150%) +const s32 StretchBufferSize = 2048; + +s32 stretchBufferL[StretchBufferSize*2]; +s32 stretchBufferR[StretchBufferSize*2]; +s32 stretchPosition=0; + +s32 stretchOutputSize = 2048; // valid values from 1024 to 3072 + +s32 blah; + +extern float cspeed; +void TimestretchUpdate(int bufferusage,int buffersize) +{ + if(cspeed>1.01) + { + stretchOutputSize+=10; + } + else if (cspeed<0.99) + { + stretchOutputSize-=10; + } + + blah++; + if(blah>=2) + { + blah=0; + + printf(" * Stretch = %d of %d\n",stretchOutputSize,StretchBufferSize); + } +} + +s32 SndWriteStretch(s32 ValL, s32 ValR) +{ + // TODO: update stretchOutputSize according to speed :P + + stretchBufferL[stretchPosition] = ValL; + stretchBufferR[stretchPosition] = ValR; + + stretchPosition++; + if(stretchPosition>=StretchBufferSize) + { + stretchPosition=0; + + if(stretchOutputSize < (StretchBufferSize/2)) + stretchOutputSize=(StretchBufferSize/2); + if(stretchOutputSize > (StretchBufferSize*3/2)) + stretchOutputSize=(StretchBufferSize*3/2); + + if(stretchOutputSize>StretchBufferSize) + { + int K = (stretchOutputSize-StretchBufferSize); + int J = StretchBufferSize - K; + + // K samples offset + for(int i=StretchBufferSize;i +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef SNDOUT_H_INCLUDE +#define SNDOUT_H_INCLUDE + +// Number of stereo samples per SndOut block. +// All drivers must work in units of this size when communicating with +// SndOut. +static const int SndOutPacketSize = 1024; + +static const int SndOutVolumeShiftBase = 8; +extern int SndOutVolumeShift; + +#define pcmlog +extern FILE *wavelog; + +s32 SndInit(); +void SndClose(); +s32 SndWrite(s32 ValL, s32 ValR); +s32 SndTest(); +void SndConfigure(HWND parent, u32 outmodidx ); +bool SndGetStats(u32 *written, u32 *played); + +int FindOutputModuleById( const char* omodid ); + +class SndBuffer +{ +public: + virtual ~SndBuffer() {} + + virtual void WriteSamples(s32 *buffer, int nSamples)=0; + virtual void PauseOnWrite(bool doPause)=0; + + virtual void ReadSamples( s16* bData )=0; + virtual void ReadSamples( s32* bData )=0; + + //virtual s32 GetBufferUsage()=0; + //virtual s32 GetBufferSize()=0; +}; + +class SndOutModule +{ +public: + // Virtual destructor, because it helps fight C+++ funny-business. + virtual ~SndOutModule(){}; + + // Returns a unique identification string for this driver. + // (usually just matches the driver's cpp filename) + virtual const char* GetIdent() const=0; + + // Returns the long name / description for this driver. + // (for use in configuration screen) + virtual const char* GetLongName() const=0; + + virtual s32 Init(SndBuffer *buffer)=0; + virtual void Close()=0; + virtual s32 Test() const=0; + virtual void Configure(HWND parent)=0; + virtual bool Is51Out() const=0; + + // Returns the number of empty samples in the output buffer. + // (which is effectively the amount of data played since the last update) + virtual int GetEmptySampleCount() const=0; +}; + +//internal +extern SndOutModule *WaveOut; +extern SndOutModule *DSoundOut; +extern SndOutModule *FModOut; +extern SndOutModule *ASIOOut; +extern SndOutModule *XAudio2Out; +extern SndOutModule *DSound51Out; + +extern SndOutModule* mods[]; + +#endif // SNDOUT_H_INCLUDE diff --git a/plugins/spu2ghz/src/spdif.h b/plugins/spu2ghz/src/spdif.h new file mode 100644 index 0000000000..7d19a36c04 --- /dev/null +++ b/plugins/spu2ghz/src/spdif.h @@ -0,0 +1,112 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef SPDIF_H_INCLUDED +#define SPDIF_H_INCLUDED + +#ifndef u32 +typedef unsigned int u32; +#endif + +/* + Preamble cell-order cell-order + (last cell "0") (last cell "1") + ---------------------------------------------- + "B" 11101000 00010111 + "M" 11100010 00011101 + "W" 11100100 00011011 + + Only the lower 4 bits are used. + +Preamble B: Marks a word containing data for channel A (left) + at the start of the data-block. + +Preamble M: Marks a word with data for channel A that isn't + at the start of the data-block. + +Preamble W: Marks a word containing data for channel B. + (right, for stereo). When using more than 2 + channels, this could also be any other channel + (except for A). + + bits meaning + ---------------------------------------------------------- + 0-3 Preamble (see above; special structure) + + 4-7 Auxillary-audio-databits + + 8-27 Sample + (A 24-bit sample can be used (using bits 4-27). + A CD-player uses only 16 bits, so only bits + 13 (LSB) to 27 (MSB) are used. Bits 4-12 are + set to 0). + + 28 Validity + (When this bit is set, the sample should not + be used by the receiver. A CD-player uses + the 'error-flag' to set this bit). + + 29 Subcode-data + + 30 Channel-status-information + + 31 Parity (bit 0-3 are not included) + +*/ + +typedef struct _subframe +{ + u32 preamble:4; + u32 aux_data:4; + u32 snd_data:20; + u32 validity:1; + u32 subcode:1; + u32 chstatus:1; + u32 parity:1; +} subframe; + +/* + bit meaning + ------------------------------------------------------------- + 0-3 controlbits: + bit 0: 0 (is set to 1 during 4 channel transmission) + bit 1: 0=Digital audio, 1=Non-audio (reserved to be 0 on old S/PDIF specs) + bit 2: copy-protection. Copying is allowed when this bit is set. + bit 3: is set when pre-emphasis is used. + + 4-7 0 (reserved) + + 9-15 catagory-code: + 0 = common 2-channel format + 1 = 2-channel CD-format + (set by a CD-player when a subcode is transmitted) + 2 = 2-channel PCM-encoder-decoder format + + others are not used + + 19-191 0 (reserved) +*/ + +typedef struct _chstatus +{ + u8 ctrlbits:4; + u8 reservd1:4; + u8 category; + u8 reservd2[22]; +} chstatus: + +#endif//SPDIF_H_INCLUDED \ No newline at end of file diff --git a/plugins/spu2ghz/src/spu2.cpp b/plugins/spu2ghz/src/spu2.cpp new file mode 100644 index 0000000000..03bb0fa8cc --- /dev/null +++ b/plugins/spu2ghz/src/spu2.cpp @@ -0,0 +1,2037 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "SPU2.h" +#include "resource.h" +#include + +#include "regtable.h" +#include "svnrev.h" + +void StartVoices(int core, u32 value); +void StopVoices(int core, u32 value); + +void InitADSR(); + +const unsigned char version = PS2E_SPU2_VERSION; +const unsigned char revision = 1; +const unsigned char build = 9; // increase that with each version + +static __forceinline void SPU2_FastWrite( u32 rmem, u16 value ); +static void SPU2writeLog(u32 rmem, u16 value); +DWORD CALLBACK TimeThread(PVOID /* unused param */); + + +const char *ParamNames[8]={"VOLL","VOLR","PITCH","ADSR1","ADSR2","ENVX","VOLXL","VOLXR"}; +const char *AddressNames[6]={"SSAH","SSAL","LSAH","LSAL","NAXH","NAXL"}; + +double opitch; +int osps; + +// [Air]: Adding the spu2init boolean wasn't necessary except to help me in +// debugging the spu2 suspend/resume behavior (when user hits escape). +static bool spu2open=false; // has spu2open plugin interface been called? +static bool spu2init=false; // has spu2init plugin interface been called? + +// [Air]: fixed the hacky part of UpdateTimer with this: +static bool resetClock = true; + +// Used to make spu2 more robust at loading incompatible saves. +// Disables re-freezing of save state data. +bool disableFreezes=false; + +void (* _irqcallback)(); +void (* dma4callback)(); +void (* dma7callback)(); + +short *spu2regs; +short *_spu2mem; +s32 uTicks; + +u8 callirq; + +HANDLE hThreadFunc; +u32 ThreadFuncID; + +#ifndef PUBLIC +V_CoreDebug DebugCores[2]; +#endif +V_Core Cores[2]; +V_SPDIF Spdif; + +s16 OutPos; +s16 InputPos; +u8 InpBuff; +u32 Cycles; +u32 Num; +u32 acumCycles; + +u32* cPtr=NULL; +u32 lClocks=0; +u32 pClocks=0; + +bool hasPtr=false; + +int PlayMode; + +s16 attrhack[2]={0,0}; + +HINSTANCE hInstance; + +bool debugDialogOpen=false; +HWND hDebugDialog=NULL; + +static char libraryName[256]; + +CRITICAL_SECTION threadSync; + +s32 logvolume[16384]; + +bool has_to_call_irq=false; + +void SetIrqCall() +{ + has_to_call_irq=true; +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD dwReason,LPVOID lpvReserved) +{ + if(dwReason==DLL_PROCESS_ATTACH) hInstance=hinstDLL; + return TRUE; +} + +void SysMessage(const char *fmt, ...) +{ + va_list list; + char tmp[512]; + + va_start(list,fmt); + sprintf_s(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "SPU2ghz Msg", 0); +} + +static void InitLibraryName() +{ +#ifdef PUBLIC + + // Public Release! + // Output a simplified string that's just our name: + + strcpy( libraryName, "SPU2ghz Playground" ); + +#elif defined( SVN_REV_UNKNOWN ) + + // Unknown revision. + // Output a name that includes devbuild status but not + // subversion revision tags: + + strcpy( libraryName, "SPU2ghz Playground" +# ifdef _DEBUG_FAST + "-Debug" +# elif defined( DEBUG ) + "-Debug/Strict" // strict debugging is slow! +# else + "-Dev" +# endif + ); +#else + + // Use TortoiseSVN's SubWCRev utility's output + // to label the specific revision: + + sprintf_s( libraryName, "SPU2ghz PG r%d%s" +# ifdef _DEBUG_FAST + "-Debug" +# elif defined( _DEBUG ) + "-Debug/Strict" // strict debugging is slow! +# else + "-Dev" +# endif + ,SVN_REV, + SVN_MODS ? "m" : "" + ); +#endif + +} + +EXPORT_C_(u32) PS2EgetLibType() +{ + return PS2E_LT_SPU2; +} + +EXPORT_C_(char*) PS2EgetLibName() +{ + InitLibraryName(); + return libraryName; +} + +EXPORT_C_(u32) PS2EgetLibVersion2(u32 type) +{ + return (version<<16)|(revision<<8)|build; +} + +EXPORT_C_(void) SPU2configure() { + configure(); +} + +EXPORT_C_(void) SPU2about() { + InitLibraryName(); + SysMessage( libraryName ); +} + +EXPORT_C_(s32) SPU2test() { + return SndTest(); +} + + +__forceinline s16 * __fastcall GetMemPtr(u32 addr) +{ +#ifndef _DEBUG_FAST + // In case you're wondering, this assert is the reason spu2ghz + // runs so incrediously slow in Debug mode. :P + assert(addr<0x100000); +#endif + return (_spu2mem+addr); +} + +__forceinline s16 __fastcall spu2M_Read( u32 addr ) +{ + return *GetMemPtr( addr & 0xfffff ); +} + +// writes a signed value to the SPU2 ram +// Invalidates the ADPCM cache in the process. +// Optimization note: don't use __forceinline because the footprint of this +// function is a little too heavy now. Better to let the compiler decide. +__inline void __fastcall spu2M_Write( u32 addr, s16 value ) +{ + // Make sure the cache is invalidated: + // (note to self : addr address WORDs, not bytes) + + addr &= 0xfffff; + if( addr >= SPU2_DYN_MEMLINE ) + { + const int cacheIdx = addr / pcm_WordsPerBlock; + pcm_cache_data[cacheIdx].Validated = false; + + ConLog( " * SPU2 : PcmCache Block Clear at 0x%x (cacheIdx=0x%x)\n", addr, cacheIdx); + } + *GetMemPtr( addr ) = value; +} + +// writes an unsigned value to the SPU2 ram +__inline void __fastcall spu2M_Write( u32 addr, u16 value ) +{ + spu2M_Write( addr, (s16)value ); +} + +void AssignVolume(V_Volume& vol, s16 value) +{ + vol.Reg_VOL = value; + if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp + vol.Mode=(value & 0xF000)>>12; + vol.Increment=(value & 0x3F); + } + else { + vol.Mode=0; + vol.Increment=0; + + value<<=1; + vol.Value=value; + + } +} + +void CoreReset(int c) +{ +#define DEFAULT_VOICE_VOLUME 0x3FFF + int v=0; + + ConLog(" * SPU2: Initializing core %d structures... ",c); + + memset(Cores+c,0,sizeof(Cores[c])); + + Cores[c].Regs.STATX=0; + Cores[c].Regs.ATTR=0; + Cores[c].ExtL=0x3FFF; + Cores[c].ExtR=0x3FFF; + Cores[c].InpL=0x3FFF; + Cores[c].InpR=0x3FFF; + Cores[c].FxL=0x7FFF; + Cores[c].FxR=0x7FFF; + Cores[c].MasterL.Reg_VOL=0x3FFF; + Cores[c].MasterL.Value=0x7FFF; + Cores[c].MasterR.Reg_VOL=0x3FFF; + Cores[c].MasterR.Value=0x7FFF; + Cores[c].ExtWetR=1; + Cores[c].ExtWetL=1; + Cores[c].ExtDryR=1; + Cores[c].ExtDryL=1; + Cores[c].InpWetR=1; + Cores[c].InpWetL=1; + Cores[c].InpDryR=1; + Cores[c].InpDryL=1; + Cores[c].SndWetR=1; + Cores[c].SndWetL=1; + Cores[c].SndDryR=1; + Cores[c].SndDryL=1; + Cores[c].Regs.MMIX = 0xFFCF; + Cores[c].Regs.VMIXL = 0xFFFFFF; + Cores[c].Regs.VMIXR = 0xFFFFFF; + Cores[c].Regs.VMIXEL = 0xFFFFFF; + Cores[c].Regs.VMIXER = 0xFFFFFF; + Cores[c].EffectsStartA= 0xEFFF8 + 0x10000*c; + Cores[c].EffectsEndA = 0xEFFFF + 0x10000*c; + Cores[c].FxEnable=0; + Cores[c].IRQA=0xFFFF0; + Cores[c].IRQEnable=1; + + for (v=0;v<24;v++) { + AssignVolume(Cores[c].Voices[v].VolumeL,DEFAULT_VOICE_VOLUME); + AssignVolume(Cores[c].Voices[v].VolumeR,DEFAULT_VOICE_VOLUME); + Cores[c].Voices[v].ADSR.Value=0; + Cores[c].Voices[v].ADSR.Phase=0; + Cores[c].Voices[v].Pitch=0x3FFF; + Cores[c].Voices[v].DryL=1; + Cores[c].Voices[v].DryR=1; + Cores[c].Voices[v].WetL=1; + Cores[c].Voices[v].WetR=1; + Cores[c].Voices[v].NextA=2800; + Cores[c].Voices[v].StartA=2800; + Cores[c].Voices[v].LoopStartA=2800; + //Cores[c].Voices[v].lastSetStartA=2800; fixme: this is part of debug now + } + Cores[c].DMAICounter=0; + Cores[c].AdmaInProgress=0; + + Cores[c].Regs.STATX=0x80; + + ConLog("done.\n"); +} + +extern void LowPassFilterInit(); + +EXPORT_C_(s32) SPU2init() +{ +#define MAKESURE(a,b) \ + /*fprintf(stderr,"%08p: %08p == %08p\n",&(regtable[a>>1]),regtable[a>>1],U16P(b));*/ \ + assert(regtable[(a)>>1]==U16P(b)) + + MAKESURE(0x800,zero); + + s32 c=0,v=0; + ReadSettings(); + acumCycles=0; + +#ifdef SPU2_LOG + if(AccessLog()) + { + spu2Log = fopen(AccessLogFileName, "w"); + setvbuf(spu2Log, NULL, _IONBF, 0); + FileLog("SPU2init\n"); + } +#endif + srand((unsigned)time(NULL)); + + disableFreezes=false; + + if (spu2init) + { + ConLog( " * SPU2: Already initialized - Ignoring SPU2init signal." ); + return 0; + } + + spu2init=true; + + spu2regs = (short*)malloc(0x010000); + _spu2mem = (short*)malloc(0x200000); + + // adpcm decoder cache: + // the cache data size is determined by taking the number of adpcm blocks + // (2MB / 16) and multiplying it by the decoded block size (28 samples). + // Thus: pcm_cache_data = 7,340,032 bytes (ouch!) + // Expanded: 16 bytes expands to 56 bytes [3.5:1 ratio] + // Resulting in 2MB * 3.5. + + pcm_cache_data = (PcmCacheEntry*)calloc( pcm_BlockCount, sizeof(PcmCacheEntry) ); + + if( (spu2regs == NULL) || (_spu2mem == NULL) || + (pcm_cache_data == NULL) ) + { + SysMessage("SPU2: Error allocating Memory\n"); return -1; + } + + for(int mem=0;mem<0x800;mem++) + { + u16 *ptr=regtable[mem>>1]; + if(!ptr) { + regtable[mem>>1] = &(spu2Ru16(mem)); + } + } + + memset(spu2regs,0,0x010000); + memset(_spu2mem,0,0x200000); + memset(&Cores,0,(sizeof(V_Core) * 2)); + CoreReset(0); + CoreReset(1); + + DMALogOpen(); + + if(WaveLog()) + { + if(!wavedump_open()) + { + SysMessage("Can't open '%s'.\nWave Log disabled.",WaveLogFileName); + } + } + + for(v=0;v<16384;v++) + { + logvolume[v]=(s32)(s32)floor(log((double)(v+1))*3376.7); + } + + LowPassFilterInit(); + InitADSR(); + +#ifdef STREAM_DUMP + il0=fopen("logs/spu2input0.pcm","wb"); + il1=fopen("logs/spu2input1.pcm","wb"); +#endif + +#ifdef EFFECTS_DUMP + el0=fopen("logs/spu2fx0.pcm","wb"); + el1=fopen("logs/spu2fx1.pcm","wb"); +#endif + + +#ifdef S2R_ENABLE + if(!replay_mode) + s2r_open("replay_dump.s2r"); +#endif + return 0; +} + + +static BOOL CALLBACK DebugProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + int wmId,wmEvent; + + switch(uMsg) + { + case WM_PAINT: + return FALSE; + case WM_INITDIALOG: + { + debugDialogOpen=true; + } + break; + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDOK: + case IDCANCEL: + debugDialogOpen=false; + EndDialog(hWnd,0); + break; + default: + return FALSE; + } + break; + default: + return FALSE; + } + return TRUE; +} + +EXPORT_C_(s32) SPU2open(void *pDsp) +{ + if( spu2open ) return 0; + + FileLog("[%10d] SPU2 Open\n",Cycles); + + /* + if(debugDialogOpen==0) + { + hDebugDialog = CreateDialogParam(hInstance,MAKEINTRESOURCE(IDD_DEBUG),0,DebugProc,0); + ShowWindow(hDebugDialog,SW_SHOWNORMAL); + debugDialogOpen=1; + }*/ + + spu2open=true; + if (!SndInit()) + { + srate_pv=(double)SampleRate/48000.0; + + spdif_init(); + + DspLoadLibrary(dspPlugin,dspPluginModule); + + return 0; + } + else + { + SPU2close(); + return -1; + }; +} + +EXPORT_C_(void) SPU2close() +{ + if( !spu2open ) return; + FileLog("[%10d] SPU2 Close\n",Cycles); + + DspCloseLibrary(); + spdif_shutdown(); + SndClose(); + + spu2open = false; +} + +EXPORT_C_(void) SPU2shutdown() +{ + if(!spu2init) return; + + ConLog( " * SPU2: Shutting down.\n" ); + + SPU2close(); + +#ifdef S2R_ENABLE + if(!replay_mode) + s2r_close(); +#endif + + DoFullDump(); +#ifdef STREAM_DUMP + fclose(il0); + fclose(il1); +#endif +#ifdef EFFECTS_DUMP + fclose(el0); + fclose(el1); +#endif + if(WaveLog() && wavedump_ok) wavedump_close(); + + DMALogClose(); + + spu2init = false; + + SAFE_FREE(spu2regs); + SAFE_FREE(_spu2mem); + + SAFE_FREE( pcm_cache_data ); + + spu2regs = NULL; + _spu2mem = NULL; + pcm_cache_data = NULL; + +#ifdef SPU2_LOG + if(!AccessLog()) return; + FileLog("[%10d] SPU2shutdown\n",Cycles); + if(spu2Log) fclose(spu2Log); +#endif +} + +EXPORT_C_(void) SPU2setClockPtr(u32 *ptr) +{ + cPtr=ptr; + hasPtr=(cPtr!=NULL); +} + +int FillRectangle(HDC dc, int left, int top, int width, int height) +{ + RECT r = { left, top, left+width, top+height }; + + return FillRect(dc, &r, (HBRUSH)GetStockObject(DC_BRUSH)); +} + +BOOL DrawRectangle(HDC dc, int left, int top, int width, int height) +{ + RECT r = { left, top, left+width, top+height }; + + POINT p[5] = { + { r.left, r.top }, + { r.right, r.top }, + { r.right, r.bottom }, + { r.left, r.bottom }, + { r.left, r.top }, + }; + + return Polyline(dc, p, 5); +} + +#ifndef PUBLIC +HFONT hf = NULL; +int lCount=0; +void UpdateDebugDialog() +{ + if(!debugDialogOpen) return; + + lCount++; + if(lCount>=(SampleRate/10)) + { + HDC hdc = GetDC(hDebugDialog); + + if(!hf) + { + hf = CreateFont( 8, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Lucida Console"); + } + + SelectObject(hdc,hf); + SelectObject(hdc,GetStockObject(DC_BRUSH)); + SelectObject(hdc,GetStockObject(DC_PEN)); + + for(int c=0;c<2;c++) + { + for(int v=0;v<24;v++) + { + int IX = 8+256*c; + int IY = 8+ 32*v; + V_Voice& vc(Cores[c].Voices[v]); + V_VoiceDebug& vcd( DebugCores[c].Voices[v] ); + + SetDCBrushColor(hdc,RGB( 0, 0, 0)); + if((vc.ADSR.Phase>0)&&(vc.ADSR.Phase<6)) + { + SetDCBrushColor(hdc,RGB( 0, 0,128)); + } + else + { + if(vcd.lastStopReason==1) + { + SetDCBrushColor(hdc,RGB(128, 0, 0)); + } + if(vcd.lastStopReason==2) + { + SetDCBrushColor(hdc,RGB( 0,128, 0)); + } + } + + FillRectangle(hdc,IX,IY,252,30); + + SetDCPenColor(hdc,RGB( 255, 128, 32)); + + DrawRectangle(hdc,IX,IY,252,30); + + SetDCBrushColor (hdc,RGB( 0,255, 0)); + + int vl = abs(vc.VolumeL.Value * 24 / 32768); + int vr = abs(vc.VolumeR.Value * 24 / 32768); + + FillRectangle(hdc,IX+38,IY+26 - vl, 4, vl); + FillRectangle(hdc,IX+42,IY+26 - vr, 4, vr); + + int adsr = (vc.ADSR.Value>>16) * 24 / 32768; + + FillRectangle(hdc,IX+48,IY+26 - adsr, 4, adsr); + + int peak = vcd.displayPeak * 24 / 32768; + + FillRectangle(hdc,IX+56,IY+26 - peak, 4, peak); + + SetTextColor(hdc,RGB( 0,255, 0)); + SetBkColor (hdc,RGB( 0, 0, 0)); + + static char t[1024]; + + sprintf(t,"%06x",vc.StartA); + TextOut(hdc,IX+4,IY+3,t,6); + + sprintf(t,"%06x",vc.NextA); + TextOut(hdc,IX+4,IY+12,t,6); + + sprintf(t,"%06x",vc.LoopStartA); + TextOut(hdc,IX+4,IY+21,t,6); + + vcd.displayPeak = 0; + + if(vcd.lastSetStartA != vc.StartA) + { + printf(" *** Warning! Core %d Voice %d: StartA should be %06x, and is %06x.\n", + c,v,vcd.lastSetStartA,vc.StartA); + vcd.lastSetStartA = vc.StartA; + } + } + } + ReleaseDC(hDebugDialog,hdc); + lCount=0; + } + + MSG msg; + while(PeekMessage(&msg,hDebugDialog,0,0,PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} +#endif + +#define TickInterval 768 +#define SanityInterval 4800 + +u32 TicksCore=0; +u32 TicksThread=0; + +static DWORD CALLBACK TimeThread(PVOID /* unused param */) +{ + while(spu2open) + { + if(TicksThread>=(TicksCore+320)) + { + Sleep(1); + } + else if(TicksThread>=TicksCore) + { + Sleep(0); + } + else + { + Mix(); + TicksThread++; + } + } + return 0; +} + +void __fastcall TimeUpdate(u32 cClocks) +{ + u32 dClocks = cClocks-lClocks; + + // [Air]: Sanity Check + // If for some reason our clock value seems way off base, just mix + // out a little bit, skip the rest, and hope the ship "rights" itself later on. + + if( dClocks > TickInterval*SanityInterval ) + { + ConLog( " * SPU2 > TimeUpdate Sanity Check (Tick Delta: %d) (PS2 Ticks: %d)\n", dClocks/TickInterval, cClocks/TickInterval ); + dClocks = TickInterval*SanityInterval; + lClocks = cClocks-dClocks; + } + + //UpdateDebugDialog(); + + //Update Mixing Progress + while(dClocks>=TickInterval) + { + if(has_to_call_irq) + { + ConLog(" * SPU2: Irq Called (%04x).\n",Spdif.Info); + has_to_call_irq=false; + if(_irqcallback) _irqcallback(); + } + + if(Cores[0].InitDelay>0) + { + Cores[0].InitDelay--; + if(Cores[0].InitDelay==0) + { + CoreReset(0); + } + } + + if(Cores[1].InitDelay>0) + { + Cores[1].InitDelay--; + if(Cores[1].InitDelay==0) + { + CoreReset(1); + } + } + + //Update DMA4 interrupt delay counter + if(Cores[0].DMAICounter>0) + { + Cores[0].DMAICounter-=TickInterval; + if(Cores[0].DMAICounter<=0) + { + Cores[0].MADR=Cores[0].TADR; + Cores[0].DMAICounter=0; + if(dma4callback) dma4callback(); + } + else { + Cores[0].MADR+=TickInterval<<1; + } + } + + //Update DMA7 interrupt delay counter + if(Cores[1].DMAICounter>0) + { + Cores[1].DMAICounter-=TickInterval; + if(Cores[1].DMAICounter<=0) + { + Cores[1].MADR=Cores[1].TADR; + Cores[1].DMAICounter=0; + //ConLog( "* SPU2 > DMA 7 Callback! %d\n", Cycles ); + if(dma7callback) dma7callback(); + } + else { + Cores[1].MADR+=TickInterval<<1; + } + } + + dClocks-=TickInterval; + lClocks+=TickInterval; + Cycles++; + + Mix(); + } +} + +bool numpad_minus_old=false; +bool numpad_minus = false; + +bool numpad_plus = false, numpad_plus_old = false; + +EXPORT_C_(void) SPU2async(u32 cycles) +{ +#ifndef PUBLIC + u32 oldClocks = lClocks; + static u32 timer=0,time1=0,time2=0; + timer++; + if (timer == 1){ + time1=timeGetTime(); + } + if (timer == 3000){ + time2 = timeGetTime()-time1 ; + timer=0; + } +#endif + + DspUpdate(); + + if(LimiterToggleEnabled) + { + numpad_minus = (GetAsyncKeyState(VK_SUBTRACT)&0x8000)!=0; + + if(numpad_minus && !numpad_minus_old) + { + if(LimitMode) LimitMode=0; + else LimitMode=1; + SndUpdateLimitMode(); + } + numpad_minus_old = numpad_minus; + } + +#ifndef PUBLIC + /*numpad_plus = (GetAsyncKeyState(VK_ADD)&0x8000)!=0; + if(numpad_plus && !numpad_plus_old) + { + DoFullDump(); + } + numpad_plus_old = numpad_plus;*/ +#endif + + if(hasPtr) + { + TimeUpdate(*cPtr); + } + else + { + pClocks+=cycles; + TimeUpdate(pClocks); + } +} + +EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()) +{ + _irqcallback=SPU2callback; + dma4callback=DMA4callback; + dma7callback=DMA7callback; +} + +u16 mask = 0xFFFF; + +void UpdateSpdifMode() +{ + int OPM=PlayMode; + u16 last = 0; + + if(mask&Spdif.Out) + { + last = mask & Spdif.Out; + mask=mask&(~Spdif.Out); + } + + if(Spdif.Out&0x4) // use 24/32bit PCM data streaming + { + PlayMode=8; + ConLog(" * SPU2: WARNING: Possibly CDDA mode set!\n"); + return; + } + + if(Spdif.Out&SPDIF_OUT_BYPASS) + { + PlayMode=2; + if(Spdif.Mode&SPDIF_MODE_BYPASS_BITSTREAM) + PlayMode=4; //bitstream bypass + } + else + { + PlayMode=0; //normal processing + if(Spdif.Out&SPDIF_OUT_PCM) + { + PlayMode=1; + } + } + if(OPM!=PlayMode) + { + ConLog(" * SPU2: Play Mode Set to %s (%d).\n",(PlayMode==0)?"Normal":((PlayMode==1)?"PCM Clone":((PlayMode==2)?"PCM Bypass":"BitStream Bypass")),PlayMode); + } +} + +__forceinline void RegLog(int level, char *RName,u32 mem,u32 core,u16 value) +{ + if( level > 1 ) + FileLog("[%10d] SPU2 write mem %08x (core %d, register %s) value %04x\n",Cycles,mem,core,RName,value); +} + +static void SPU_ps1_write(u32 mem, u16 value) +{ + bool show=true; + + u32 reg = mem&0xffff; + + if((reg>=0x1c00)&&(reg<0x1d80)) + { + //voice values + u8 voice = ((reg-0x1c00)>>4); + u8 vval = reg&0xf; + switch(vval) + { + case 0: //VOLL (Volume L) + Cores[0].Voices[voice].VolumeL.Mode=0; + Cores[0].Voices[voice].VolumeL.Value=value<<1; + Cores[0].Voices[voice].VolumeL.Reg_VOL = value; break; + case 1: //VOLR (Volume R) + Cores[0].Voices[voice].VolumeR.Mode=0; + Cores[0].Voices[voice].VolumeR.Value=value<<1; + Cores[0].Voices[voice].VolumeR.Reg_VOL = value; break; + case 2: Cores[0].Voices[voice].Pitch=value; break; + case 3: Cores[0].Voices[voice].StartA=(u32)value<<8; break; + case 4: // ADSR1 (Envelope) + Cores[0].Voices[voice].ADSR.Am=(value & 0x8000)>>15; + Cores[0].Voices[voice].ADSR.Ar=(value & 0x7F00)>>8; + Cores[0].Voices[voice].ADSR.Dr=(value & 0xF0)>>4; + Cores[0].Voices[voice].ADSR.Sl=(value & 0xF); + Cores[0].Voices[voice].ADSR.Reg_ADSR1 = value; break; + case 5: // ADSR2 (Envelope) + Cores[0].Voices[voice].ADSR.Sm=(value & 0xE000)>>13; + Cores[0].Voices[voice].ADSR.Sr=(value & 0x1FC0)>>6; + Cores[0].Voices[voice].ADSR.Rm=(value & 0x20)>>5; + Cores[0].Voices[voice].ADSR.Rr=(value & 0x1F); + Cores[0].Voices[voice].ADSR.Reg_ADSR2 = value; break; + case 6: + // [Air] Experimental --> shifting value into a 31 bit range. + // shifting by 16 might be more correct? + Cores[0].Voices[voice].ADSR.Value = value<<15; + ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); + break; + case 7: Cores[0].Voices[voice].LoopStartA=(u32)value <<8; break; + + jNO_DEFAULT; + } + } + else switch(reg) + { + case 0x1d80:// Mainvolume left + Cores[0].MasterL.Mode=0; + Cores[0].MasterL.Value=value; + break; + case 0x1d82:// Mainvolume right + Cores[0].MasterL.Mode=0; + Cores[0].MasterR.Value=value; + break; + case 0x1d84:// Reverberation depth left + Cores[0].FxL=value; + break; + case 0x1d86:// Reverberation depth right + Cores[0].FxR=value; + break; + + case 0x1d88:// Voice ON (0-15) + SPU2_FastWrite(REG_S_KON,value); + break; + case 0x1d8a:// Voice ON (16-23) + SPU2_FastWrite(REG_S_KON+2,value); + break; + + case 0x1d8c:// Voice OFF (0-15) + SPU2_FastWrite(REG_S_KOFF,value); + break; + case 0x1d8e:// Voice OFF (16-23) + SPU2_FastWrite(REG_S_KOFF+2,value); + break; + + case 0x1d90:// Channel FM (pitch lfo) mode (0-15) + SPU2_FastWrite(REG_S_PMON,value); + break; + case 0x1d92:// Channel FM (pitch lfo) mode (16-23) + SPU2_FastWrite(REG_S_PMON+2,value); + break; + + + case 0x1d94:// Channel Noise mode (0-15) + SPU2_FastWrite(REG_S_NON,value); + break; + case 0x1d96:// Channel Noise mode (16-23) + SPU2_FastWrite(REG_S_NON+2,value); + break; + + case 0x1d98:// Channel Reverb mode (0-15) + SPU2_FastWrite(REG_S_VMIXEL,value); + SPU2_FastWrite(REG_S_VMIXER,value); + break; + case 0x1d9a:// Channel Reverb mode (16-23) + SPU2_FastWrite(REG_S_VMIXEL+2,value); + SPU2_FastWrite(REG_S_VMIXER+2,value); + break; + case 0x1d9c:// Channel Reverb mode (0-15) + SPU2_FastWrite(REG_S_VMIXL,value); + SPU2_FastWrite(REG_S_VMIXR,value); + break; + case 0x1d9e:// Channel Reverb mode (16-23) + SPU2_FastWrite(REG_S_VMIXL+2,value); + SPU2_FastWrite(REG_S_VMIXR+2,value); + break; + + case 0x1da2:// Reverb work area start + { + u32 val=(u32)value <<8; + + SPU2_FastWrite(REG_A_ESA, val&0xFFFF); + SPU2_FastWrite(REG_A_ESA+2,val>>16); + } + break; + case 0x1da4: + Cores[0].IRQA=(u32)value<<8; + break; + case 0x1da6: + Cores[0].TSA=(u32)value<<8; + break; + + case 0x1daa: + SPU2_FastWrite(REG_C_ATTR,value); + break; + case 0x1dae: + SPU2_FastWrite(REG_P_STATX,value); + break; + case 0x1da8:// Spu Write to Memory + DmaWrite(0,value); + show=false; + break; + } + + if(show) FileLog("[%10d] (!) SPU write mem %08x value %04x\n",Cycles,mem,value); + + spu2Ru16(mem)=value; +} + +static u16 SPU_ps1_read(u32 mem) +{ + bool show=true; + u16 value = spu2Ru16(mem); + + u32 reg = mem&0xffff; + + if((reg>=0x1c00)&&(reg<0x1d80)) + { + //voice values + u8 voice = ((reg-0x1c00)>>4); + u8 vval = reg&0xf; + switch(vval) + { + case 0: //VOLL (Volume L) + value=Cores[0].Voices[voice].VolumeL.Mode; + value=Cores[0].Voices[voice].VolumeL.Value; + value=Cores[0].Voices[voice].VolumeL.Reg_VOL; break; + case 1: //VOLR (Volume R) + value=Cores[0].Voices[voice].VolumeR.Mode; + value=Cores[0].Voices[voice].VolumeR.Value; + value=Cores[0].Voices[voice].VolumeR.Reg_VOL; break; + case 2: value=Cores[0].Voices[voice].Pitch; break; + case 3: value=Cores[0].Voices[voice].StartA; break; + case 4: value=Cores[0].Voices[voice].ADSR.Reg_ADSR1; break; + case 5: value=Cores[0].Voices[voice].ADSR.Reg_ADSR2; break; + case 6: value=Cores[0].Voices[voice].ADSR.Value >> 16; break; + case 7: value=Cores[0].Voices[voice].LoopStartA; break; + + jNO_DEFAULT; + } + } + else switch(reg) + { + case 0x1d80: value = Cores[0].MasterL.Value; break; + case 0x1d82: value = Cores[0].MasterR.Value; break; + case 0x1d84: value = Cores[0].FxL; break; + case 0x1d86: value = Cores[0].FxR; break; + + case 0x1d88: value = 0; break; + case 0x1d8a: value = 0; break; + case 0x1d8c: value = 0; break; + case 0x1d8e: value = 0; break; + + case 0x1d90: value = Cores[0].Regs.PMON&0xFFFF; break; + case 0x1d92: value = Cores[0].Regs.PMON>>16; break; + + case 0x1d94: value = Cores[0].Regs.NON&0xFFFF; break; + case 0x1d96: value = Cores[0].Regs.NON>>16; break; + + case 0x1d98: value = Cores[0].Regs.VMIXEL&0xFFFF; break; + case 0x1d9a: value = Cores[0].Regs.VMIXEL>>16; break; + case 0x1d9c: value = Cores[0].Regs.VMIXL&0xFFFF; break; + case 0x1d9e: value = Cores[0].Regs.VMIXL>>16; break; + + case 0x1da2: value = Cores[0].EffectsStartA>>3; break; + case 0x1da4: value = Cores[0].IRQA>>3; break; + case 0x1da6: value = Cores[0].TSA>>3; break; + + case 0x1daa: + value = SPU2read(REG_C_ATTR); + break; + case 0x1dae: + value = 0; //SPU2read(REG_P_STATX)<<3; + break; + case 0x1da8: + value = DmaRead(0); + show=false; + break; + } + + if(show) FileLog("[%10d] (!) SPU read mem %08x value %04x\n",Cycles,mem,value); + return value; +} + +void RegWriteLog(u32 core,u16 value); + +static void SPU2writeLog(u32 rmem, u16 value) +{ +#ifndef PUBLIC + u32 vx=0, vc=0, core=0, omem=rmem, mem=rmem&0x7FF; + omem=mem=mem&0x7FF; //FFFF; + if (mem & 0x400) { omem^=0x400; core=1; } + + /* + if ((omem >= 0x0000) && (omem < 0x0180)) { // Voice Params + u32 voice=(omem & 0x1F0) >> 4; + u32 param=(omem & 0xF)>>1; + FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Param %s) value %x\n",Cycles,rmem,core,voice,ParamNames[param],value); + } + else if ((omem >= 0x01C0) && (omem < 0x02DE)) { + u32 voice =((omem-0x01C0) / 12); + u32 address =((omem-0x01C0) % 12)>>1; + FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Address %s) value %x\n",Cycles,rmem,core,voice,AddressNames[address],value); + } + */ + if ((mem >= 0x0760) && (mem < 0x07b0)) { + omem=mem; core=0; + if (mem >= 0x0788) {omem-=0x28; core=1;} + switch(omem) { + case REG_P_EVOLL: RegLog(2,"EVOLL",rmem,core,value); break; + case REG_P_EVOLR: RegLog(2,"EVOLR",rmem,core,value); break; + case REG_P_AVOLL: if (core) { RegLog(2,"AVOLL",rmem,core,value); } break; + case REG_P_AVOLR: if (core) { RegLog(2,"AVOLR",rmem,core,value); } break; + case REG_P_BVOLL: RegLog(2,"BVOLL",rmem,core,value); break; + case REG_P_BVOLR: RegLog(2,"BVOLR",rmem,core,value); break; + case REG_P_MVOLXL: RegLog(2,"MVOLXL",rmem,core,value); break; + case REG_P_MVOLXR: RegLog(2,"MVOLXR",rmem,core,value); break; + case R_IIR_ALPHA: RegLog(2,"IIR_ALPHA",rmem,core,value); break; + case R_ACC_COEF_A: RegLog(2,"ACC_COEF_A",rmem,core,value); break; + case R_ACC_COEF_B: RegLog(2,"ACC_COEF_B",rmem,core,value); break; + case R_ACC_COEF_C: RegLog(2,"ACC_COEF_C",rmem,core,value); break; + case R_ACC_COEF_D: RegLog(2,"ACC_COEF_D",rmem,core,value); break; + case R_IIR_COEF: RegLog(2,"IIR_COEF",rmem,core,value); break; + case R_FB_ALPHA: RegLog(2,"FB_ALPHA",rmem,core,value); break; + case R_FB_X: RegLog(2,"FB_X",rmem,core,value); break; + case R_IN_COEF_L: RegLog(2,"IN_COEF_L",rmem,core,value); break; + case R_IN_COEF_R: RegLog(2,"IN_COEF_R",rmem,core,value); break; + + } + } + else if ((mem>=0x07C0) && (mem<0x07CE)) { + switch(mem) { + case SPDIF_OUT: + RegLog(2,"SPDIF_OUT",rmem,-1,value); + break; + case IRQINFO: + RegLog(2,"IRQINFO",rmem,-1,value); + break; + case 0x7c4: + if(Spdif.Unknown1 != value) ConLog(" * SPU2: SPDIF Unknown Register 1 set to %04x\n",value); + RegLog(2,"SPDIF_UNKNOWN1",rmem,-1,value); + break; + case SPDIF_MODE: + if(Spdif.Mode != value) ConLog(" * SPU2: SPDIF Mode set to %04x\n",value); + RegLog(2,"SPDIF_MODE",rmem,-1,value); + break; + case SPDIF_MEDIA: + if(Spdif.Media != value) ConLog(" * SPU2: SPDIF Media set to %04x\n",value); + RegLog(2,"SPDIF_MEDIA",rmem,-1,value); + break; + case 0x7ca: + if(Spdif.Unknown2 != value) ConLog(" * SPU2: SPDIF Unknown Register 2 set to %04x\n",value); + RegLog(2,"SPDIF_UNKNOWN2",rmem,-1,value); + break; + case SPDIF_COPY: + if(Spdif.Protection != value) ConLog(" * SPU2: SPDIF Copy set to %04x\n",value); + RegLog(2,"SPDIF_COPY",rmem,-1,value); + break; + } + UpdateSpdifMode(); + } + else + switch(omem) { + case REG_C_ATTR: + RegLog(4,"ATTR",rmem,core,value); + break; + case REG_S_PMON: + RegLog(1,"PMON0",rmem,core,value); + break; + case (REG_S_PMON + 2): + RegLog(1,"PMON1",rmem,core,value); + break; + case REG_S_NON: + RegLog(1,"NON0",rmem,core,value); + break; + case (REG_S_NON + 2): + RegLog(1,"NON1",rmem,core,value); + break; + case REG_S_VMIXL: + RegLog(1,"VMIXL0",rmem,core,value); + case (REG_S_VMIXL + 2): + RegLog(1,"VMIXL1",rmem,core,value); + break; + case REG_S_VMIXEL: + RegLog(1,"VMIXEL0",rmem,core,value); + break; + case (REG_S_VMIXEL + 2): + RegLog(1,"VMIXEL1",rmem,core,value); + break; + case REG_S_VMIXR: + RegLog(1,"VMIXR0",rmem,core,value); + break; + case (REG_S_VMIXR + 2): + RegLog(1,"VMIXR1",rmem,core,value); + break; + case REG_S_VMIXER: + RegLog(1,"VMIXER0",rmem,core,value); + break; + case (REG_S_VMIXER + 2): + RegLog(1,"VMIXER1",rmem,core,value); + break; + case REG_P_MMIX: + RegLog(1,"MMIX",rmem,core,value); + break; + case REG_A_IRQA: + RegLog(2,"IRQAH",rmem,core,value); + break; + case (REG_A_IRQA + 2): + RegLog(2,"IRQAL",rmem,core,value); + break; + case (REG_S_KON + 2): + RegLog(2,"KON1",rmem,core,value); + break; + case REG_S_KON: + RegLog(2,"KON0",rmem,core,value); + break; + case (REG_S_KOFF + 2): + RegLog(2,"KOFF1",rmem,core,value); + break; + case REG_S_KOFF: + RegLog(2,"KOFF0",rmem,core,value); + break; + case REG_A_TSA: + RegLog(2,"TSAH",rmem,core,value); + break; + case (REG_A_TSA + 2): + RegLog(2,"TSAL",rmem,core,value); + break; + case REG_S_ENDX: + //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); + RegLog(2,"ENDX0",rmem,core,value); + break; + case (REG_S_ENDX + 2): + //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); + RegLog(2,"ENDX1",rmem,core,value); + break; + case REG_P_MVOLL: + RegLog(1,"MVOLL",rmem,core,value); + break; + case REG_P_MVOLR: + RegLog(1,"MVOLR",rmem,core,value); + break; + case REG_S_ADMAS: + RegLog(3,"ADMAS",rmem,core,value); + ConLog(" * SPU2: Core %d AutoDMAControl set to %d\n",core,value); + break; + case REG_P_STATX: + RegLog(3,"STATX",rmem,core,value); + break; + case REG_A_ESA: + RegLog(1,"ESAH",rmem,core,value); + break; + case (REG_A_ESA + 2): + RegLog(1,"ESAL",rmem,core,value); + break; + case REG_A_EEA: + RegLog(1,"EEAH",rmem,core,value); + break; + +#define LOG_REVB_REG(n,t) \ + case R_##n: \ + RegLog(2,t "H",mem,core,value); \ + break; \ + case (R_##n + 2): \ + RegLog(2,t "L",mem,core,value); \ + break; + + LOG_REVB_REG(FB_SRC_A,"FB_SRC_A") + LOG_REVB_REG(FB_SRC_B,"FB_SRC_B") + LOG_REVB_REG(IIR_SRC_A0,"IIR_SRC_A0") + LOG_REVB_REG(IIR_SRC_A1,"IIR_SRC_A1") + LOG_REVB_REG(IIR_SRC_B1,"IIR_SRC_B1") + LOG_REVB_REG(IIR_SRC_B0,"IIR_SRC_B0") + LOG_REVB_REG(IIR_DEST_A0,"IIR_DEST_A0") + LOG_REVB_REG(IIR_DEST_A1,"IIR_DEST_A1") + LOG_REVB_REG(IIR_DEST_B0,"IIR_DEST_B0") + LOG_REVB_REG(IIR_DEST_B1,"IIR_DEST_B1") + LOG_REVB_REG(ACC_SRC_A0,"ACC_SRC_A0") + LOG_REVB_REG(ACC_SRC_A1,"ACC_SRC_A1") + LOG_REVB_REG(ACC_SRC_B0,"ACC_SRC_B0") + LOG_REVB_REG(ACC_SRC_B1,"ACC_SRC_B1") + LOG_REVB_REG(ACC_SRC_C0,"ACC_SRC_C0") + LOG_REVB_REG(ACC_SRC_C1,"ACC_SRC_C1") + LOG_REVB_REG(ACC_SRC_D0,"ACC_SRC_D0") + LOG_REVB_REG(ACC_SRC_D1,"ACC_SRC_D1") + LOG_REVB_REG(MIX_DEST_A0,"MIX_DEST_A0") + LOG_REVB_REG(MIX_DEST_A1,"MIX_DEST_A1") + LOG_REVB_REG(MIX_DEST_B0,"MIX_DEST_B0") + LOG_REVB_REG(MIX_DEST_B1,"MIX_DEST_B1") + + default: RegLog(2,"UNKNOWN",rmem,core,value); spu2Ru16(mem) = value; + } +#endif +} + + +static __forceinline void SPU2_FastWrite( u32 rmem, u16 value ) +{ + u32 vx=0, vc=0, core=0, omem, mem; + omem=mem=rmem & 0x7FF; //FFFF; + if (mem & 0x400) { omem^=0x400; core=1; } + + //else if ((omem >= 0x0000) && (omem < 0x0180)) { // Voice Params + if (omem < 0x0180) { // Voice Params + u32 voice=(omem & 0x1F0) >> 4; + u32 param=(omem & 0xF)>>1; + //FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Param %s) value %x\n",Cycles,rmem,core,voice,ParamNames[param],value); + switch (param) { + case 0: //VOLL (Volume L) + if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp + Cores[core].Voices[voice].VolumeL.Mode=(value & 0xF000)>>12; + Cores[core].Voices[voice].VolumeL.Increment=(value & 0x3F); + } + else { + Cores[core].Voices[voice].VolumeL.Mode=0; + Cores[core].Voices[voice].VolumeL.Increment=0; + if(value&0x4000) + value=0x3fff - (value&0x3fff); + Cores[core].Voices[voice].VolumeL.Value=value<<1; + } + Cores[core].Voices[voice].VolumeL.Reg_VOL = value; break; + case 1: //VOLR (Volume R) + if (value & 0x8000) { + Cores[core].Voices[voice].VolumeR.Mode=(value & 0xF000)>>12; + Cores[core].Voices[voice].VolumeR.Increment=(value & 0x3F); + } + else { + Cores[core].Voices[voice].VolumeR.Mode=0; + Cores[core].Voices[voice].VolumeR.Increment=0; + Cores[core].Voices[voice].VolumeR.Value=value<<1; + } + Cores[core].Voices[voice].VolumeR.Reg_VOL = value; break; + case 2: Cores[core].Voices[voice].Pitch=value; break; + case 3: // ADSR1 (Envelope) + Cores[core].Voices[voice].ADSR.Am=(value & 0x8000)>>15; + Cores[core].Voices[voice].ADSR.Ar=(value & 0x7F00)>>8; + Cores[core].Voices[voice].ADSR.Dr=(value & 0xF0)>>4; + Cores[core].Voices[voice].ADSR.Sl=(value & 0xF); + Cores[core].Voices[voice].ADSR.Reg_ADSR1 = value; break; + case 4: // ADSR2 (Envelope) + Cores[core].Voices[voice].ADSR.Sm=(value & 0xE000)>>13; + Cores[core].Voices[voice].ADSR.Sr=(value & 0x1FC0)>>6; + Cores[core].Voices[voice].ADSR.Rm=(value & 0x20)>>5; + Cores[core].Voices[voice].ADSR.Rr=(value & 0x1F); + Cores[core].Voices[voice].ADSR.Reg_ADSR2 = value; break; + case 5: + // [Air] : Mysterious volume set code. Too bad none of my games ever use it. + // (as usual... ) + Cores[core].Voices[voice].ADSR.Value = value << 15; + ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); + break; + case 6: Cores[core].Voices[voice].VolumeL.Value=value; break; + case 7: Cores[core].Voices[voice].VolumeR.Value=value; break; + + jNO_DEFAULT; + } + } + else if ((omem >= 0x01C0) && (omem < 0x02DE)) { + u32 voice =((omem-0x01C0) / 12); + u32 address =((omem-0x01C0) % 12)>>1; + //FileLog("[%10d] SPU2 write mem %08x (Core %d Voice %d Address %s) value %x\n",Cycles,rmem,core,voice,AddressNames[address],value); + + switch (address) { + case 0: Cores[core].Voices[voice].StartA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].StartA & 0xFFF8); + #ifndef PUBLIC + DebugCores[core].Voices[voice].lastSetStartA = Cores[core].Voices[voice].StartA; + #endif + break; + case 1: Cores[core].Voices[voice].StartA=(Cores[core].Voices[voice].StartA & 0x0F0000) | (value & 0xFFF8); + #ifndef PUBLIC + DebugCores[core].Voices[voice].lastSetStartA = Cores[core].Voices[voice].StartA; + #endif + //if(core==1) printf(" *** StartA for C%dV%02d set to 0x%05x\n",core,voice,Cores[core].Voices[voice].StartA); + break; + case 2: Cores[core].Voices[voice].LoopStartA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].LoopStartA & 0xFFF8); + Cores[core].Voices[voice].LoopMode=3; break; + case 3: Cores[core].Voices[voice].LoopStartA=(Cores[core].Voices[voice].LoopStartA & 0x0F0000) | (value & 0xFFF8);break; + Cores[core].Voices[voice].LoopMode=3; break; + case 4: Cores[core].Voices[voice].NextA=((value & 0x0F) << 16) | (Cores[core].Voices[voice].NextA & 0xFFF8); + //printf(" *** Warning: C%dV%02d NextA MODIFIED EXTERNALLY!\n",core,voice); + break; + case 5: Cores[core].Voices[voice].NextA=(Cores[core].Voices[voice].NextA & 0x0F0000) | (value & 0xFFF8); + //printf(" *** Warning: C%dV%02d NextA MODIFIED EXTERNALLY!\n",core,voice); + break; + } + } + else + switch(omem) { + case REG_C_ATTR: + RegLog(4,"ATTR",rmem,core,value); + { + int irqe=Cores[core].IRQEnable; + int bit0=Cores[core].AttrBit0; + int bit4=Cores[core].AttrBit4; + + if(((value>>15)&1)&&(!Cores[core].CoreEnabled)&&(Cores[core].InitDelay==0)) // on init/reset + { + if(hasPtr) + { + Cores[core].InitDelay=1; + Cores[core].Regs.STATX=0; + } + else + { + CoreReset(core); + } + } + + Cores[core].AttrBit0 =(value>> 0) & 0x01; //1 bit + Cores[core].DMABits =(value>> 1) & 0x07; //3 bits + Cores[core].AttrBit4 =(value>> 4) & 0x01; //1 bit + Cores[core].AttrBit5 =(value>> 5) & 0x01; //1 bit + Cores[core].IRQEnable =(value>> 6) & 0x01; //1 bit + Cores[core].FxEnable =(value>> 7) & 0x01; //1 bit + Cores[core].NoiseClk =(value>> 8) & 0x3f; //6 bits + //Cores[core].Mute =(value>>14) & 0x01; //1 bit + Cores[core].Mute=0; + Cores[core].CoreEnabled=(value>>15) & 0x01; //1 bit + Cores[core].Regs.ATTR =value&0x7fff; + + if(value&0x000E) + { + ConLog(" * SPU2: Core %d ATTR unknown bits SET! value=%04x\n",core,value); + } + + if(Cores[core].AttrBit0!=bit0) + { + ConLog(" * SPU2: ATTR bit 0 set to %d\n",Cores[core].AttrBit0); + } + if(Cores[core].IRQEnable!=irqe) + { + ConLog(" * SPU2: IRQ %s\n",((Cores[core].IRQEnable==0)?"disabled":"enabled")); + if(!Cores[core].IRQEnable) + Spdif.Info=0; + } + + } + break; + case REG_S_PMON: + RegLog(1,"PMON0",rmem,core,value); + vx=2; for (vc=1;vc<16;vc++) { Cores[core].Voices[vc].Modulated=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.PMON = (Cores[core].Regs.PMON & 0xFFFF0000) | value; + break; + case (REG_S_PMON + 2): + RegLog(1,"PMON1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].Modulated=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.PMON = (Cores[core].Regs.PMON & 0xFFFF) | (value << 16); + break; + case REG_S_NON: + RegLog(1,"NON0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].Noise=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.NON = (Cores[core].Regs.NON & 0xFFFF0000) | value; + break; + case (REG_S_NON + 2): + RegLog(1,"NON1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].Noise=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.NON = (Cores[core].Regs.NON & 0xFFFF) | (value << 16); + break; + case REG_S_VMIXL: + RegLog(1,"VMIXL0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].DryL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXL = (Cores[core].Regs.VMIXL & 0xFFFF0000) | value; + case (REG_S_VMIXL + 2): + RegLog(1,"VMIXL1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].DryL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXL = (Cores[core].Regs.VMIXL & 0xFFFF) | (value << 16); + case REG_S_VMIXEL: + RegLog(1,"VMIXEL0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].WetL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXEL = (Cores[core].Regs.VMIXEL & 0xFFFF0000) | value; + break; + case (REG_S_VMIXEL + 2): + RegLog(1,"VMIXEL1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].WetL=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXEL = (Cores[core].Regs.VMIXEL & 0xFFFF) | (value << 16); + break; + case REG_S_VMIXR: + RegLog(1,"VMIXR0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].DryR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXR = (Cores[core].Regs.VMIXR & 0xFFFF0000) | value; + break; + case (REG_S_VMIXR + 2): + RegLog(1,"VMIXR1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].DryR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXR = (Cores[core].Regs.VMIXR & 0xFFFF) | (value << 16); + break; + case REG_S_VMIXER: + RegLog(1,"VMIXER0",rmem,core,value); + vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].WetR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXER = (Cores[core].Regs.VMIXER & 0xFFFF0000) | value; + break; + case (REG_S_VMIXER + 2): + RegLog(1,"VMIXER1",rmem,core,value); + vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].WetR=(s8)((value & vx)/vx); vx<<=1; } + Cores[core].Regs.VMIXER = (Cores[core].Regs.VMIXER & 0xFFFF) | (value << 16); + break; + case REG_P_MMIX: + RegLog(1,"MMIX",rmem,core,value); + vx=value; + if (core == 0) vx&=0xFF0; + Cores[core].ExtWetR=(vx & 0x001); + Cores[core].ExtWetL=(vx & 0x002)>>1; + Cores[core].ExtDryR=(vx & 0x004)>>2; + Cores[core].ExtDryL=(vx & 0x008)>>3; + Cores[core].InpWetR=(vx & 0x010)>>4; + Cores[core].InpWetL=(vx & 0x020)>>5; + Cores[core].InpDryR=(vx & 0x040)>>6; + Cores[core].InpDryL=(vx & 0x080)>>7; + Cores[core].SndWetR=(vx & 0x100)>>8; + Cores[core].SndWetL=(vx & 0x200)>>9; + Cores[core].SndDryR=(vx & 0x400)>>10; + Cores[core].SndDryL=(vx & 0x800)>>11; + Cores[core].Regs.MMIX = value; + break; + case (REG_S_KON + 2): + RegLog(2,"KON1",rmem,core,value); + StartVoices(core,((u32)value)<<16); + break; + case REG_S_KON: + RegLog(2,"KON0",rmem,core,value); + StartVoices(core,((u32)value)); + break; + case (REG_S_KOFF + 2): + RegLog(2,"KOFF1",rmem,core,value); + StopVoices(core,((u32)value)<<16); + break; + case REG_S_KOFF: + RegLog(2,"KOFF0",rmem,core,value); + StopVoices(core,((u32)value)); + break; + case REG_S_ENDX: + //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); + RegLog(2,"ENDX0",rmem,core,value); + Cores[core].Regs.ENDX&=0x00FF0000; break; + case (REG_S_ENDX + 2): + //ConLog(" * SPU2: Core %d ENDX cleared!\n",core); + RegLog(2,"ENDX1",rmem,core,value); + Cores[core].Regs.ENDX&=0xFFFF; break; + case REG_P_MVOLL: + RegLog(1,"MVOLL",rmem,core,value); + if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp + Cores[core].MasterL.Mode=(value & 0xE000)/0x2000; + Cores[core].MasterL.Increment=(value & 0x3F) | ((value & 0x800)/0x10); + } + else { + Cores[core].MasterL.Mode=0; + Cores[core].MasterL.Increment=0; + Cores[core].MasterL.Value=value; + } + Cores[core].MasterL.Reg_VOL=value; + break; + case REG_P_MVOLR: + RegLog(1,"MVOLR",rmem,core,value); + if (value & 0x8000) { // +Lin/-Lin/+Exp/-Exp + Cores[core].MasterR.Mode=(value & 0xE000)/0x2000; + Cores[core].MasterR.Increment=(value & 0x3F) | ((value & 0x800)/0x10); + } + else { + Cores[core].MasterR.Mode=0; + Cores[core].MasterR.Increment=0; + Cores[core].MasterR.Value=value; + } + Cores[core].MasterR.Reg_VOL=value; + break; + case REG_S_ADMAS: + RegLog(3,"ADMAS",rmem,core,value); + //ConLog(" * SPU2: Core %d AutoDMAControl set to %d (%d)\n",core,value, Cycles); + Cores[core].AutoDMACtrl=value; + + if(value==0) + { + Cores[core].AdmaInProgress=0; + } + break; + + default: + *(regtable[mem>>1])=value; + break; + } + + SPU2writeLog(mem,value); + if ((mem>=0x07C0) && (mem<0x07CE)) + { + UpdateSpdifMode(); + } +} + + +EXPORT_C_(void) SPU2write(u32 rmem, u16 value) +{ +#ifdef S2R_ENABLE + if(!replay_mode) + s2r_writereg(Cycles,rmem,value); +#endif + + if(rmem==0x1f9001ac) + { + //RegWriteLog(0,value); + if((Cores[0].IRQEnable)&&(Cores[0].TSA==Cores[0].IRQA)) + { + Spdif.Info=4; + SetIrqCall(); + } + spu2M_Write( Cores[0].TSA++, value ); + Cores[0].TSA&=0xfffff; + } + else if(rmem==0x1f9005ac) + { + //RegWriteLog(1,value); + if((Cores[0].IRQEnable)&&(Cores[0].TSA==Cores[0].IRQA)) + { + Spdif.Info=4; + SetIrqCall(); + } + spu2M_Write( Cores[1].TSA++, value ); + Cores[1].TSA&=0xfffff; + } + else + { + if(hasPtr) TimeUpdate(*cPtr); + + if (rmem>>16 == 0x1f80) + SPU_ps1_write(rmem,value); + else + SPU2_FastWrite( rmem, value ); + } +} + +EXPORT_C_(u16) SPU2read(u32 rmem) +{ +// if(!replay_mode) +// s2r_readreg(Cycles,rmem); + + if(hasPtr) TimeUpdate(*cPtr); + + u16 ret=0xDEAD; u32 core=0, mem=rmem&0xFFFF, omem=mem; + if (mem & 0x400) { omem^=0x400; core=1; } + + if(rmem==0x1f9001AC) + { + ret = DmaRead(core); + } + else if (rmem>>16 == 0x1f80) + { + ret = SPU_ps1_read(rmem); + } + else if ((mem&0xFFFF)>=0x800) + { + ret=spu2Ru16(mem); + ConLog(" * SPU2: Read from reg>=0x800: %x value %x\n",mem,ret); + FileLog(" * SPU2: Read from reg>=0x800: %x value %x\n",mem,ret); + } + else + { + ret = *(regtable[(mem>>1)]); + + FileLog("[%10d] SPU2 read mem %x (core %d, register %x): %x\n",Cycles, mem, core, (omem & 0x7ff), ret); + } + + return ret; +} + +typedef struct +{ + // compatibility with zerospu2 removed... + + u32 version; + u8 unkregs[0x10000]; + u8 mem[0x200000]; + + u32 id; + V_Core Cores[2]; + V_SPDIF Spdif; + s16 OutPos; + s16 InputPos; + u8 InpBuff; + u32 Cycles; + s32 uTicks; + double srate_pv; + double opitch; + int osps; + int PlayMode; + + int lClocks; + + PcmCacheEntry cacheData; + +} SPU2freezeData; + +// No more ZeroSPU compatibility... +//#define ZEROSPU_VERSION 0x70000001 + +#define SAVE_ID 0x73326701 + +// versioning for saves. +// Increment this if changes to V_Core or V_Voice structs are made. +// Chances are we'll never explicitly support older save versions, +// but might as well version them anyway. Could come in handly someday! +#define SAVE_VERSION 0x0101 + +static int getFreezeSize() +{ + if( disableFreezes ) return 8; // length of the string id "invalid" (plus a zero!) + + int size = sizeof(SPU2freezeData); + + // calculate the amount of memory consumed by our cache: + + for( int bidx=0; bidxdata; + + if( spud->id != SAVE_ID || spud->version < 0x100 ) + { + printf("\n*** SPU2Ghz Warning:\n"); + printf(" The savestate you are trying to load was not made with this plugin.\n"); + printf(" The emulator will not be stable! Find a memorycard savespot to save your\n"); + printf(" game, reset, and then continue from there.\n\n"); + + disableFreezes=true; + lClocks = 0; + resetClock = true; + + // Do *not* reset the cores. + // We'll need some "hints" as to how the cores should be initialized, + // and the only way to get that is to use the game's existing core settings + // and hope they kinda match the settings for the savestate (IRQ enables and such). + // + + //CoreReset( 0 ); + //CoreReset( 1 ); + + // adpcm cache : Clear all the cache flags and buffers. + + wipe_the_cache(); + } + else + { + disableFreezes=false; + + // base stuff + memcpy(spu2regs, spud->unkregs, 0x010000); + memcpy(_spu2mem, spud->mem, 0x200000); + + memcpy(Cores, spud->Cores, sizeof(Cores)); + memcpy(&Spdif, &spud->Spdif, sizeof(Spdif)); + OutPos = spud->OutPos; + InputPos = spud->InputPos; + InpBuff = spud->InpBuff; + Cycles = spud->Cycles; + uTicks = spud->uTicks; + srate_pv = spud->srate_pv; + opitch = spud->opitch; + osps = spud->osps; + PlayMode = spud->PlayMode; + lClocks = spud->lClocks; + + // Load the ADPCM cache: + + wipe_the_cache(); + if( spud->version == 0x100 ) // don't support 0x100 cache anymore. + { + printf("\n*** SPU2Ghz Warning:\n"); + printf("\tSavestate version is from an older version of this plugin.\n"); + printf("\tAudio may not recover correctly."); + + const PcmCacheEntry* pcmSrc = &spud->cacheData; + int blksLoaded=0; + + for( int bidx=0; bidx FreezeLoad > Loaded %d cache blocks.\n", blksLoaded++ ); + } + + } else if (mode == FREEZE_SAVE) + { + if (data->data == NULL) return -1; + + if( disableFreezes ) + { + // No point in making a save state since the SPU2 + // state is completely bogus anyway... Let's just + // give this some random ID that no one will recognize. + + strcpy( data->data, "invalid" ); + return 0; + } + + + SPU2freezeData *spud = (SPU2freezeData*)data->data; + + spud->id=SAVE_ID; + spud->version=SAVE_VERSION;//ZEROSPU_VERSION; //Zero compat working bad, better not save that + + memcpy(spud->unkregs, spu2regs, 0x010000); + memcpy(spud->mem, _spu2mem, 0x200000); + memcpy(spud->Cores, Cores, sizeof(Cores)); + memcpy(&spud->Spdif, &Spdif, sizeof(Spdif)); + spud->OutPos = OutPos; + spud->InputPos = InputPos; + spud->InpBuff = InpBuff; + spud->Cycles = Cycles; + spud->uTicks = uTicks; + spud->srate_pv = srate_pv; + spud->opitch = opitch; + spud->osps = osps; + spud->PlayMode = PlayMode; + spud->lClocks = lClocks; + + // Save our cache: + // We could just force the user to rebuild the cache when loading + // from stavestates, but for most games the cache is pretty + // small and compresses well. + // + // Potential Alternative: + // If the cache is not saved then it is necessary to save the + // decoded blocks currently in use by active voices. This allows + // voices to resume seamlessly on load. + + PcmCacheEntry* pcmDst = &spud->cacheData; + int blksSaved=0; + + for( int bidx=0; bidx FreezeSave > Saved %d cache blocks.\n", blksSaved++ ); + + } + else if (mode == FREEZE_SIZE) + { + data->size = getFreezeSize(); + } + return 0; + +} + +void VoiceStart(int core,int vc) +{ + if((Cycles-Cores[core].Voices[vc].PlayCycle)>=4) + { + if(Cores[core].Voices[vc].StartA&7) + { + fprintf( stderr, " *** Missaligned StartA %05x!\n",Cores[core].Voices[vc].StartA); + Cores[core].Voices[vc].StartA=(Cores[core].Voices[vc].StartA+0xFFFF8)+0x8; + } + + Cores[core].Voices[vc].ADSR.Releasing=0; + Cores[core].Voices[vc].ADSR.Value=1; + Cores[core].Voices[vc].ADSR.Phase=1; + Cores[core].Voices[vc].PlayCycle=Cycles; + Cores[core].Voices[vc].SCurrent=28; + Cores[core].Voices[vc].LoopMode=0; + Cores[core].Voices[vc].LoopFlags=0; + Cores[core].Voices[vc].LoopStartA=Cores[core].Voices[vc].StartA; + Cores[core].Voices[vc].NextA=Cores[core].Voices[vc].StartA; + Cores[core].Voices[vc].Prev1=0; + Cores[core].Voices[vc].Prev2=0; + + Cores[core].Voices[vc].PV1=Cores[core].Voices[vc].PV2=0; + Cores[core].Voices[vc].PV3=Cores[core].Voices[vc].PV4=0; + + Cores[core].Regs.ENDX&=~(1<>vc) & 1) { + VoiceStart(core,vc); + } + } + Cores[core].Regs.ENDX &= ~(value); + //Cores[core].Regs.ENDX = 0; +} + +void StopVoices(int core, u32 value) +{ + u32 vx=1,vc=0; + for (vc=0;vc<24;vc++) { + if ((value>>vc) & 1) { + Cores[core].Voices[vc].ADSR.Releasing=1; + //if(MsgKeyOnOff()) ConLog(" * SPU2: KeyOff: Core %d; Voice %d.\n",core,vc); + } + } +} + + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +EXPORT_C_(int) SPU2setupRecording(int start, void* pData) +{ + // Don't record if we have a bogus state. + if( disableFreezes ) return 0; + + if(start==0) + { + //stop recording + RecordStop(); + if(recording==0) + return 1; + } + else if(start==1) + { + //start recording + RecordStart(); + if(recording!=0) + return 1; + } + return 0; +} diff --git a/plugins/spu2ghz/src/spu2.h b/plugins/spu2ghz/src/spu2.h new file mode 100644 index 0000000000..3e2e60a1db --- /dev/null +++ b/plugins/spu2ghz/src/spu2.h @@ -0,0 +1,227 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#ifndef SPU2_H_INCLUDED +#define SPU2_H_INCLUDED +//system defines +#ifdef __LINUX__ + #include +#else +# define WINVER 0x0501 +# define _WIN32_WINNT 0x0501 +# include +# include +#endif +#include "stdlib.h" +#include "stdio.h" +#include "stdarg.h" +#include "math.h" +#include "time.h" + +//SPU2 plugin defines +//#define SPU2defs // not using the PCSX2 defs (see below) +#include "PS2Edefs.h" + +#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall + +// We have our own versions that have the DLLExport attribute configured: + +EXPORT_C_(s32) SPU2init(); +EXPORT_C_(s32) SPU2open(void *pDsp); +EXPORT_C_(void) SPU2close(); +EXPORT_C_(void) SPU2shutdown(); +EXPORT_C_(void) SPU2write(u32 mem, u16 value); +EXPORT_C_(u16) SPU2read(u32 mem); +EXPORT_C_(void) SPU2readDMA4Mem(u16 *pMem, u32 size); +EXPORT_C_(void) SPU2writeDMA4Mem(u16 *pMem, u32 size); +EXPORT_C_(void) SPU2interruptDMA4(); +EXPORT_C_(void) SPU2readDMA7Mem(u16* pMem, u32 size); +EXPORT_C_(void) SPU2writeDMA7Mem(u16 *pMem, u32 size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +EXPORT_C_(void) SPU2setDMABaseAddr(uptr baseaddr); + +EXPORT_C_(void) SPU2interruptDMA7(); +EXPORT_C_(u32) SPU2ReadMemAddr(int core); +EXPORT_C_(void) SPU2WriteMemAddr(int core,u32 value); +EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +EXPORT_C_(int) SPU2setupRecording(int start, void* pData); + +EXPORT_C_(void) SPU2setClockPtr(u32* ptr); + +EXPORT_C_(void) SPU2async(u32 cycles); +EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data); +EXPORT_C_(void) SPU2configure(); +EXPORT_C_(void) SPU2about(); +EXPORT_C_(s32) SPU2test(); + + +//#define EFFECTS_DUMP + +//Plugin parts +#include "config.h" +#include "defs.h" +#include "regs.h" +#include "dma.h" +#include "mixer.h" +#include "sndout.h" + +#include "spu2replay.h" + +#define SPU2_LOG + +#include "debug.h" + +// [Air] : give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + +//-------------------------------------------------------------------------------------- +// Helper macros +//-------------------------------------------------------------------------------------- +#ifndef SAFE_FREE +# define SAFE_FREE(p) { if(p) { free(p); (p)=NULL; } } +#endif +#ifndef SAFE_DELETE_ARRAY +# define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } +#endif +#ifndef SAFE_DELETE +# define SAFE_DELETE_OBJ(p) { if(p) { delete (p); (p)=NULL; } } +#endif +#ifndef SAFE_RELEASE +# define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } +#endif + +// The SPU2 has a dynamic memory range which is used for several internal operations, such as +// registers, CORE 1/2 mixing, AutoDMAs, and some other fancy stuff. We exclude this range +// from the cache here: +static const s32 SPU2_DYN_MEMLINE = 0x2800; + +// 8 short words per encoded PCM block. (as stored in SPU2 ram) +static const int pcm_WordsPerBlock = 8; + +// number of cachable ADPCM blocks (any blocks above the SPU2_DYN_MEMLINE) +static const int pcm_BlockCount = 0x100000 / pcm_WordsPerBlock; + +// 28 samples per decoded PCM block (as stored in our cache) +static const int pcm_DecodedSamplesPerBlock = 28; + +struct PcmCacheEntry +{ + bool Validated; + s16 Sampledata[pcm_DecodedSamplesPerBlock]; +}; + +extern void spdif_set51(u32 is_5_1_out); +extern u32 spdif_init(); +extern void spdif_shutdown(); +extern void spdif_get_samples(s32 *samples); // fills the buffer with [l,r,c,lfe,sl,sr] if using 5.1 output, or [l,r] if using stereo + +extern short *spu2regs; +extern short *_spu2mem; + +extern PcmCacheEntry* pcm_cache_data; + +extern s16 __forceinline * __fastcall GetMemPtr(u32 addr); +extern s16 __forceinline __fastcall spu2M_Read( u32 addr ); +extern void __inline __fastcall spu2M_Write( u32 addr, s16 value ); +extern void __inline __fastcall spu2M_Write( u32 addr, u16 value ); + +#define spu2Rs16(mmem) (*(s16 *)((s8 *)spu2regs + ((mmem) & 0x1fff))) +#define spu2Ru16(mmem) (*(u16 *)((s8 *)spu2regs + ((mmem) & 0x1fff))) + +void SysMessage(const char *fmt, ...); + +extern void VoiceStart(int core,int vc); +extern void VoiceStop(int core,int vc); + +extern s32 uTicks; + +extern void (* _irqcallback)(); +extern void (* dma4callback)(); +extern void (* dma7callback)(); + +extern void SetIrqCall(); + +extern double srate_pv; + +extern s16 *input_data; +extern u32 input_data_ptr; + +extern HINSTANCE hInstance; + +extern int PlayMode; + +extern int recording; +void RecordStart(); +void RecordStop(); +void RecordWrite(s16 left, s16 right); + +extern CRITICAL_SECTION threadSync; + +extern u32 lClocks; + +extern u32* cPtr; +extern bool hasPtr; + +extern bool disableFreezes; + +void __fastcall TimeUpdate(u32 cClocks); + +void TimestretchUpdate(int bufferusage,int buffersize); + +s32 DspLoadLibrary(char *fileName, int modNum); +void DspCloseLibrary(); +int DspProcess(s16 *buffer, int samples); +void DspUpdate(); // to let the Dsp process window messages + +void SndUpdateLimitMode(); +//#define PCM24_S1_INTERLEAVE + +#endif // SPU2_H_INCLUDED // diff --git a/plugins/spu2ghz/src/spu2replay.cpp b/plugins/spu2ghz/src/spu2replay.cpp new file mode 100644 index 0000000000..f613e0160c --- /dev/null +++ b/plugins/spu2ghz/src/spu2replay.cpp @@ -0,0 +1,196 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include + +#include "spu2.h" + +FILE* s2rfile; + +void s2r_write16(s16 data) +{ + fwrite(&data,2,1,s2rfile); +} + +void s2r_write32(u32 data) +{ + fwrite(&data,4,1,s2rfile); +} + +#define EMITC(i,a) s2r_write32(((u32)(i&0xFF)<<24)|(a&0xFFFFFF)) + +int s2r_open(char *filename) +{ + s2rfile=fopen(filename,"wb"); + return s2rfile?0:-1; +} + +void s2r_readreg(u32 ticks,u32 addr) +{ + if(!s2rfile) return; + s2r_write32(ticks); + EMITC(0,addr); +} + +void s2r_writereg(u32 ticks,u32 addr,s16 value) +{ + if(!s2rfile) return; + s2r_write32(ticks); + EMITC(1,addr); + s2r_write16(value); +} + +void s2r_writedma4(u32 ticks,u16*data,u32 len) +{ + u32 i; + if(!s2rfile) return; + s2r_write32(ticks); + EMITC(2,len); + for(i=0;i>24; + sval&=0xFFFFFF; + + while((ccycle-lasync)>64) + { + lasync+=64; + pcycles=lasync; + pclocks=pcycles*768; + + SPU2async(pclocks); + } + pcycles=ccycle; + pclocks=pcycles*768; + + + switch(evid) + { + case 0: + SPU2read(sval); + break; + case 1: + Cread(&tval,2,1,file); + SPU2write(sval,tval); + break; + case 2: + Cread(dmabuffer,sval,2,file); + SPU2writeDMA4Mem(dmabuffer,sval); + break; + case 3: + Cread(dmabuffer,sval,2,file); + SPU2writeDMA7Mem(dmabuffer,sval); + break; + default: + // not implemented + return; + break; + } + } + + //shutdown + SPU2close(); + SPU2shutdown(); + fclose(file); + + replay_mode=false; +} diff --git a/plugins/spu2ghz/src/spu2replay.h b/plugins/spu2ghz/src/spu2replay.h new file mode 100644 index 0000000000..6e3765f0fd --- /dev/null +++ b/plugins/spu2ghz/src/spu2replay.h @@ -0,0 +1,35 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#ifndef SPU2REPLAY_H_INCLUDED +#define SPU2REPLAY_H_INCLUDED + +// s2r dumping +int s2r_open(char *filename); +void s2r_readreg(u32 ticks,u32 addr); +void s2r_writereg(u32 ticks,u32 addr,s16 value); +void s2r_writedma4(u32 ticks,u16*data,u32 len); +void s2r_writedma7(u32 ticks,u16*data,u32 len); +void s2r_close(); + +// s2r playing +void CALLBACK s2r_replay(HWND hwnd, HINSTANCE hinst, LPSTR filename, int nCmdShow); + +extern bool replay_mode; + +#endif//SPU2REPLAY_H_INCLUDED \ No newline at end of file diff --git a/plugins/spu2ghz/src/utf8.cpp b/plugins/spu2ghz/src/utf8.cpp new file mode 100644 index 0000000000..1a53d5cd80 --- /dev/null +++ b/plugins/spu2ghz/src/utf8.cpp @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2001 Peter Harris + * Copyright (C) 2001 Edmund Grimley Evans + * + * 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 + */ + +/* + * Convert a string between UTF-8 and the locale's charset. + */ + +#include +#include + +#include "utf8.h" + + +#ifdef _WIN32 + + /* Thanks to Peter Harris for this win32 + * code. + */ + +#include +#include + +static unsigned char *make_utf8_string(const wchar_t *unicode) +{ + int size = 0, index = 0, out_index = 0; + unsigned char *out; + unsigned short c; + + /* first calculate the size of the target string */ + c = unicode[index++]; + while(c) { + if(c < 0x0080) { + size += 1; + } else if(c < 0x0800) { + size += 2; + } else { + size += 3; + } + c = unicode[index++]; + } + + out = (unsigned char*)malloc(size + 1); + if (out == NULL) + return NULL; + index = 0; + + c = unicode[index++]; + while(c) + { + if(c < 0x080) { + out[out_index++] = (unsigned char)c; + } else if(c < 0x800) { + out[out_index++] = 0xc0 | (c >> 6); + out[out_index++] = 0x80 | (c & 0x3f); + } else { + out[out_index++] = 0xe0 | (c >> 12); + out[out_index++] = 0x80 | ((c >> 6) & 0x3f); + out[out_index++] = 0x80 | (c & 0x3f); + } + c = unicode[index++]; + } + out[out_index] = 0x00; + + return out; +} + +static wchar_t *make_unicode_string(const unsigned char *utf8) +{ + int size = 0, index = 0, out_index = 0; + wchar_t *out; + unsigned char c; + + /* first calculate the size of the target string */ + c = utf8[index++]; + while(c) { + if((c & 0x80) == 0) { + index += 0; + } else if((c & 0xe0) == 0xe0) { + index += 2; + } else { + index += 1; + } + size += 1; + c = utf8[index++]; + } + + out = (wchar_t*)malloc((size + 1) * sizeof(wchar_t)); + if (out == NULL) + return NULL; + index = 0; + + c = utf8[index++]; + while(c) + { + if((c & 0x80) == 0) { + out[out_index++] = c; + } else if((c & 0xe0) == 0xe0) { + out[out_index] = (c & 0x1F) << 12; + c = utf8[index++]; + out[out_index] |= (c & 0x3F) << 6; + c = utf8[index++]; + out[out_index++] |= (c & 0x3F); + } else { + out[out_index] = (c & 0x3F) << 6; + c = utf8[index++]; + out[out_index++] |= (c & 0x3F); + } + c = utf8[index++]; + } + out[out_index] = 0; + + return out; +} + +int utf8_encode(const char *from, char **to) +{ + wchar_t *unicode; + int wchars, err; + + wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, + strlen(from), NULL, 0); + + if(wchars == 0) + { + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + return -1; + } + + unicode = (wchar_t*)calloc(wchars + 1, sizeof(unsigned short)); + if(unicode == NULL) + { + fprintf(stderr, "Out of memory processing string to UTF8\n"); + return -1; + } + + err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, + strlen(from), unicode, wchars); + if(err != wchars) + { + free(unicode); + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + return -1; + } + + /* On NT-based windows systems, we could use WideCharToMultiByte(), but + * MS doesn't actually have a consistent API across win32. + */ + *to = (char*)make_utf8_string(unicode); + + free(unicode); + return 0; +} + +int utf8_decode(const char *from, char **to) +{ + wchar_t *unicode; + int chars, err; + + /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but + * MS doesn't actually have a consistent API across win32. + */ + unicode = make_unicode_string((unsigned char*)from); + if(unicode == NULL) + { + fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n"); + return -1; + } + + chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, + -1, NULL, 0, NULL, NULL); + + if(chars == 0) + { + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + free(unicode); + return -1; + } + + *to = (char *)calloc(chars + 1, sizeof(unsigned char)); + if(*to == NULL) + { + fprintf(stderr, "Out of memory processing string to local charset\n"); + free(unicode); + return -1; + } + + err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, + -1, *to, chars, NULL, NULL); + if(err != chars) + { + fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + free(unicode); + free(*to); + *to = NULL; + return -1; + } + + free(unicode); + return 0; +} + +#else /* End win32. Rest is for real operating systems */ + + +#ifdef HAVE_LANGINFO_CODESET +#include +#endif + +int iconvert(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen); + +static char *current_charset = 0; /* means "US-ASCII" */ + +void convert_set_charset(const char *charset) +{ + + if (!charset) + charset = getenv("CHARSET"); + +#ifdef HAVE_LANGINFO_CODESET + if (!charset) + charset = nl_langinfo(CODESET); +#endif + + free(current_charset); + current_charset = 0; + if (charset && *charset) + current_charset = strdup(charset); +} + +static int convert_buffer(const char *fromcode, const char *tocode, + const char *from, size_t fromlen, + char **to, size_t *tolen) +{ + int ret = -1; + +#ifdef HAVE_ICONV + ret = iconvert(fromcode, tocode, from, fromlen, to, tolen); + if (ret != -1) + return ret; +#endif + +#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */ + ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen); + if (ret != -1) + return ret; +#endif + + return ret; +} + +static int convert_string(const char *fromcode, const char *tocode, + const char *from, char **to, char replace) +{ + int ret; + size_t fromlen; + char *s; + + fromlen = strlen(from); + ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0); + if (ret == -2) + return -1; + if (ret != -1) + return ret; + + s = malloc(fromlen + 1); + if (!s) + return -1; + strcpy(s, from); + *to = s; + for (; *s; s++) + if (*s & ~0x7f) + *s = replace; + return 3; +} + +int utf8_encode(const char *from, char **to) +{ + char *charset; + + if (!current_charset) + convert_set_charset(0); + charset = current_charset ? current_charset : "US-ASCII"; + return convert_string(charset, "UTF-8", from, to, '#'); +} + +int utf8_decode(const char *from, char **to) +{ + char *charset; + + if(*from == 0) { + *to = malloc(1); + **to = 0; + return 1; + } + + if (!current_charset) + convert_set_charset(0); + charset = current_charset ? current_charset : "US-ASCII"; + return convert_string("UTF-8", charset, from, to, '?'); +} + +#endif diff --git a/plugins/spu2ghz/src/utf8.h b/plugins/spu2ghz/src/utf8.h new file mode 100644 index 0000000000..0f799a43cd --- /dev/null +++ b/plugins/spu2ghz/src/utf8.h @@ -0,0 +1,36 @@ + +/* + * Convert a string between UTF-8 and the locale's charset. + * Invalid bytes are replaced by '#', and characters that are + * not available in the target encoding are replaced by '?'. + * + * If the locale's charset is not set explicitly then it is + * obtained using nl_langinfo(CODESET), where available, the + * environment variable CHARSET, or assumed to be US-ASCII. + * + * Return value of conversion functions: + * + * -1 : memory allocation failed + * 0 : data was converted exactly + * 1 : valid data was converted approximately (using '?') + * 2 : input was invalid (but still converted, using '#') + * 3 : unknown encoding (but still converted, using '?') + */ + +#ifndef __UTF8_H +#define __UTF8_H + +#ifdef __cplusplus +extern "C" { +#endif + +void convert_set_charset(const char *charset); + +int utf8_encode(const char *from, char **to); +int utf8_decode(const char *from, char **to); + +#ifdef __cplusplus +} +#endif + +#endif /* __UTF8_H */ diff --git a/plugins/spu2ghz/src/wavedump_wav.cpp b/plugins/spu2ghz/src/wavedump_wav.cpp new file mode 100644 index 0000000000..c90d64df58 --- /dev/null +++ b/plugins/spu2ghz/src/wavedump_wav.cpp @@ -0,0 +1,196 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include "spu2.h" +#include + +#define WAVONLY + +typedef struct { + //Main Header + char riffID[4]; + long riffSize; + char riffTYPE[4]; + //Format Tag + char chunkID[4]; + long chunkSize; + short wFormatTag; + unsigned short wChannels; + unsigned long dwSamplesPerSec; + unsigned long dwAvgBytesPerSec; + unsigned short wBlockAlign; + unsigned short wBitsPerSample; + //Data Tag + char dataID[4]; + long dataSize; +} WAVEHeader; + +int wavedump_ok=0; +int datasize; +FILE *fdump; + +#ifndef WAVONLY +int flacdump_open(); +void flacdump_close(); +void flacdump_write(s16 left,s16 right); +int oggvdump_open(); +void oggvdump_close(); +void oggvdump_write(s16 left,s16 right); +#endif + +int wavedump_open() +{ +#ifndef WAVONLY + if(WaveDumpFormat==1) return flacdump_open(); + if(WaveDumpFormat==2) return oggvdump_open(); +#endif + + fdump=fopen(WaveLogFileName,"wb"); + if(fdump==NULL) return 0; + + fseek(fdump,sizeof(WAVEHeader),SEEK_SET); + + datasize=0; + wavedump_ok=1; + return 1; +} + +void wavedump_flush() +{ + WAVEHeader w; + + memcpy(w.riffID,"RIFF",4); + w.riffSize=datasize+36; + memcpy(w.riffTYPE,"WAVE",4); + memcpy(w.chunkID,"fmt ",4); + w.chunkSize=0x10; + w.wFormatTag=1; + w.wChannels=2; + w.dwSamplesPerSec=48000; + w.dwAvgBytesPerSec=48000*4; + w.wBlockAlign=4; + w.wBitsPerSample=16; + memcpy(w.dataID,"data",4); + w.dataSize=datasize; + + fseek(fdump,0,SEEK_SET); + fwrite(&w,sizeof(w),1,fdump); + + fseek(fdump,datasize+sizeof(w),SEEK_SET); +} + +void wavedump_close() +{ + if(!wavedump_ok) return; + + wavedump_flush(); +#ifndef WAVONLY + if(WaveDumpFormat==1) { flacdump_close(); return;} + if(WaveDumpFormat==2) { oggvdump_close(); return;} +#endif + + + fclose(fdump); + wavedump_ok=0; +} + +void wavedump_write(s16 left,s16 right) +{ + s16 buffer[2]={left,right}; + + if(!wavedump_ok) return; + +#ifndef WAVONLY + if(WaveDumpFormat==1) return flacdump_write(left,right); + if(WaveDumpFormat==2) return oggvdump_write(left,right); +#endif + datasize+=4; + + fwrite(buffer,4,1,fdump); + + if((datasize&1023)==0) + wavedump_flush(); +} + +FILE *recordFile; +int recordSize; +int recording; + +void RecordStart() +{ + if(recording&&recordFile) + fclose(recordFile); + + recordFile=fopen("recording.wav","wb"); + if(recordFile==NULL) return; + + fseek(recordFile,sizeof(WAVEHeader),SEEK_SET); + + recordSize=0; + recording=1; +} + +void RecordFlush() +{ + WAVEHeader w; + + memcpy(w.riffID,"RIFF",4); + w.riffSize=recordSize+36; + memcpy(w.riffTYPE,"WAVE",4); + memcpy(w.chunkID,"fmt ",4); + w.chunkSize=0x10; + w.wFormatTag=1; + w.wChannels=2; + w.dwSamplesPerSec=48000; + w.dwAvgBytesPerSec=48000*4; + w.wBlockAlign=4; + w.wBitsPerSample=16; + memcpy(w.dataID,"data",4); + w.dataSize=recordSize; + + fseek(recordFile,0,SEEK_SET); + fwrite(&w,sizeof(w),1,recordFile); + fseek(recordFile,recordSize+sizeof(w),SEEK_SET); +} + +void RecordStop() +{ + if(!recording) + return; + recording=0; + + RecordFlush(); + + fclose(recordFile); +} + +void RecordWrite(s16 left, s16 right) +{ + if(!recording) + return; + + s16 buffer[2]={left,right}; + + recordSize+=4; + + fwrite(buffer,4,1,recordFile); + + if((recordSize&1023)==0) + RecordFlush(); + +} diff --git a/plugins/spu2ghz/src/waveout.cpp b/plugins/spu2ghz/src/waveout.cpp new file mode 100644 index 0000000000..a9c6a14ae8 --- /dev/null +++ b/plugins/spu2ghz/src/waveout.cpp @@ -0,0 +1,278 @@ +//GiGaHeRz's SPU2 Driver +//Copyright (c) 2003-2008, David Quintana +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library 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 +//Lesser General Public License for more details. +// +//You should have received a copy of the GNU Lesser General Public +//License along with this library; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +#include "spu2.h" +#include "dialogs.h" +#include + + +class WaveOutModule: public SndOutModule +{ +private: +# define MAX_BUFFER_COUNT 8 + + static const int PacketsPerBuffer = (1024 / SndOutPacketSize); + static const int BufferSize = SndOutPacketSize*PacketsPerBuffer; + static const int BufferSizeBytes = BufferSize << 1; + + u32 numBuffers; + HWAVEOUT hwodevice; + WAVEFORMATEX wformat; + WAVEHDR whbuffer[MAX_BUFFER_COUNT]; + + s16* qbuffer; + + #define QBUFFER(x) (qbuffer + BufferSize * (x)) + + bool waveout_running; + HANDLE thread; + DWORD tid; + + SndBuffer *buff; + + FILE *voicelog; + + char ErrText[256]; + + static DWORD CALLBACK RThread(WaveOutModule*obj) + { + return obj->Thread(); + } + + DWORD CALLBACK Thread() + { + while( waveout_running ) + { + bool didsomething = false; + for(u32 i=0;idwBytesRecorded = buf->dwBufferLength; + + s16 *t = (s16*)buf->lpData; + for(int p=0; pReadSamples( t ); + + whbuffer[i].dwFlags&=~WHDR_DONE; + waveOutWrite(hwodevice,buf,sizeof(WAVEHDR)); + didsomething = true; + } + + if( didsomething ) + Sleep(1); + else + Sleep(0); + } + return 0; + } + +public: + s32 Init(SndBuffer *sb) + { + buff = sb; + numBuffers = Config_WaveOut.NumBuffers; + + MMRESULT woores; + + if (Test()) return -1; + + wformat.wFormatTag=WAVE_FORMAT_PCM; + wformat.nSamplesPerSec=SampleRate; + wformat.wBitsPerSample=16; + wformat.nChannels=2; + wformat.nBlockAlign=((wformat.wBitsPerSample * wformat.nChannels) / 8); + wformat.nAvgBytesPerSec=(wformat.nSamplesPerSec * wformat.nBlockAlign); + wformat.cbSize=0; + + qbuffer=new s16[BufferSize*numBuffers]; + + woores = waveOutOpen(&hwodevice,WAVE_MAPPER,&wformat,0,0,0); + if (woores != MMSYSERR_NOERROR) + { + waveOutGetErrorText(woores,(char *)&ErrText,255); + SysMessage("WaveOut Error: %s",ErrText); + return -1; + } + + for(u32 i=0;i MAX_BUFFER_COUNT ) Config_WaveOut.NumBuffers = MAX_BUFFER_COUNT; + } + EndDialog(hWnd,0); + break; + case IDCANCEL: + EndDialog(hWnd,0); + break; + default: + return FALSE; + } + break; + + case WM_HSCROLL: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + switch(wmId) { + //case TB_ENDTRACK: + //case TB_THUMBPOSITION: + case TB_LINEUP: + case TB_LINEDOWN: + case TB_PAGEUP: + case TB_PAGEDOWN: + wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0); + case TB_THUMBTRACK: + if( wmEvent < 3 ) wmEvent = 3; + if( wmEvent > MAX_BUFFER_COUNT ) wmEvent = MAX_BUFFER_COUNT; + SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent); + sprintf_s(temp,128,"%d (%d ms latency)",wmEvent, 1000 / (96000 / (wmEvent * BufferSize))); + SetWindowText(GetDlgItem(hWnd,IDC_LATENCY_LABEL),temp); + break; + default: + return FALSE; + } + break; + + default: + return FALSE; + } + return TRUE; + } + +public: + virtual void Configure(HWND parent) + { + INT_PTR ret; + ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_WAVEOUT),GetActiveWindow(),(DLGPROC)ConfigProc,1); + if(ret==-1) + { + MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0); + return; + } + } + + virtual bool Is51Out() const { return false; } + + s32 Test() const + { + if (waveOutGetNumDevs() == 0) { + SysMessage("No waveOut Devices Present\n"); return -1; + } + return 0; + } + + int GetEmptySampleCount() const + { + int result = 0; + for(int i=0;i +#include + +// need C definitions +extern "C" { +#define GSdefs +#include "PS2Edefs.h" +} + +#ifdef _WIN32 + +#include +#include + +extern HWND GShwnd; + +#else + +#include +#include +#include +#include + +#define __inline inline + +typedef int BOOL; + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +#endif + +#if defined(_MSC_VER) +#define FASTCALL(fn) __fastcall fn +#else + +#ifdef __x86_64 +#define FASTCALL(fn) fn +#else +#define FASTCALL(fn) __attribute__((fastcall)) fn +#endif +#endif + +struct Vector_16F +{ + u16 x, y, z, w; +}; + + +///////////////////// +// define when releasing +// The only code that uses it is commented out! +//#define ZEROGS_CACHEDCLEAR // much better performance +//#define RELEASE_TO_PUBLIC + +#if defined(ZEROGS_DEVBUILD) +#define GS_LOG __Log +#else +#define GS_LOG 0&& +#endif + +#define ERROR_LOG __LogToConsole +#define DEBUG_LOG printf + +#ifdef RELEASE_TO_PUBLIC +#define WARN_LOG 0&& +#define PRIM_LOG 0&& +#else +#define WARN_LOG printf +#define PRIM_LOG if (conf.log & 0x00000010) GS_LOG +#endif + +#ifndef GREG_LOG +#define GREG_LOG 0&& +#endif +#ifndef PRIM_LOG +#define PRIM_LOG 0&& +#endif +#ifndef WARN_LOG +#define WARN_LOG 0&& +#endif + +#define REG64(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + struct { \ + +#define REG128(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + struct { \ + +#define REG64_(prefix, name) REG64(prefix##name) +#define REG128_(prefix, name) REG128(prefix##name) + +#define REG_END }; }; +#define REG_END2 }; + +#define REG64_SET(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + +#define REG128_SET(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + +#define REG_SET_END }; + +REG64_(GSReg, BGCOLOR) + u32 R:8; + u32 G:8; + u32 B:8; + u32 _PAD1:8; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, BUSDIR) + u32 DIR:1; + u32 _PAD1:31; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, CSR) + u32 SIGNAL:1; + u32 FINISH:1; + u32 HSINT:1; + u32 VSINT:1; + u32 EDWINT:1; + u32 ZERO1:1; + u32 ZERO2:1; + u32 _PAD1:1; + u32 FLUSH:1; + u32 RESET:1; + u32 _PAD2:2; + u32 NFIELD:1; + u32 FIELD:1; + u32 FIFO:2; + u32 REV:8; + u32 ID:8; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, DISPFB) // (-1/2) + u32 FBP:9; + u32 FBW:6; + u32 PSM:5; + u32 _PAD:12; + u32 DBX:11; + u32 DBY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, DISPLAY) // (-1/2) + u32 DX:12; + u32 DY:11; + u32 MAGH:4; + u32 MAGV:2; + u32 _PAD:3; + u32 DW:12; + u32 DH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTBUF) + u32 EXBP:14; + u32 EXBW:6; + u32 FBIN:2; + u32 WFFMD:1; + u32 EMODA:2; + u32 EMODC:2; + u32 _PAD1:5; + u32 WDX:11; + u32 WDY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, EXTDATA) + u32 SX:12; + u32 SY:11; + u32 SMPH:4; + u32 SMPV:2; + u32 _PAD1:3; + u32 WW:12; + u32 WH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTWRITE) + u32 WRITE; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, IMR) + u32 _PAD1:8; + u32 SIGMSK:1; + u32 FINISHMSK:1; + u32 HSMSK:1; + u32 VSMSK:1; + u32 EDWMSK:1; + u32 _PAD2:19; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, PMODE) + u32 EN1:1; + u32 EN2:1; + u32 CRTMD:3; + u32 MMOD:1; + u32 AMOD:1; + u32 SLBG:1; + u32 ALP:8; + u32 _PAD:16; + u32 _PAD1:32; +REG_END + +REG64_(GSReg, SIGLBLID) + u32 SIGID:32; + u32 LBLID:32; +REG_END + +REG64_(GSReg, SMODE1) + u32 RC:3; + u32 LC:7; + u32 T1248:2; + u32 SLCK:1; + u32 CMOD:2; + u32 EX:1; + u32 PRST:1; + u32 SINT:1; + u32 XPCK:1; + u32 PCK2:2; + u32 SPML:4; + u32 GCONT:1; + u32 PHS:1; + u32 PVS:1; + u32 PEHS:1; + u32 PEVS:1; + u32 CLKSEL:2; + u32 NVCK:1; + u32 SLCK2:1; + u32 VCKSEL:2; + u32 VHP:1; + u32 _PAD1:27; +REG_END + +REG64_(GSReg, SMODE2) + u32 INT:1; + u32 FFMD:1; + u32 DPMS:2; + u32 _PAD2:28; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, SIGBLID) + u32 SIGID; + u32 LBLID; +REG_END + +extern int g_LastCRC; +extern u8* g_pBasePS2Mem; +#define PMODE ((GSRegPMODE*)(g_pBasePS2Mem+0x0000)) +#define SMODE1 ((GSRegSMODE1*)(g_pBasePS2Mem+0x0010)) +#define SMODE2 ((GSRegSMODE2*)(g_pBasePS2Mem+0x0020)) +// SRFSH +#define SYNCH1 ((GSRegSYNCH1*)(g_pBasePS2Mem+0x0040)) +#define SYNCH2 ((GSRegSYNCH2*)(g_pBasePS2Mem+0x0050)) +#define SYNCV ((GSRegSYNCV*)(g_pBasePS2Mem+0x0060)) +#define DISPFB1 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0070)) +#define DISPLAY1 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x0080)) +#define DISPFB2 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0090)) +#define DISPLAY2 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x00a0)) +#define EXTBUF ((GSRegEXTBUF*)(g_pBasePS2Mem+0x00b0)) +#define EXTDATA ((GSRegEXTDATA*)(g_pBasePS2Mem+0x00c0)) +#define EXTWRITE ((GSRegEXTWRITE*)(g_pBasePS2Mem+0x00d0)) +#define BGCOLOR ((GSRegBGCOLOR*)(g_pBasePS2Mem+0x00e0)) +#define CSR ((GSRegCSR*)(g_pBasePS2Mem+0x1000)) +#define IMR ((GSRegIMR*)(g_pBasePS2Mem+0x1010)) +#define BUSDIR ((GSRegBUSDIR*)(g_pBasePS2Mem+0x1040)) +#define SIGLBLID ((GSRegSIGBLID*)(g_pBasePS2Mem+0x1080)) + +#define GET_GSFPS (((SMODE1->CMOD&1) ? 50 : 60) / (SMODE2->INT ? 1 : 2)) + +// +// sps2tags.h +// +#ifdef _M_AMD64 +#define GET_GIF_REG(tag, reg) \ + (((tag).ai64[1] >> ((reg) << 2)) & 0xf) +#else +#define GET_GIF_REG(tag, reg) \ + (((tag).ai32[2 + ((reg) >> 3)] >> (((reg) & 7) << 2)) & 0xf) +#endif + +// +// GIFTag +REG128(GIFTag) + u32 NLOOP:15; + u32 EOP:1; + u32 _PAD1:16; + u32 _PAD2:14; + u32 PRE:1; + u32 PRIM:11; + u32 FLG:2; // enum GIF_FLG + u32 NREG:4; + u64 REGS:64; +REG_END + +typedef struct { + int x, y, w, h; +} Rect; + +typedef struct { + int x, y; +} Point; + +typedef struct { + int x0, y0; + int x1, y1; +} Rect2; + +typedef struct { + int x, y, c; +} PointC; + +#define GSOPTION_FULLSCREEN 0x2 +#define GSOPTION_BMPSNAP 0x4 +#define GSOPTION_CAPTUREAVI 0x8 + +#define GSOPTION_WINDIMS 0x70 +#define GSOPTION_WIN640 0x00 +#define GSOPTION_WIN800 0x10 +#define GSOPTION_WIN1024 0x20 +#define GSOPTION_WIN1280 0x30 +#define GSOPTION_WIN960W 0x40 +#define GSOPTION_WIN1280W 0x50 +#define GSOPTION_WIN1920W 0x60 + +#define GSOPTION_WIREFRAME 0x100 +#define GSOPTION_WIDESCREEN 0x200 +#define GSOPTION_LOADED 0x8000 + +typedef struct { + u8 mrtdepth; // write color in render target + u8 interlace; + u8 aa; // antialiasing 0 - off, 1 - 2x, 2 - 4x + u8 bilinear; // set to enable bilinear support + u32 options; + u32 gamesettings; // default game settings + int width, height; + int winstyle; // window style before full screen +#ifdef GS_LOG + u32 log; +#endif +} GSconf; + +#define VERTEXGPU \ + union \ + { \ + struct \ + { \ + u16 x, y, f, resv0; /* note: xy is 12d3*/ \ + u32 rgba; \ + u32 z; \ + }; \ + }; \ + \ + float s, t, q; \ + +typedef struct { + s16 x, y, f, resv0; /* note: xy is 12d3*/ \ + u32 rgba; + u32 z; + float s, t, q; +} VertexGPU; + +typedef struct { + VERTEXGPU + u16 u, v; +} Vertex; + +extern int g_GameSettings; +extern GSconf conf; +extern int ppf; + +#define PSMCT32 0 +#define PSMCT24 1 +#define PSMCT16 2 +#define PSMCT16S 10 +#define PSMT8 19 +#define PSMT4 20 +#define PSMT8H 27 +#define PSMT4HL 36 +#define PSMT4HH 44 +#define PSMT32Z 48 +#define PSMT24Z 49 +#define PSMT16Z 50 +#define PSMT16SZ 58 + +#define PSMT_ISCLUT(psm) (((psm)&0x7)>2) +#define PSMT_IS16BIT(psm) (((psm)&7)==2||((psm)&7)==10) + +typedef struct { + int nloop; + int eop; + int nreg; +} tagInfo; + +typedef union { + s64 SD; + u64 UD; + s32 SL[2]; + u32 UL[2]; + s16 SS[4]; + u16 US[4]; + s8 SC[8]; + u8 UC[8]; +} reg64; + +/* general purpose regs structs */ +typedef struct { + int fbp; + int fbw; + int fbh; + int psm; + u32 fbm; +} frameInfo; + +typedef struct { + u16 prim; + + union { + struct { + u16 iip : 1; + u16 tme : 1; + u16 fge : 1; + u16 abe : 1; + u16 aa1 : 1; + u16 fst : 1; + u16 ctxt : 1; + u16 fix : 1; + u16 resv : 8; + }; + u16 _val; + }; +} primInfo; + +extern primInfo *prim; + +typedef union { + struct { + u32 ate : 1; + u32 atst : 3; + u32 aref : 8; + u32 afail : 2; + u32 date : 1; + u32 datm : 1; + u32 zte : 1; + u32 ztst : 2; + u32 resv : 13; + }; + u32 _val; +} pixTest; + +typedef struct { + int bp; + int bw; + int psm; +} bufInfo; + +typedef struct { + int tbp0; + int tbw; + int cbp; + u16 tw, th; + u8 psm; + u8 tcc; + u8 tfx; + u8 cpsm; + u8 csm; + u8 csa; + u8 cld; +} tex0Info; + +#define TEX_MODULATE 0 +#define TEX_DECAL 1 +#define TEX_HIGHLIGHT 2 +#define TEX_HIGHLIGHT2 3 + +typedef struct { + int lcm; + int mxl; + int mmag; + int mmin; + int mtba; + int l; + int k; +} tex1Info; + +typedef struct { + int wms; + int wmt; + int minu; + int maxu; + int minv; + int maxv; +} clampInfo; + +typedef struct { + int cbw; + int cou; + int cov; +} clutInfo; + +typedef struct { + int tbp[3]; + int tbw[3]; +} miptbpInfo; + +typedef struct { + u16 aem; + u8 ta[2]; + float fta[2]; +} texaInfo; + +typedef struct { + int sx; + int sy; + int dx; + int dy; + int dir; +} trxposInfo; + +typedef struct { + union { + struct { + u8 a : 2; + u8 b : 2; + u8 c : 2; + u8 d : 2; + }; + u8 abcd; + }; + + u8 fix : 8; +} alphaInfo; + +typedef struct { + u16 zbp; // word address / 64 + u8 psm; + u8 zmsk; +} zbufInfo; + +typedef struct { + int fba; +} fbaInfo; + +typedef struct { + int mode; + int regn; + u64 regs; + tagInfo tag; +} pathInfo; + +typedef struct { + Vertex gsvertex[3]; + u32 rgba; + float q; + Vertex vertexregs; + + int primC; // number of verts current storing + int primIndex; // current prim index + int nTriFanVert; + + int prac; + int dthe; + int colclamp; + int fogcol; + int smask; + int pabe; + u64 buff[2]; + int buffsize; + int cbp[2]; // internal cbp registers + + u32 CSRw; + + primInfo _prim[2]; + bufInfo srcbuf, srcbufnew; + bufInfo dstbuf, dstbufnew; + + clutInfo clut; + + texaInfo texa; + trxposInfo trxpos, trxposnew; + + int imageWtemp, imageHtemp; + + int imageTransfer; + int imageWnew, imageHnew, imageX, imageY, imageEndX, imageEndY; + + pathInfo path1; + pathInfo path2; + pathInfo path3; + +} GSinternal; + +extern GSinternal gs; + +extern FILE *gsLog; + +void __Log(const char *fmt, ...); +void __LogToConsole(const char *fmt, ...); + +void LoadConfig(); +void SaveConfig(); + +extern void (*GSirq)(); + +void *SysLoadLibrary(char *lib); // Loads Library +void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library +char *SysLibError(); // Gets previous error loading sysbols +void SysCloseLibrary(void *lib); // Closes Library +void SysMessage(char *fmt, ...); + +extern "C" void * memcpy_amd(void *dest, const void *src, size_t n); +extern "C" u8 memcmp_mmx(const void *dest, const void *src, int n); + +template +class CInterfacePtr +{ +public: + inline CInterfacePtr() : ptr(NULL) {} + inline explicit CInterfacePtr(T* newptr) : ptr(newptr) { if ( ptr != NULL ) ptr->AddRef(); } + inline ~CInterfacePtr() { if( ptr != NULL ) ptr->Release(); } + + inline T* operator* () { assert( ptr != NULL); return *ptr; } + inline T* operator->() { return ptr; } + inline T* get() { return ptr; } + + inline void release() { + if( ptr != NULL ) { ptr->Release(); ptr = NULL; } + } + + inline operator T*() { return ptr; } + + inline bool operator==(T* rhs) { return ptr == rhs; } + inline bool operator!=(T* rhs) { return ptr != rhs; } + + inline CInterfacePtr& operator= (T* newptr) { + if( ptr != NULL ) ptr->Release(); + ptr = newptr; + + if( ptr != NULL ) ptr->AddRef(); + return *this; + } + +private: + T* ptr; +}; + +#define RGBA32to16(c) \ + (u16)((((c) & 0x000000f8) >> 3) | \ + (((c) & 0x0000f800) >> 6) | \ + (((c) & 0x00f80000) >> 9) | \ + (((c) & 0x80000000) >> 16)) \ + +#define RGBA16to32(c) \ + (((c) & 0x001f) << 3) | \ + (((c) & 0x03e0) << 6) | \ + (((c) & 0x7c00) << 9) | \ + (((c) & 0x8000) ? 0xff000000 : 0) \ + +// converts float16 [0,1] to BYTE [0,255] (assumes value is in range, otherwise will take lower 8bits) +// f is a u16 +__forceinline u16 Float16ToBYTE(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + u16 d = ((((f&0x3ff)|0x400)*255)>>(10-((f>>10)&0x1f)+15)); + return d > 255 ? 255 : d; +} + +__forceinline u16 Float16ToALPHA(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + // round up instead of down (crash and burn), too much and charlie breaks + u16 d = (((((f&0x3ff)|0x400))*255)>>(10-((f>>10)&0x1f)+15)); + d = (d)>>1; + return d > 255 ? 255 : d; +} + +#ifndef COLOR_ARGB +#define COLOR_ARGB(a,r,g,b) \ + ((u32)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) +#endif + +// assumes that positive in [1,2] (then extracts fraction by just looking at the specified bits) +#define Float16ToBYTE_2(f) ((u8)(*(u16*)&f>>2)) +#define Float16To5BIT(f) (Float16ToBYTE(f)>>3) + +#define Float16Alpha(f) (((*(u16*)&f&0x7c00)>=0x3900)?0x8000:0) // alpha is >= 1 + +// converts an array of 4 u16s to a u32 color +// f is a pointer to a u16 +#define Float16ToARGB(f) COLOR_ARGB(Float16ToALPHA(f.w), Float16ToBYTE(f.x), Float16ToBYTE(f.y), Float16ToBYTE(f.z)); + +#define Float16ToARGB16(f) (Float16Alpha(f.w)|(Float16To5BIT(f.x)<<10)|(Float16To5BIT(f.y)<<5)|Float16To5BIT(f.z)) + +// used for Z values +#define Float16ToARGB_Z(f) COLOR_ARGB((u32)Float16ToBYTE_2(f.w), Float16ToBYTE_2(f.x), Float16ToBYTE_2(f.y), Float16ToBYTE_2(f.z)) +#define Float16ToARGB16_Z(f) ((Float16ToBYTE_2(f.y)<<8)|Float16ToBYTE_2(f.z)) + + +inline float Clamp(float fx, float fmin, float fmax) +{ + if( fx < fmin ) return fmin; + return fx > fmax ? fmax : fx; +} + +#endif diff --git a/plugins/zerogs/dx/GSmain.cpp b/plugins/zerogs/dx/GSmain.cpp new file mode 100644 index 0000000000..eb1d957347 --- /dev/null +++ b/plugins/zerogs/dx/GSmain.cpp @@ -0,0 +1,1049 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ +#if defined(_WIN32) || defined(_WIN32) +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +using namespace std; + +#include "Win32.h" + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" +#include "zerogsshaders/zerogsshaders.h" + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +#ifdef _DEBUG +HANDLE g_hCurrentThread = NULL; +#endif + +GSinternal gs; +char GStitle[256]; +GSconf conf; +int ppf; +primInfo *prim; +FILE *gsLog; +int g_GSMultiThreaded = 0; +void (*GSirq)(); +u8* g_pBasePS2Mem = NULL; +int g_TransferredToGPU = 0; +int g_GameSettings = 0; + +static LARGE_INTEGER luPerfFreq; + +// statistics +u32 g_nGenVars = 0, g_nTexVars = 0, g_nAlphaVars = 0, g_nResolve = 0; + +#define VER 97 +const unsigned char version = PS2E_GS_VERSION; +unsigned char revision = 0; // revision and build gives plugin version +unsigned char build = VER; +unsigned char minor = 1; + +#ifdef _DEBUG +char *libraryName = "ZeroGS Playground (Debug) "; +#elif defined(RELEASE_TO_PUBLIC) + +#ifdef ZEROGS_SSE2 +char *libraryName = "ZeroGS Playground"; +#else +char *libraryName = "ZeroGS Playground (no SSE2)"; +#endif + +#else +char *libraryName = "ZeroGS Playground (Dev) "; +#endif + +static const char* s_aa[5] = { "AA none |", "AA 2x |", "AA 4x |", "AA 8x", "AA 16x" }; + +extern GIFRegHandler g_GIFPackedRegHandlers[]; +extern GIFRegHandler g_GIFRegHandlers[]; +GIFRegHandler g_GIFTempRegHandlers[16] = {0}; +extern int g_nPixelShaderVer; +extern int g_nFrameRender; +extern int g_nFramesSkipped; + +const char* pbilinear[] = { "off", "normal", "forced" }; + +int s_frameskipping = 0; +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_GS; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (version<<16) | (revision<<8) | build | (minor << 24); +} + +#ifdef _WIN32 + +HWND GShwnd; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "GSsoftdx Msg", 0); +} + +#endif + +void __Log(const char *fmt, ...) { + va_list list; + + // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. + // (GSinit won't have been called then) + + if (gsLog == NULL || !conf.log) return; + + va_start(list, fmt); + vfprintf(gsLog, fmt, list); + va_end(list); +} + +void __LogToConsole(const char *fmt, ...) { + va_list list; + + printf("ZeroGS: "); + + // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. + // (GSinit won't have been called then) + + va_start(list, fmt); + if( gsLog != NULL ) + vfprintf(gsLog, fmt, list); + vprintf(fmt, list); + va_end(list); +} + +void CALLBACK GSsetBaseMem(void* pmem) { + g_pBasePS2Mem = (u8*)pmem; +} + +extern int VALIDATE_THRESH; +extern u32 TEXDESTROY_THRESH; +int g_LastCRC = 0; +void CALLBACK GSsetGameCRC(int crc, int options) +{ + VALIDATE_THRESH = 8; + g_GameSettings = conf.gamesettings|options; + conf.mrtdepth = !(conf.gamesettings&GAME_DISABLEMRTDEPTH); + + g_GameSettings |= GAME_PATH3HACK; + g_LastCRC = crc; + + //g_GameSettings |= GAME_PARTIALDEPTH; + +// g_GameSettings |= GAME_DOPARALLELCTX|GAME_XENOSPECHACK; +// VALIDATE_THRESH = 64; +// TEXDESTROY_THRESH = 32; + + switch(crc) { + case 0x54A548B4: // crash n burn + // overbright + if( pd3dDevice != NULL ) { + pd3dDevice->SetPixelShaderConstantF(27, DXVEC4(0.5f, 0.9f/256.0f, 0,1/255.0f), 1); // g_fExactColor + } + break; + + case 0xA3D63039: // xenosaga(j) + case 0x0E7807B2: // xenosaga(u) + g_GameSettings |= GAME_DOPARALLELCTX; + VALIDATE_THRESH = 64; + TEXDESTROY_THRESH = 32; + break; + + case 0x7D2FE035: // espgaluda (j) + VALIDATE_THRESH = 24; + //g_GameSettings |= GAME_BIGVALIDATE; + break; + } + + DEBUG_LOG("ZeroGS: Set game options: 0x%8.8x\n", g_GameSettings); +} + +void CALLBACK GSsetFrameSkip(int frameskip) +{ + s_frameskipping |= frameskip; + if( frameskip && g_nFrameRender > 1 ) { + + for(int i = 0; i < 16; ++i) { + g_GIFPackedRegHandlers[i] = GIFPackedRegHandlerNOP; + } + + // still keep certain handlers + g_GIFPackedRegHandlers[6] = GIFRegHandlerTEX0_1; + g_GIFPackedRegHandlers[7] = GIFRegHandlerTEX0_2; + g_GIFPackedRegHandlers[14] = GIFPackedRegHandlerA_D; + + g_GIFRegHandlers[0] = GIFRegHandlerNOP; + g_GIFRegHandlers[1] = GIFRegHandlerNOP; + g_GIFRegHandlers[2] = GIFRegHandlerNOP; + g_GIFRegHandlers[3] = GIFRegHandlerNOP; + g_GIFRegHandlers[4] = GIFRegHandlerNOP; + g_GIFRegHandlers[5] = GIFRegHandlerNOP; + g_GIFRegHandlers[12] = GIFRegHandlerNOP; + g_GIFRegHandlers[13] = GIFRegHandlerNOP; + g_GIFRegHandlers[26] = GIFRegHandlerNOP; + g_GIFRegHandlers[27] = GIFRegHandlerNOP; + g_nFrameRender = 0; + } + else if( !frameskip && g_nFrameRender <= 0 ) { + g_nFrameRender = 1; + + if( g_GIFTempRegHandlers[0] == NULL ) return; // not init yet + + // restore + memcpy(g_GIFPackedRegHandlers, g_GIFTempRegHandlers, sizeof(g_GIFTempRegHandlers)); + + g_GIFRegHandlers[0] = GIFRegHandlerPRIM; + g_GIFRegHandlers[1] = GIFRegHandlerRGBAQ; + g_GIFRegHandlers[2] = GIFRegHandlerST; + g_GIFRegHandlers[3] = GIFRegHandlerUV; + g_GIFRegHandlers[4] = GIFRegHandlerXYZF2; + g_GIFRegHandlers[5] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[12] = GIFRegHandlerXYZF3; + g_GIFRegHandlers[13] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[26] = GIFRegHandlerPRMODECONT; + g_GIFRegHandlers[27] = GIFRegHandlerPRMODE; + } +} + +void CALLBACK GSreset() { + + memset(&gs, 0, sizeof(gs)); + + ZeroGS::GSStateReset(); + + gs.prac = 1; + prim = &gs._prim[0]; + gs.nTriFanVert = -1; + gs.imageTransfer = -1; + gs.q = 1; +} + +void CALLBACK GSgifSoftReset(u32 mask) +{ + if( mask & 1 ) memset(&gs.path1, 0, sizeof(gs.path1)); + if( mask & 2 ) memset(&gs.path2, 0, sizeof(gs.path2)); + if( mask & 4 ) memset(&gs.path3, 0, sizeof(gs.path3)); + gs.imageTransfer = -1; + gs.q = 1; + gs.nTriFanVert = -1; +} + +s32 CALLBACK GSinit() +{ + memcpy(g_GIFTempRegHandlers, g_GIFPackedRegHandlers, sizeof(g_GIFTempRegHandlers)); + +#ifdef GS_LOG + gsLog = fopen("logs/gsLog.txt", "w"); + if (gsLog == NULL) { + gsLog = fopen("gsLog.txt", "w"); + if (gsLog == NULL) { + SysMessage("Can't create gsLog.txt"); return -1; + } + } + setvbuf(gsLog, NULL, _IONBF, 0); + GS_LOG("GSinit\n"); +#endif + + GSreset(); + GS_LOG("GSinit ok\n"); + + return 0; +} + +void CALLBACK GSshutdown() +{ +#ifdef GS_LOG + fclose(gsLog); +#endif +} + +LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + static int nWindowWidth = 0, nWindowHeight = 0; + + switch( msg ) { + case WM_DESTROY: + PostQuitMessage( 0 ); + return 0; + + case WM_KEYDOWN: +// switch(wParam) { +// case VK_ESCAPE: +// SendMessage(hWnd, WM_DESTROY, 0L, 0L); +// break; +// } + break; + + case WM_ACTIVATE: + + if( wParam != WA_INACTIVE ) { + //DEBUG_LOG("restoring device\n"); + ZeroGS::Restore(); + } + + break; + + case WM_SIZE: + nWindowWidth = lParam&0xffff; + nWindowHeight = lParam>>16; + ZeroGS::ChangeWindowSize(nWindowWidth, nWindowHeight); + + break; + + case WM_SIZING: + // if button is 0, then just released so can resize + if( GetSystemMetrics(SM_SWAPBUTTON) ? !GetAsyncKeyState(VK_RBUTTON) : !GetAsyncKeyState(VK_LBUTTON) ) { + ZeroGS::SetChangeDeviceSize(nWindowWidth, nWindowHeight); + } + break; + + case WM_SETCURSOR: + SetCursor(NULL); + break; + } + + return DefWindowProc( hWnd, msg, wParam, lParam ); +} + +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) { + + g_GSMultiThreaded = multithread; + + GS_LOG("GSopen\n"); + +#ifdef _DEBUG + g_hCurrentThread = GetCurrentThread(); +#endif + + assert( GSirq != NULL ); + LoadConfig(); + g_GameSettings = 0; + + strcpy(GStitle, Title); + + RECT rc, rcdesktop; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, + GetModuleHandle(NULL), NULL, NULL, NULL, NULL, + "PS2EMU_ZEROGS", NULL }; + RegisterClassEx( &wc ); + + AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + GShwnd = CreateWindow( "PS2EMU_ZEROGS", "ZeroGS", WS_OVERLAPPEDWINDOW, + (rcdesktop.right-(rc.right-rc.left))/2, (rcdesktop.bottom-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, wc.hInstance, NULL ); + + if(GShwnd == NULL) { + GS_LOG("Failed to create window. Exiting..."); + return -1; + } + + if( pDsp != NULL ) + *(int*)pDsp = (int)GShwnd; + + DEBUG_LOG("creating zerogs\n"); + //if (conf.record) recOpen(); + if( FAILED(ZeroGS::Create(conf.width, conf.height)) ) + return -1; + + DEBUG_LOG("initialization successful\n"); + + if( FAILED(ZeroGS::InitDeviceObjects()) ) + return -1; + + if( conf.bilinear == 2 ) { + ZeroGS::AddMessage("forced bilinear filtering - on", 1000); + } + else if( conf.bilinear == 1 ) { + ZeroGS::AddMessage("normal bilinear filtering - on", 1000); + } + if( conf.aa ) { + char strtitle[64]; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); + ZeroGS::AddMessage(strtitle); + } + if( conf.options & GSOPTION_WIDESCREEN ) { + ZeroGS::AddMessage("16:9 widescreen - on", 1000); + } + + // set just in case + SetWindowLongPtr(GShwnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)MsgProc); + + ShowWindow( GShwnd, SW_SHOWDEFAULT ); + UpdateWindow( GShwnd ); + SetFocus(GShwnd); + + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + +#ifdef _WIN32 + QueryPerformanceFrequency(&luPerfFreq); +#else + luPerfFreq.QuadPart = 1; +#endif + + GS_LOG("GSopen ok\n"); + + gs.path1.mode = 0; + gs.path2.mode = 0; + gs.path3.mode = 0; + + return 0; +} + +void CALLBACK GSclose() { + ZeroGS::Destroy(1); + + //if (conf.record) recClose(); + +#ifdef _WIN32 + DestroyWindow(GShwnd); +#endif +} + +void CALLBACK GSirqCallback(void (*callback)()) { + GSirq = callback; +} + +void CALLBACK GSwriteCSR(u32 write) +{ + gs.CSRw = write; +} + +void CALLBACK GSchangeSaveState(int newstate, const char* filename) +{ + char str[255]; + sprintf(str, "save state %d", newstate); + ZeroGS::AddMessage(str); +} + +void CALLBACK GSmakeSnapshot(char *path) +{ + FILE *bmpfile; + char filename[256]; + u32 snapshotnr = 0; + + // increment snapshot value & try to get filename + for (;;) { + snapshotnr++; + + sprintf(filename,"%ssnap%03ld.%s", path, snapshotnr, (conf.options&GSOPTION_BMPSNAP)?"bmp":"jpg"); + + bmpfile=fopen(filename,"rb"); + if (bmpfile == NULL) break; + fclose(bmpfile); + } + + // try opening new snapshot file + if((bmpfile=fopen(filename,"wb"))==NULL) { + char strdir[255]; + sprintf(strdir, "%s", path); + CreateDirectory(strdir, NULL); + + if((bmpfile=fopen(filename,"wb"))==NULL) return; + } + + fclose(bmpfile); + + // get the bits + ZeroGS::SaveSnapshot(filename); +} + +int UPDATE_FRAMES = 16; +int g_nFrame = 0; +int g_nRealFrame = 0; +static BOOL g_bHidden = 0; + +float fFPS = 0; + +void CALLBACK GSvsync(int interlace) +{ + GS_LOG("\nGSvsync\n\n"); + + static u32 dwTime = timeGetTime(); + static int nToNextUpdate = 1; + + char strtitle[512]; + + g_nRealFrame++; + + MSG msg; + ZeroMemory( &msg, sizeof(msg) ); + while( 1 ) { + if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) + { + switch( msg.message ) { + case WM_KEYDOWN : + if( msg.wParam == VK_F5 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + if( g_nPixelShaderVer == SHADER_20 ) { + conf.bilinear = 0; + sprintf(strtitle, "ps 2.0 doesn't support bilinear filtering"); + } + else { + conf.bilinear = (conf.bilinear+1)%3; + sprintf(strtitle, "bilinear filtering - %s", pbilinear[conf.bilinear]); + } + } + else { + conf.interlace++; + if( conf.interlace > 2 ) conf.interlace = 0; + if( conf.interlace < 2 ) sprintf(strtitle, "interlace on - mode %d", conf.interlace); + else sprintf(strtitle, "interlace off"); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); + } + else if( msg.wParam == VK_F6 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + conf.aa--; // -1 + if( conf.aa > 4) conf.aa = 4; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + else { + conf.aa++; + if( conf.aa > 4 ) conf.aa = 0; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); + } + else if( msg.wParam == VK_F7 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + extern BOOL g_bDisplayFPS; + g_bDisplayFPS ^= 1; + } + else { + conf.options ^= GSOPTION_WIREFRAME; + SETRS(D3DRS_FILLMODE, (conf.options&GSOPTION_WIREFRAME)?D3DFILL_WIREFRAME:D3DFILL_SOLID); + sprintf(strtitle, "wireframe rendering - %s", (conf.options&GSOPTION_WIREFRAME)?"on":"off"); +// conf.options ^= GSOPTION_CAPTUREAVI; +// if( conf.options & GSOPTION_CAPTUREAVI ) ZeroGS::StartCapture(); +// else ZeroGS::StopCapture(); +// +// sprintf(strtitle, "capture avi (zerogs_dump.avi) - %s", (conf.options&GSOPTION_CAPTUREAVI) ? "on" : "off"); +// ZeroGS::AddMessage(strtitle); +// SaveConfig(); + } + } + else if( msg.wParam == VK_F9 ) { + + if( (GetKeyState(VK_SHIFT)&0x8000) ) { + conf.options ^= GSOPTION_WIDESCREEN; + sprintf(strtitle, "16:9 widescreen - %s", (conf.options&GSOPTION_WIDESCREEN)?"on":"off"); + } + else { + g_GameSettings ^= GAME_PATH3HACK; + sprintf(strtitle, "path3 hack - %s", (g_GameSettings&GAME_PATH3HACK) ? "on" : "off"); + } + ZeroGS::AddMessage(strtitle); + } + else if( msg.wParam == VK_ESCAPE ) { + + if( conf.options & GSOPTION_FULLSCREEN ) { + // destroy that msg + conf.options &= ~GSOPTION_FULLSCREEN; + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + ZeroGS::ChangeDeviceSize(conf.width, conf.height); + UpdateWindow(GShwnd); + continue; // so that msg doesn't get sent + } + else { + SendMessage(GShwnd, WM_DESTROY, 0, 0); + g_bHidden = 1; + return; + } + } + + break; + } + + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + else + break; + } + + if( (GetKeyState(VK_MENU)&0x8000) && (GetKeyState(VK_RETURN)&0x8000) ) { + conf.options ^= GSOPTION_FULLSCREEN; + + if( conf.options & GSOPTION_FULLSCREEN ) { + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + } + + ZeroGS::SetChangeDeviceSize( + (conf.options&GSOPTION_FULLSCREEN) ? 1280 : conf.width, + (conf.options&GSOPTION_FULLSCREEN) ? 960 : conf.height); + } + +// if( conf.fullscreen && (GetKeyState(VK_ESCAPE)&0x8000)) { +// conf.fullscreen &= ~GSOPTION_FULLSCREEN; +// ZeroGS::SetChangeDeviceSize(conf.width, conf.height); +// } + + //if( conf.interlace && g_nGenVars + g_nTexVars + g_nAlphaVars + g_nResolve == 0 ) + // CSR->FIELD = 0; // 0 should always be the repeating at 0 + + ZeroGS::RenderCRTC(!interlace); + + if( --nToNextUpdate <= 0 ) { + + u32 d = timeGetTime(); + fFPS = UPDATE_FRAMES * 1000.0f / (float)max(d-dwTime,1); + dwTime = d; + g_nFrame += UPDATE_FRAMES; + +#ifdef RELEASE_TO_PUBLIC + const char* g_pShaders[4] = { "ps 2.0", "ps 2.0a", "ps 2.0b", "ps 3.0" }; + + _snprintf(strtitle, 512, "%s 0.%d.%d %.1f fps | %s%s%s%s %s (%.1f)", libraryName, build, minor, fFPS, + (conf.interlace < 2) ? "interlace | " : "", + conf.bilinear ? (conf.bilinear==2?"forced bilinear | ":"bilinear | ") : "", + conf.aa ? s_aa[conf.aa] : "", + (g_GameSettings&GAME_FFXHACK) ? "ffxhack | " : "", + g_pShaders[g_nPixelShaderVer], (ppf&0xfffff)/(float)UPDATE_FRAMES); +#else + _snprintf(strtitle, 512, "%d | %.1f fps (sk:%d%%) | g: %.1f, t: %.1f, a: %.1f, r: %.1f | p: %.1f | tex: %d %d (%d kbpf)", g_nFrame, fFPS, + 100*g_nFramesSkipped/g_nFrame, + g_nGenVars/(float)UPDATE_FRAMES, g_nTexVars/(float)UPDATE_FRAMES, g_nAlphaVars/(float)UPDATE_FRAMES, + g_nResolve/(float)UPDATE_FRAMES, (ppf&0xfffff)/(float)UPDATE_FRAMES, + ZeroGS::g_MemTargs.listTargets.size(), ZeroGS::g_MemTargs.listClearedTargets.size(), g_TransferredToGPU>>10); + //_snprintf(strtitle, 512, "%x %x", *(int*)(ZeroGS::g_pbyGSMemory + 256 * 0x3e0c + 4), *(int*)(ZeroGS::g_pbyGSMemory + 256 * 0x3e04 + 4)); + +#endif + + if( !(conf.options&GSOPTION_FULLSCREEN) ) + SetWindowText(GShwnd, strtitle); + + if( fFPS < 16 ) UPDATE_FRAMES = 4; + else if( fFPS < 32 ) UPDATE_FRAMES = 8; + else UPDATE_FRAMES = 16; + + nToNextUpdate = UPDATE_FRAMES; + + g_TransferredToGPU = 0; + g_nGenVars = 0; + g_nTexVars = 0; + g_nAlphaVars = 0; + g_nResolve = 0; + ppf = 0; + g_nFramesSkipped = 0; + } +} + +void GIFtag(pathInfo *path, u32 *data) { + + path->tag.nloop = data[0] & 0x7fff; + path->tag.eop = (data[0] >> 15) & 0x1; + u32 tagpre = (data[1] >> 14) & 0x1; + u32 tagprim = (data[1] >> 15) & 0x7ff; + u32 tagflg = (data[1] >> 26) & 0x3; + path->tag.nreg = (data[1] >> 28)<<2; + + if (path->tag.nreg == 0) path->tag.nreg = 64; + + gs.q = 1; + +// GS_LOG("GIFtag: %8.8lx_%8.8lx_%8.8lx_%8.8lx: EOP=%d, NLOOP=%x, FLG=%x, NREG=%d, PRE=%d\n", +// data[3], data[2], data[1], data[0], +// path->tag.eop, path->tag.nloop, tagflg, path->tag.nreg, tagpre); + + path->mode = tagflg+1; + + switch (tagflg) { + case 0x0: + path->regs = *(u64 *)(data+2); + path->regn = 0; + if (tagpre) + GIFRegHandlerPRIM((u32*)&tagprim); + + break; + + case 0x1: + path->regs = *(u64 *)(data+2); + path->regn = 0; + break; + } +} + +void _GSgifPacket(pathInfo *path, u32 *pMem) { // 128bit + + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +void _GSgifRegList(pathInfo *path, u32 *pMem) { // 64bit + int reg; + + reg = (int)((path->regs >> path->regn) & 0xf); + + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +//static pathInfo* s_pLastPath = &gs.path3; +static int nPath3Hack = 0; + +void CALLBACK GSgetLastTag(u64* ptag) +{ + *(u32*)ptag = nPath3Hack; + nPath3Hack = 0; +} + +void _GSgifTransfer(pathInfo *path, u32 *pMem, u32 size) +{ +#ifdef _DEBUG + assert( g_hCurrentThread == GetCurrentThread() ); +#endif + + //s_pLastPath = path; + //BOOL bAfter0Tag = 0; + +// if( conf.log & 0x20 ) { +// __Log("%d: %x:%x\n", (path==&gs.path3)?3:(path==&gs.path2?2:1), pMem, size); +// for(int i = 0; i < size; i++) { +// __Log("%x %x %x %x\n", pMem[4*i+0], pMem[4*i+1], pMem[4*i+2], pMem[4*i+3]); +// } +// } + + while(size > 0) + { + //LOG(_T("Transfer(%08x, %d) START\n"), pMem, size); + if (path->tag.nloop == 0) + { + GIFtag(path, pMem); + pMem+= 4; + size--; + + if ((g_GameSettings & GAME_PATH3HACK) && path == &gs.path3 && gs.path3.tag.eop) + nPath3Hack = 1; + + if (path == &gs.path1) + { + // if too much data, just ignore + if (path->tag.nloop * (path->tag.nreg / 4) > (int)size * (path->mode==2?2:1)) + { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) + { + ERROR_LOG("VU1 too much data, ignore if gfx are fine\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + + if (path->mode == 1) + { + // check if 0xb is in any reg, if yes, exit (kh2) + for(int i = 0; i < path->tag.nreg; i += 4) + { + if (((path->regs >> i)&0xf) == 11) + { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) + { + ERROR_LOG("Invalid unpack type\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + } + } + } + + if(path->tag.nloop == 0 ) + { + if( path == &gs.path1 ) + { + // ffx hack + if( g_GameSettings & GAME_FFXHACK ) + { + if( path->tag.eop ) + return; + continue; + } + + return; + } + + if( !path->tag.eop ) + { + //DEBUG_LOG("continuing from eop\n"); + continue; + } + + break; + } + } + + switch(path->mode) { + case 1: // PACKED + { + assert( path->tag.nloop > 0 ); + for(; size > 0; size--, pMem += 4) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) + { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) + { + size--; + pMem += 4; + break; + } + } + } + break; + } + case 2: // REGLIST + { + //GS_LOG("%8.8x%8.8x %d L\n", ((u32*)&gs.regs)[1], *(u32*)&gs.regs, path->tag.nreg/4); + assert( path->tag.nloop > 0 ); + size *= 2; + for(; size > 0; pMem+= 2, size--) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) + { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) + { + size--; + pMem += 2; + break; + } + } + } + + if( size & 1 ) pMem += 2; + size /= 2; + break; + } + case 3: // GIF_IMAGE (FROM_VFRAM) + case 4: + { + if(gs.imageTransfer >= 0 && gs.imageTransfer <= 1) + { + int process = min((int)size, path->tag.nloop); + + if( process > 0 ) + { + if (gs.imageTransfer) + ZeroGS::TransferLocalHost(pMem, process); + else + ZeroGS::TransferHostLocal(pMem, process*4); + + path->tag.nloop -= process; + pMem += process*4; size -= process; + + assert( size == 0 || path->tag.nloop == 0 ); + } + break; + } + else + { + // simulate + int process = min((int)size, path->tag.nloop); + path->tag.nloop -= process; + pMem += process*4; size -= process; + } + + break; + } + default: // GIF_IMAGE + GS_LOG("*** WARNING **** Unexpected GIFTag flag\n"); + assert(0); + path->tag.nloop = 0; + break; + + } + + if( path == &gs.path1 && path->tag.eop ) + return; + } +} + +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size) +{ + //GS_LOG("GSgifTransfer2 size = %lx (mode %d, gs.path2.tag.nloop = %d)\n", size, gs.path2.mode, gs.path2.tag.nloop); + + _GSgifTransfer(&gs.path2, pMem, size); +} + +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size) +{ + //GS_LOG("GSgifTransfer3 size = %lx (mode %d, gs.path3.tag.nloop = %d)\n", size, gs.path3.mode, gs.path3.tag.nloop); + + nPath3Hack = 0; + _GSgifTransfer(&gs.path3, pMem, size); +} + +static int count = 0; +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr) +{ + pathInfo *path = &gs.path1; + + //GS_LOG("GSgifTransfer1 0x%x (mode %d)\n", addr, path->mode); + + addr &= 0x3fff; + +#ifdef _DEBUG + PRIM_LOG("count: %d\n", count); + count++; +#endif + + gs.path1.tag.nloop = 0; + gs.path1.tag.eop = 0; + _GSgifTransfer(&gs.path1, (u32*)((u8*)pMem+addr), (0x4000-addr)/16); + + if( !gs.path1.tag.eop && gs.path1.tag.nloop > 0 ) { + assert( (addr&0xf) == 0 ); //BUG + gs.path1.tag.nloop = 0; + ERROR_LOG("Transfer1 - 2\n"); + return; + } +} + +void CALLBACK GSreadFIFO(u64 *pMem) +{ + //GS_LOG("GSreadFIFO\n"); + + ZeroGS::TransferLocalHost((u32*)pMem, 1); +} + +void CALLBACK GSreadFIFO2(u64 *pMem, int qwc) +{ + //GS_LOG("GSreadFIFO2\n"); + + ZeroGS::TransferLocalHost((u32*)pMem, qwc); +} + +int CALLBACK GSsetupRecording(int start, void* pData) +{ + if( start ) { + if( conf.options & GSOPTION_CAPTUREAVI ) + return 1; + if( !ZeroGS::StartCapture() ) + return 0; + conf.options |= GSOPTION_CAPTUREAVI; + DEBUG_LOG("ZeroGS: started recording at zerogs.avi\n"); + } + else { + if( !(conf.options & GSOPTION_CAPTUREAVI) ) + return 1; + conf.options &= ~GSOPTION_CAPTUREAVI; + ZeroGS::StopCapture(); + DEBUG_LOG("ZeroGS: stopped recording\n"); + } + + return 1; +} + +s32 CALLBACK GSfreeze(int mode, freezeData *data) +{ + switch (mode) + { + case FREEZE_LOAD: + if (!ZeroGS::Load(data->data)) DEBUG_LOG("GS: Bad load format!"); + g_nRealFrame += 100; + break; + case FREEZE_SAVE: + ZeroGS::Save(data->data); + break; + case FREEZE_SIZE: + data->size = ZeroGS::Save(NULL); + break; + default: + break; + } + + return 0; +} + +extern HINSTANCE hInst; +void CALLBACK GSconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); + + if( g_nPixelShaderVer == SHADER_20 ) + conf.bilinear = 0; +} diff --git a/plugins/zerogs/dx/Mem.cpp b/plugins/zerogs/dx/Mem.cpp new file mode 100644 index 0000000000..4bcc7dcf02 --- /dev/null +++ b/plugins/zerogs/dx/Mem.cpp @@ -0,0 +1,904 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "GS.h" +#include "Mem.h" +#include "zerogs.h" +#include "targets.h" +#include "x86.h" + +u32 g_blockTable32[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable32Z[4][8] = { + { 24, 25, 28, 29, 8, 9, 12, 13}, + { 26, 27, 30, 31, 10, 11, 14, 15}, + { 16, 17, 20, 21, 0, 1, 4, 5}, + { 18, 19, 22, 23, 2, 3, 6, 7} +}; + +u32 g_blockTable16[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_blockTable16S[8][4] = { + { 0, 2, 16, 18 }, + { 1, 3, 17, 19 }, + { 8, 10, 24, 26 }, + { 9, 11, 25, 27 }, + { 4, 6, 20, 22 }, + { 5, 7, 21, 23 }, + { 12, 14, 28, 30 }, + { 13, 15, 29, 31 } +}; + +u32 g_blockTable16Z[8][4] = { + { 24, 26, 16, 18 }, + { 25, 27, 17, 19 }, + { 28, 30, 20, 22 }, + { 29, 31, 21, 23 }, + { 8, 10, 0, 2 }, + { 9, 11, 1, 3 }, + { 12, 14, 4, 6 }, + { 13, 15, 5, 7 } +}; + +u32 g_blockTable16SZ[8][4] = { + { 24, 26, 8, 10 }, + { 25, 27, 9, 11 }, + { 16, 18, 0, 2 }, + { 17, 19, 1, 3 }, + { 28, 30, 12, 14 }, + { 29, 31, 13, 15 }, + { 20, 22, 4, 6 }, + { 21, 23, 5, 7 } +}; + +u32 g_blockTable8[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable4[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_columnTable32[8][8] = { + { 0, 1, 4, 5, 8, 9, 12, 13 }, + { 2, 3, 6, 7, 10, 11, 14, 15 }, + { 16, 17, 20, 21, 24, 25, 28, 29 }, + { 18, 19, 22, 23, 26, 27, 30, 31 }, + { 32, 33, 36, 37, 40, 41, 44, 45 }, + { 34, 35, 38, 39, 42, 43, 46, 47 }, + { 48, 49, 52, 53, 56, 57, 60, 61 }, + { 50, 51, 54, 55, 58, 59, 62, 63 }, +}; + +u32 g_columnTable16[8][16] = { + { 0, 2, 8, 10, 16, 18, 24, 26, + 1, 3, 9, 11, 17, 19, 25, 27 }, + { 4, 6, 12, 14, 20, 22, 28, 30, + 5, 7, 13, 15, 21, 23, 29, 31 }, + { 32, 34, 40, 42, 48, 50, 56, 58, + 33, 35, 41, 43, 49, 51, 57, 59 }, + { 36, 38, 44, 46, 52, 54, 60, 62, + 37, 39, 45, 47, 53, 55, 61, 63 }, + { 64, 66, 72, 74, 80, 82, 88, 90, + 65, 67, 73, 75, 81, 83, 89, 91 }, + { 68, 70, 76, 78, 84, 86, 92, 94, + 69, 71, 77, 79, 85, 87, 93, 95 }, + { 96, 98, 104, 106, 112, 114, 120, 122, + 97, 99, 105, 107, 113, 115, 121, 123 }, + { 100, 102, 108, 110, 116, 118, 124, 126, + 101, 103, 109, 111, 117, 119, 125, 127 }, +}; + +u32 g_columnTable8[16][16] = { + { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 + 2, 6, 18, 22, 34, 38, 50, 54 }, + { 8, 12, 24, 28, 40, 44, 56, 60, + 10, 14, 26, 30, 42, 46, 58, 62 }, + { 33, 37, 49, 53, 1, 5, 17, 21, + 35, 39, 51, 55, 3, 7, 19, 23 }, + { 41, 45, 57, 61, 9, 13, 25, 29, + 43, 47, 59, 63, 11, 15, 27, 31 }, + { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 + 98, 102, 114, 118, 66, 70, 82, 86 }, + { 104, 108, 120, 124, 72, 76, 88, 92, + 106, 110, 122, 126, 74, 78, 90, 94 }, + { 65, 69, 81, 85, 97, 101, 113, 117, + 67, 71, 83, 87, 99, 103, 115, 119 }, + { 73, 77, 89, 93, 105, 109, 121, 125, + 75, 79, 91, 95, 107, 111, 123, 127 }, + { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 + 130, 134, 146, 150, 162, 166, 178, 182 }, + { 136, 140, 152, 156, 168, 172, 184, 188, + 138, 142, 154, 158, 170, 174, 186, 190 }, + { 161, 165, 177, 181, 129, 133, 145, 149, + 163, 167, 179, 183, 131, 135, 147, 151 }, + { 169, 173, 185, 189, 137, 141, 153, 157, + 171, 175, 187, 191, 139, 143, 155, 159 }, + { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 + 226, 230, 242, 246, 194, 198, 210, 214 }, + { 232, 236, 248, 252, 200, 204, 216, 220, + 234, 238, 250, 254, 202, 206, 218, 222 }, + { 193, 197, 209, 213, 225, 229, 241, 245, + 195, 199, 211, 215, 227, 231, 243, 247 }, + { 201, 205, 217, 221, 233, 237, 249, 253, + 203, 207, 219, 223, 235, 239, 251, 255 }, +}; + +u32 g_columnTable4[16][32] = { + { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 + 2, 10, 34, 42, 66, 74, 98, 106, + 4, 12, 36, 44, 68, 76, 100, 108, + 6, 14, 38, 46, 70, 78, 102, 110 }, + { 16, 24, 48, 56, 80, 88, 112, 120, + 18, 26, 50, 58, 82, 90, 114, 122, + 20, 28, 52, 60, 84, 92, 116, 124, + 22, 30, 54, 62, 86, 94, 118, 126 }, + { 65, 73, 97, 105, 1, 9, 33, 41, + 67, 75, 99, 107, 3, 11, 35, 43, + 69, 77, 101, 109, 5, 13, 37, 45, + 71, 79, 103, 111, 7, 15, 39, 47 }, + { 81, 89, 113, 121, 17, 25, 49, 57, + 83, 91, 115, 123, 19, 27, 51, 59, + 85, 93, 117, 125, 21, 29, 53, 61, + 87, 95, 119, 127, 23, 31, 55, 63 }, + { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 + 194, 202, 226, 234, 130, 138, 162, 170, + 196, 204, 228, 236, 132, 140, 164, 172, + 198, 206, 230, 238, 134, 142, 166, 174 }, + { 208, 216, 240, 248, 144, 152, 176, 184, + 210, 218, 242, 250, 146, 154, 178, 186, + 212, 220, 244, 252, 148, 156, 180, 188, + 214, 222, 246, 254, 150, 158, 182, 190 }, + { 129, 137, 161, 169, 193, 201, 225, 233, + 131, 139, 163, 171, 195, 203, 227, 235, + 133, 141, 165, 173, 197, 205, 229, 237, + 135, 143, 167, 175, 199, 207, 231, 239 }, + { 145, 153, 177, 185, 209, 217, 241, 249, + 147, 155, 179, 187, 211, 219, 243, 251, + 149, 157, 181, 189, 213, 221, 245, 253, + 151, 159, 183, 191, 215, 223, 247, 255 }, + { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 + 258, 266, 290, 298, 322, 330, 354, 362, + 260, 268, 292, 300, 324, 332, 356, 364, + 262, 270, 294, 302, 326, 334, 358, 366 }, + { 272, 280, 304, 312, 336, 344, 368, 376, + 274, 282, 306, 314, 338, 346, 370, 378, + 276, 284, 308, 316, 340, 348, 372, 380, + 278, 286, 310, 318, 342, 350, 374, 382 }, + { 321, 329, 353, 361, 257, 265, 289, 297, + 323, 331, 355, 363, 259, 267, 291, 299, + 325, 333, 357, 365, 261, 269, 293, 301, + 327, 335, 359, 367, 263, 271, 295, 303 }, + { 337, 345, 369, 377, 273, 281, 305, 313, + 339, 347, 371, 379, 275, 283, 307, 315, + 341, 349, 373, 381, 277, 285, 309, 317, + 343, 351, 375, 383, 279, 287, 311, 319 }, + { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 + 450, 458, 482, 490, 386, 394, 418, 426, + 452, 460, 484, 492, 388, 396, 420, 428, + 454, 462, 486, 494, 390, 398, 422, 430 }, + { 464, 472, 496, 504, 400, 408, 432, 440, + 466, 474, 498, 506, 402, 410, 434, 442, + 468, 476, 500, 508, 404, 412, 436, 444, + 470, 478, 502, 510, 406, 414, 438, 446 }, + { 385, 393, 417, 425, 449, 457, 481, 489, + 387, 395, 419, 427, 451, 459, 483, 491, + 389, 397, 421, 429, 453, 461, 485, 493, + 391, 399, 423, 431, 455, 463, 487, 495 }, + { 401, 409, 433, 441, 465, 473, 497, 505, + 403, 411, 435, 443, 467, 475, 499, 507, + 405, 413, 437, 445, 469, 477, 501, 509, + 407, 415, 439, 447, 471, 479, 503, 511 }, +}; + +u32 g_pageTable32[32][64]; +u32 g_pageTable32Z[32][64]; +u32 g_pageTable16[64][64]; +u32 g_pageTable16S[64][64]; +u32 g_pageTable16Z[64][64]; +u32 g_pageTable16SZ[64][64]; +u32 g_pageTable8[64][128]; +u32 g_pageTable4[128][128]; + +BLOCK m_Blocks[0x40]; // do so blocks are indexable +static PCSX2_ALIGNED16(u32 tempblock[64]); + +#define DSTPSM gs.dstbuf.psm + +#define START_HOSTLOCAL() \ + assert( gs.imageTransfer == 0 ); \ + u8* pstart = ZeroGS::g_pbyGSMemory + gs.dstbuf.bp*256; \ + \ + const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; \ + int i = gs.imageY, j = gs.imageX; \ + +extern BOOL g_bSaveTrans; + +#define END_HOSTLOCAL() \ +End: \ + if( i >= gs.imageEndY ) { \ + assert( gs.imageTransfer == -1 || i == gs.imageEndY ); \ + gs.imageTransfer = -1; \ + /*int start, end; \ + ZeroGS::GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); \ + ZeroGS::g_MemTargs.ClearRange(start, end);*/ \ + } \ + else { \ + /* update new params */ \ + gs.imageY = i; \ + gs.imageX = j; \ + } \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_(psm, T, widthlimit, endY) { \ + assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 1) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + } \ + } \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ + /* write as many pixel at one time as possible */ \ + if( nSize < widthlimit ) goto End; \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize*sizeof(T)/4 == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + pbuf += pitch-fracX; \ + } \ +} \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_24(psm, T, widthlimit, endY) { \ + if( widthlimit != 8 || ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize == 0 ); goto End; } \ + } \ + } \ + else { \ + assert( /*(nSize%widthlimit) == 0 &&*/ widthlimit == 8 ); \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += 3*widthlimit) { \ + if( nSize < widthlimit ) goto End; \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf+0), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *(u32*)(pbuf+3), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *(u32*)(pbuf+6), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *(u32*)(pbuf+9), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *(u32*)(pbuf+12), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *(u32*)(pbuf+15), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *(u32*)(pbuf+18), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *(u32*)(pbuf+21), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { \ + if( nSize < 0 ) { \ + /* extracted too much */ \ + assert( (nSize%3)==0 && nSize > -24 ); \ + j += nSize/3; \ + nSize = 0; \ + } \ + assert( gs.imageTransfer == -1 || nSize == 0 ); \ + goto End; \ + } \ + } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_24(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, *(u32*)pbuf, gs.dstbuf.bw); \ + } \ + pbuf += 3*(pitch-fracX); \ + } \ +} \ + +// meant for 4bit transfers +#define TRANSMIT_HOSTLOCAL_Y_4(psm, T, widthlimit, endY) { \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 4 ) { \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 6 ) { \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || (nSize/32) == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_4(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j+=2, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0]&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, (i+tempi)%2048, pbuf[0]>>4, gs.dstbuf.bw); \ + } \ + pbuf += (pitch-fracX)/2; \ + } \ +} \ + +// calculate pitch in source buffer +#define TRANSMIT_PITCH_(pitch, T) (pitch*sizeof(T)) +#define TRANSMIT_PITCH_24(pitch, T) (pitch*3) +#define TRANSMIT_PITCH_4(pitch, T) (pitch/2) + +// special swizzle macros +#define SwizzleBlock24(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 7; ++by, pblock += 8, pnewsrc += pitch-24) { \ + for(int bx = 0; bx < 8; ++bx, pnewsrc += 3) { \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + } \ + for(int bx = 0; bx < 7; ++bx, pnewsrc += 3) { \ + /* might be 1 byte out of bounds of GS memory */ \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + /* do 3 bytes for the last copy */ \ + *((u8*)pblock+28) = pnewsrc[0]; \ + *((u8*)pblock+29) = pnewsrc[1]; \ + *((u8*)pblock+30) = pnewsrc[2]; \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x00ffffff); \ +} \ + +#define SwizzleBlock24u SwizzleBlock24 + +#define SwizzleBlock8H(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<16; \ + pblock[2] = u<<8; \ + pblock[3] = u; \ + u = *(u32*)(pnewsrc+4); \ + pblock[4] = u<<24; \ + pblock[5] = u<<16; \ + pblock[6] = u<<8; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xff000000); \ +} \ + +#define SwizzleBlock8Hu SwizzleBlock8H + +#define SwizzleBlock4HH(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<28; \ + pblock[1] = u<<24; \ + pblock[2] = u<<20; \ + pblock[3] = u<<16; \ + pblock[4] = u<<12; \ + pblock[5] = u<<8; \ + pblock[6] = u<<4; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xf0000000); \ +} \ + +#define SwizzleBlock4HHu SwizzleBlock4HH + +#define SwizzleBlock4HL(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<20; \ + pblock[2] = u<<16; \ + pblock[3] = u<<12; \ + pblock[4] = u<<8; \ + pblock[5] = u<<4; \ + pblock[6] = u; \ + pblock[7] = u>>4; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x0f000000); \ +} \ + +#define SwizzleBlock4HLu SwizzleBlock4HL + +// ------------------------ +// | Y | +// ------------------------ +// | block | | +// | aligned area | X | +// | | | +// ------------------------ +// | Y | +// ------------------------ +#define DEFINE_TRANSFERLOCAL(psm, T, widthlimit, blockbits, blockwidth, blockheight, TransSfx, SwizzleBlock) \ +int TransferHostLocal##psm(const void* pbyMem, u32 nQWordSize) \ +{ \ + START_HOSTLOCAL(); \ + \ + const T* pbuf = (const T*)pbyMem; \ + int nLeftOver = (nQWordSize*4*2)%(TRANSMIT_PITCH##TransSfx(2, T)); \ + int nSize = nQWordSize*4*2/TRANSMIT_PITCH##TransSfx(2, T); \ + nSize = min(nSize, gs.imageWnew * gs.imageHnew); \ + \ + int pitch, area, fracX; \ + int endY = ROUND_UPPOW2(i, blockheight); \ + int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); \ + int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); \ + bool bAligned, bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; \ + \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /* hack */ \ + int testwidth = (int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx); \ + if ((testwidth <= widthlimit) && (testwidth >= -widthlimit)) { \ + /* Don't transfer */ \ + /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ \ + gs.imageTransfer = -1; \ + } \ + bCanAlign = false; \ + } \ + \ + /* first align on block boundary */ \ + if( MOD_POW2(i, blockheight) || !bCanAlign ) { \ + \ + if( !bCanAlign ) \ + endY = gs.imageEndY; /* transfer the whole image */ \ + else \ + assert( endY < gs.imageEndY); /* part of alignment condition */ \ + \ + if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) || ((gs.imageEndX-j)%widthlimit) ) { \ + /* transmit with a width of 1 */ \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, (1+(DSTPSM == 0x14)), endY); \ + } \ + else { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, endY); \ + } \ + \ + if( nSize == 0 || i == gs.imageEndY ) \ + goto End; \ + } \ + \ + assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); \ + \ + /* can align! */ \ + pitch = gs.imageEndX-gs.trxpos.dx; \ + area = pitch*blockheight; \ + fracX = gs.imageEndX-alignedX; \ + \ + /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ \ + bAligned = !((uptr)pbuf & 0xf) && (TRANSMIT_PITCH##TransSfx(pitch, T)&0xf) == 0; \ + \ + /* transfer aligning to blocks */ \ + for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { \ + \ + if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + else { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock##u(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + \ + /* transfer the rest */ \ + if( alignedX < gs.imageEndX ) { \ + TRANSMIT_HOSTLOCAL_X##TransSfx(psm, T, widthlimit, blockheight, alignedX); \ + pbuf -= TRANSMIT_PITCH##TransSfx((alignedX-gs.trxpos.dx), T)/sizeof(T); \ + } \ + else pbuf += (blockheight-1)*TRANSMIT_PITCH##TransSfx(pitch, T)/sizeof(T); \ + j = gs.trxpos.dx; \ + } \ + \ + if( TRANSMIT_PITCH##TransSfx(nSize, T)/4 > 0 ) { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, gs.imageEndY); \ + /* sometimes wrong sizes are sent (tekken tag) */ \ + assert( gs.imageTransfer == -1 || TRANSMIT_PITCH##TransSfx(nSize,T)/4 <= 2 ); \ + } \ + \ + END_HOSTLOCAL(); \ + return (nSize * TRANSMIT_PITCH##TransSfx(2, T) + nLeftOver)/2; \ +} \ + +DEFINE_TRANSFERLOCAL(32, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(32Z, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(24, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(24Z, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(16, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16S, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16Z, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16SZ, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(8, u8, 4, 8, 16, 16, _, SwizzleBlock8); +DEFINE_TRANSFERLOCAL(4, u8, 8, 4, 32, 16, _4, SwizzleBlock4); +DEFINE_TRANSFERLOCAL(8H, u8, 4, 32, 8, 8, _, SwizzleBlock8H); +DEFINE_TRANSFERLOCAL(4HL, u8, 8, 32, 8, 8, _4, SwizzleBlock4HL); +DEFINE_TRANSFERLOCAL(4HH, u8, 8, 32, 8, 8, _4, SwizzleBlock4HH); + +//#define T u8 +//#define widthlimit 8 +//#define blockbits 4 +//#define blockwidth 32 +//#define blockheight 16 +// +//void TransferHostLocal4(const void* pbyMem, u32 nQWordSize) +//{ +// START_HOSTLOCAL(); +// +// const T* pbuf = (const T*)pbyMem; +// u32 nSize = nQWordSize*16*2/TRANSMIT_PITCH_4(2, T); +// nSize = min(nSize, gs.imageWnew * gs.imageHnew); +// +// int endY = ROUND_UPPOW2(i, blockheight); +// int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); +// int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); +// bool bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; +// +// if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { +// /* hack */ +// if( abs((int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= widthlimit ) { +// /* don't transfer */ +// /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ +// gs.imageTransfer = -1; +// } +// bCanAlign = false; +// } +// +// /* first align on block boundary */ +// if( MOD_POW2(i, blockheight) || !bCanAlign ) { +// +// if( !bCanAlign ) +// endY = gs.imageEndY; /* transfer the whole image */ +// else +// assert( endY < gs.imageEndY); /* part of alignment condition */ +// +// if( (DSTPSM == 0x13 || DSTPSM == 0x14) && ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { +// /* transmit with a width of 1 */ +// TRANSMIT_HOSTLOCAL_Y_4(4, T, (1+(DSTPSM == 0x14)), endY); +// } +// else { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, endY); +// } +// +// if( nSize == 0 || i == gs.imageEndY ) +// goto End; +// } +// +// assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); +// +// /* can align! */ +// int pitch = gs.imageEndX-gs.trxpos.dx; +// u32 area = pitch*blockheight; +// int fracX = gs.imageEndX-alignedX; +// +// /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ +// bool bAligned = !((u32)pbuf & 0xf) && (TRANSMIT_PITCH_4(pitch, T)&0xf) == 0; +// +// /* transfer aligning to blocks */ +// for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { +// +// if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// else { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4u(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// +// /* transfer the rest */ +// if( alignedX < gs.imageEndX ) { +// TRANSMIT_HOSTLOCAL_X_4(4, T, widthlimit, blockheight, alignedX); +// pbuf -= TRANSMIT_PITCH_4((alignedX-gs.trxpos.dx), T)/sizeof(T); +// } +// else pbuf += (blockheight-1)*TRANSMIT_PITCH_4(pitch, T)/sizeof(T); +// j = 0; +// } +// +// if( TRANSMIT_PITCH_4(nSize, T)/4 > 0 ) { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, gs.imageEndY); +// /* sometimes wrong sizes are sent (tekken tag) */ +// assert( gs.imageTransfer == -1 || TRANSMIT_PITCH_4(nSize,T)/4 <= 2 ); +// } +// +// END_HOSTLOCAL(); +//} + +void TransferLocalHost32(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16S(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8H(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HL(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HH(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost32Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16SZ(void* pbyMem, u32 nQWordSize) +{ +} + +#define FILL_BLOCK(bw, bh, ox, oy, mult, psm, psmcol) { \ + b.vTexDims = D3DXVECTOR2(BLOCK_TEXWIDTH/(float)(bw), BLOCK_TEXHEIGHT/(float)bh); \ + b.vTexBlock = D3DXVECTOR4((float)bw/BLOCK_TEXWIDTH, (float)bh/BLOCK_TEXHEIGHT, ((float)ox+0.2f)/BLOCK_TEXWIDTH, ((float)oy+0.05f)/BLOCK_TEXHEIGHT); \ + b.width = bw; \ + b.height = bh; \ + b.colwidth = bh / 4; \ + b.colheight = bw / 8; \ + b.bpp = 32/mult; \ + \ + b.pageTable = &g_pageTable##psm[0][0]; \ + b.blockTable = &g_blockTable##psm[0][0]; \ + b.columnTable = &g_columnTable##psmcol[0][0]; \ + assert( sizeof(g_pageTable##psm) == bw*bh*sizeof(g_pageTable##psm[0][0]) ); \ + psrcf = (float*)pBlockTexture->pBits + ox + oy * pBlockTexture->Pitch/sizeof(float); \ + psrcw = (WORD*)pBlockTexture->pBits + ox + oy * pBlockTexture->Pitch/sizeof(WORD); \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + /* fill the table */ \ + u32 u = g_blockTable##psm[(i / b.colheight)][(j / b.colwidth)] * 64 * mult + g_columnTable##psmcol[i%b.colheight][j%b.colwidth]; \ + b.pageTable[i*bw+j] = u; \ + if( format == D3DFMT_R32F ) { \ + psrcf[i*pBlockTexture->Pitch/sizeof(float)+j] = (float)(u) / (float)(GPU_TEXWIDTH*mult); \ + } \ + else { \ + psrcw[i*pBlockTexture->Pitch/sizeof(WORD)+j] = u; \ + } \ + } \ + } \ + \ + if( pBilinearTexture != NULL ) { \ + assert( format == D3DFMT_R32F ); \ + psrcv = (DXVEC4*)pBilinearTexture->pBits + ox + oy * pBilinearTexture->Pitch/sizeof(DXVEC4); \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + DXVEC4* pv = &psrcv[i*pBilinearTexture->Pitch/sizeof(DXVEC4)+j]; \ + pv->x = psrcf[i*pBlockTexture->Pitch/sizeof(float)+j]; \ + pv->y = psrcf[i*pBlockTexture->Pitch/sizeof(float)+((j+1)%bw)]; \ + pv->z = psrcf[((i+1)%bh)*pBlockTexture->Pitch/sizeof(float)+j]; \ + pv->w = psrcf[((i+1)%bh)*pBlockTexture->Pitch/sizeof(float)+((j+1)%bw)]; \ + } \ + } \ + } \ + b.getPixelAddress = getPixelAddress##psm; \ + b.getPixelAddress_0 = getPixelAddress##psm##_0; \ + b.writePixel = writePixel##psm; \ + b.writePixel_0 = writePixel##psm##_0; \ + b.readPixel = readPixel##psm; \ + b.readPixel_0 = readPixel##psm##_0; \ + b.TransferHostLocal = TransferHostLocal##psm; \ + b.TransferLocalHost = TransferLocalHost##psm; \ +} \ + +void BLOCK::FillBlocks(const D3DLOCKED_RECT* pBlockTexture, const D3DLOCKED_RECT* pBilinearTexture, D3DFORMAT format) +{ + assert( pBlockTexture != NULL ); + assert( format == D3DFMT_R32F || format == D3DFMT_G16R16 ); + + int i, j; + BLOCK b; + float* psrcf = NULL; + WORD* psrcw = NULL; + DXVEC4* psrcv = NULL; + + memset(m_Blocks, 0, sizeof(m_Blocks)); + + // 32 + FILL_BLOCK(64, 32, 0, 0, 1, 32, 32); + m_Blocks[PSMCT32] = b; + + // 24 (same as 32 except write/readPixel are different) + m_Blocks[PSMCT24] = b; + m_Blocks[PSMCT24].writePixel = writePixel24; + m_Blocks[PSMCT24].writePixel_0 = writePixel24_0; + m_Blocks[PSMCT24].readPixel = readPixel24; + m_Blocks[PSMCT24].readPixel_0 = readPixel24_0; + m_Blocks[PSMCT24].TransferHostLocal = TransferHostLocal24; + m_Blocks[PSMCT24].TransferLocalHost = TransferLocalHost24; + + // 8H (same as 32 except write/readPixel are different) + m_Blocks[PSMT8H] = b; + m_Blocks[PSMT8H].writePixel = writePixel8H; + m_Blocks[PSMT8H].writePixel_0 = writePixel8H_0; + m_Blocks[PSMT8H].readPixel = readPixel8H; + m_Blocks[PSMT8H].readPixel_0 = readPixel8H_0; + m_Blocks[PSMT8H].TransferHostLocal = TransferHostLocal8H; + m_Blocks[PSMT8H].TransferLocalHost = TransferLocalHost8H; + + m_Blocks[PSMT4HL] = b; + m_Blocks[PSMT4HL].writePixel = writePixel4HL; + m_Blocks[PSMT4HL].writePixel_0 = writePixel4HL_0; + m_Blocks[PSMT4HL].readPixel = readPixel4HL; + m_Blocks[PSMT4HL].readPixel_0 = readPixel4HL_0; + m_Blocks[PSMT4HL].TransferHostLocal = TransferHostLocal4HL; + m_Blocks[PSMT4HL].TransferLocalHost = TransferLocalHost4HL; + + m_Blocks[PSMT4HH] = b; + m_Blocks[PSMT4HH].writePixel = writePixel4HH; + m_Blocks[PSMT4HH].writePixel_0 = writePixel4HH_0; + m_Blocks[PSMT4HH].readPixel = readPixel4HH; + m_Blocks[PSMT4HH].readPixel_0 = readPixel4HH_0; + m_Blocks[PSMT4HH].TransferHostLocal = TransferHostLocal4HH; + m_Blocks[PSMT4HH].TransferLocalHost = TransferLocalHost4HH; + + // 32z + FILL_BLOCK(64, 32, 64, 0, 1, 32Z, 32); + m_Blocks[PSMT32Z] = b; + + // 24Z (same as 32Z except write/readPixel are different) + m_Blocks[PSMT24Z] = b; + m_Blocks[PSMT24Z].writePixel = writePixel24Z; + m_Blocks[PSMT24Z].writePixel_0 = writePixel24Z_0; + m_Blocks[PSMT24Z].readPixel = readPixel24Z; + m_Blocks[PSMT24Z].readPixel_0 = readPixel24Z_0; + m_Blocks[PSMT24Z].TransferHostLocal = TransferHostLocal24Z; + m_Blocks[PSMT24Z].TransferLocalHost = TransferLocalHost24Z; + + // 16 + FILL_BLOCK(64, 64, 0, 32, 2, 16, 16); + m_Blocks[PSMCT16] = b; + + // 16s + FILL_BLOCK(64, 64, 64, 32, 2, 16S, 16); + m_Blocks[PSMCT16S] = b; + + // 16z + FILL_BLOCK(64, 64, 0, 96, 2, 16Z, 16); + m_Blocks[PSMT16Z] = b; + + // 16sz + FILL_BLOCK(64, 64, 64, 96, 2, 16SZ, 16); + m_Blocks[PSMT16SZ] = b; + + // 8 + FILL_BLOCK(128, 64, 0, 160, 4, 8, 8); + m_Blocks[PSMT8] = b; + + // 4 + FILL_BLOCK(128, 128, 0, 224, 8, 4, 4); + m_Blocks[PSMT4] = b; +} diff --git a/plugins/zerogs/dx/Mem.h b/plugins/zerogs/dx/Mem.h new file mode 100644 index 0000000000..5d3e89ec8e --- /dev/null +++ b/plugins/zerogs/dx/Mem.h @@ -0,0 +1,486 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __MEM_H__ +#define __MEM_H__ + +#include + +// works only when base is a power of 2 +#define ROUND_UPPOW2(val, base) (((val)+(base-1))&~(base-1)) +#define ROUND_DOWNPOW2(val, base) ((val)&~(base-1)) +#define MOD_POW2(val, base) ((val)&(base-1)) + +// d3d texture dims +#define BLOCK_TEXWIDTH 128 +#define BLOCK_TEXHEIGHT 512 + +// rest not visible externally +struct BLOCK +{ + BLOCK() { memset(this, 0, sizeof(BLOCK)); } + + // shader constants for this block + D3DXVECTOR4 vTexBlock; + D3DXVECTOR2 vTexDims; + int width, height; // dims of one page in pixels + int bpp; + int colwidth, colheight; + u32* pageTable; // offset inside each page + u32* blockTable; + u32* columnTable; + + u32 (*getPixelAddress)(int x, int y, u32 bp, u32 bw); + u32 (*getPixelAddress_0)(int x, int y, u32 bw); + void (*writePixel)(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw); + void (*writePixel_0)(void* pmem, int x, int y, u32 pixel, u32 bw); + u32 (*readPixel)(const void* pmem, int x, int y, u32 bp, u32 bw); + u32 (*readPixel_0)(const void* pmem, int x, int y, u32 bw); + int (*TransferHostLocal)(const void* pbyMem, u32 nQWordSize); + void (*TransferLocalHost)(void* pbyMem, u32 nQWordSize); + + // texture must be of dims BLOCK_TEXWIDTH and BLOCK_TEXHEIGHT + static void FillBlocks(const D3DLOCKED_RECT* pBlockTexture, const D3DLOCKED_RECT* pBilinearTexture, D3DFORMAT format); +}; + +extern BLOCK m_Blocks[]; + +extern u32 g_blockTable32[4][8]; +extern u32 g_blockTable32Z[4][8]; +extern u32 g_blockTable16[8][4]; +extern u32 g_blockTable16S[8][4]; +extern u32 g_blockTable16Z[8][4]; +extern u32 g_blockTable16SZ[8][4]; +extern u32 g_blockTable8[4][8]; +extern u32 g_blockTable4[8][4]; + +extern u32 g_columnTable32[8][8]; +extern u32 g_columnTable16[8][16]; +extern u32 g_columnTable8[16][16]; +extern u32 g_columnTable4[16][32]; + +extern u32 g_pageTable32[32][64]; +extern u32 g_pageTable32Z[32][64]; +extern u32 g_pageTable16[64][64]; +extern u32 g_pageTable16S[64][64]; +extern u32 g_pageTable16Z[64][64]; +extern u32 g_pageTable16SZ[64][64]; +extern u32 g_pageTable8[64][128]; +extern u32 g_pageTable4[128][128]; + +static __forceinline u32 getPixelAddress32(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +static __forceinline u32 getPixelAddress32_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24 getPixelAddress32 +#define getPixelAddress24_0 getPixelAddress32_0 +#define getPixelAddress8H getPixelAddress32 +#define getPixelAddress8H_0 getPixelAddress32_0 +#define getPixelAddress4HL getPixelAddress32 +#define getPixelAddress4HL_0 getPixelAddress32_0 +#define getPixelAddress4HH getPixelAddress32 +#define getPixelAddress4HH_0 getPixelAddress32_0 + +static __forceinline u32 getPixelAddress16(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16S(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16S_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress8(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 256 + basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +static __forceinline u32 getPixelAddress8_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +static __forceinline u32 getPixelAddress4(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 512 + basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +static __forceinline u32 getPixelAddress4_0(int x, int y, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +static __forceinline u32 getPixelAddress32Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +static __forceinline u32 getPixelAddress32Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24Z getPixelAddress32Z +#define getPixelAddress24Z_0 getPixelAddress32Z_0 + +static __forceinline u32 getPixelAddress16Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16SZ(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16SZ_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline void writePixel32(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel24(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +static __forceinline void writePixel16(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel16S(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16S(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel8(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[getPixelAddress8(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel8H(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32(x, y, bp, bw)+3] = pixel; +} + +static __forceinline void writePixel4(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +static __forceinline void writePixel4HL(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL(x, y, bp, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +static __forceinline void writePixel4HH(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH(x, y, bp, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +static __forceinline void writePixel32Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel24Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z(x, y, bp, bw); + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +static __forceinline void writePixel16Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel16SZ(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)] = pixel; +} + + +/////////////// + +static __forceinline u32 readPixel32(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel24(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel16S(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel8(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel8H(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32(x, y, bp, bw) + 3]; +} + +static __forceinline u32 readPixel4(const void* pmem, int x, int y, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +static __forceinline u32 readPixel4HL(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL(x, y, bp, bw)+3; + return *p & 0x0f; +} + +static __forceinline u32 readPixel4HH(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH(x, y, bp, bw) + 3; + return *p >> 4; +} + +/////////////// + +static __forceinline u32 readPixel32Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel24Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel16SZ(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)]; +} + +/////////////////////////////// +// Functions that take 0 bps // +/////////////////////////////// + +static __forceinline void writePixel32_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel24_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32_0(x, y, bw)]; + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +static __forceinline void writePixel16_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel16S_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16S_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel8_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[getPixelAddress8_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel8H_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32_0(x, y, bw)+3] = pixel; +} + +static __forceinline void writePixel4_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +static __forceinline void writePixel4HL_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL_0(x, y, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +static __forceinline void writePixel4HH_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH_0(x, y, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +static __forceinline void writePixel32Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel24Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z_0(x, y, bw); + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +static __forceinline void writePixel16Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel16SZ_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)] = pixel; +} + + +/////////////// + +static __forceinline u32 readPixel32_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)]; +} + +static __forceinline u32 readPixel24_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16_0(x, y, bw)]; +} + +static __forceinline u32 readPixel16S_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S_0(x, y, bw)]; +} + +static __forceinline u32 readPixel8_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8_0(x, y, bw)]; +} + +static __forceinline u32 readPixel8H_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32_0(x, y, bw) + 3]; +} + +static __forceinline u32 readPixel4_0(const void* pmem, int x, int y, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +static __forceinline u32 readPixel4HL_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL_0(x, y, bw)+3; + return *p & 0x0f; +} + +static __forceinline u32 readPixel4HH_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH_0(x, y, bw) + 3; + return *p >> 4; +} + +/////////////// + +static __forceinline u32 readPixel32Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)]; +} + +static __forceinline u32 readPixel24Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z_0(x, y, bw)]; +} + +static __forceinline u32 readPixel16SZ_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)]; +} + +#endif /* __MEM_H__ */ diff --git a/plugins/zerogs/dx/README.txt b/plugins/zerogs/dx/README.txt new file mode 100644 index 0000000000..e54d8a1b31 --- /dev/null +++ b/plugins/zerogs/dx/README.txt @@ -0,0 +1,13 @@ +ZeroGS DirectX +-------------- +author: zerofrog (@gmail.com) + +ZeroGS heavily uses GPU shaders. All the shaders are written in Microsoft's HLSL language and can be found in ps2hw.fx, ps2hw_ctx0.fx and ps2hw_ctx1.fx. + +'Dev' versions of ZeroGS directly read ps2hw.fx +'Release' versions of ZeroGS read a precompiled version of ps2hw.fx from ps2hw.dat. In order to build ps2hw.dat, compile ZeroGSShaders and execute: + +./ZeroGSShaders ps2hw.fx ps2hw.dat + +For Windows users, once ZeroGSShaders is built, run buildshaders.bat directly. It will update all necessary resource files. +Note that ZeroGSShaders has only been tested in Windows so far, but the Windows ps2hw.dat can be used in linux builds. diff --git a/plugins/zerogs/dx/Regs.cpp b/plugins/zerogs/dx/Regs.cpp new file mode 100644 index 0000000000..6515389b05 --- /dev/null +++ b/plugins/zerogs/dx/Regs.cpp @@ -0,0 +1,1116 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +GIFRegHandler g_GIFPackedRegHandlers[16] = { + GIFRegHandlerPRIM, GIFPackedRegHandlerRGBA, GIFPackedRegHandlerSTQ, GIFPackedRegHandlerUV, + GIFPackedRegHandlerXYZF2, GIFPackedRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFPackedRegHandlerFOG, GIFPackedRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFPackedRegHandlerA_D, GIFPackedRegHandlerNOP }; + +GIFRegHandler g_GIFRegHandlers[] = { + GIFRegHandlerPRIM, GIFRegHandlerRGBAQ, GIFRegHandlerST, GIFRegHandlerUV, + GIFRegHandlerXYZF2, GIFRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFRegHandlerFOG, GIFRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFRegHandlerNOP, GIFRegHandlerNOP, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerTEX1_1, GIFRegHandlerTEX1_2, GIFRegHandlerTEX2_1, GIFRegHandlerTEX2_2, + GIFRegHandlerXYOFFSET_1,GIFRegHandlerXYOFFSET_2,GIFRegHandlerPRMODECONT,GIFRegHandlerPRMODE, + GIFRegHandlerTEXCLUT, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerSCANMSK, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerMIPTBP1_1, GIFRegHandlerMIPTBP1_2, GIFRegHandlerMIPTBP2_1, GIFRegHandlerMIPTBP2_2, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerTEXA, + GIFRegHandlerNull, GIFRegHandlerFOGCOL, GIFRegHandlerNull, GIFRegHandlerTEXFLUSH, + GIFRegHandlerSCISSOR_1, GIFRegHandlerSCISSOR_2, GIFRegHandlerALPHA_1, GIFRegHandlerALPHA_2, + GIFRegHandlerDIMX, GIFRegHandlerDTHE, GIFRegHandlerCOLCLAMP, GIFRegHandlerTEST_1, + GIFRegHandlerTEST_2, GIFRegHandlerPABE, GIFRegHandlerFBA_1, GIFRegHandlerFBA_2, + GIFRegHandlerFRAME_1, GIFRegHandlerFRAME_2, GIFRegHandlerZBUF_1, GIFRegHandlerZBUF_2, + GIFRegHandlerBITBLTBUF, GIFRegHandlerTRXPOS, GIFRegHandlerTRXREG, GIFRegHandlerTRXDIR, + GIFRegHandlerHWREG, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerSIGNAL, GIFRegHandlerFINISH, GIFRegHandlerLABEL, GIFRegHandlerNull }; + +C_ASSERT(sizeof(g_GIFRegHandlers)/sizeof(g_GIFRegHandlers[0]) == 100 ); + +// values for keeping track of changes +u32 s_uTex1Data[2][2] = {0}, s_uClampData[2] = {0}; + +void __fastcall GIFPackedRegHandlerNull(u32* data) +{ +#ifdef _DEBUG + DEBUG_LOG("Unexpected packed reg handler %8.8lx_%8.8lx %x\n", data[0], data[1], data[2]); +#endif +} + +void __fastcall GIFPackedRegHandlerRGBA(u32* data) +{ + gs.rgba = (data[0] & 0xff) | + ((data[1] & 0xff) << 8) | + ((data[2] & 0xff) << 16) | + ((data[3] & 0xff) << 24); + gs.vertexregs.rgba = gs.rgba; + gs.vertexregs.q = gs.q; +} + +void __fastcall GIFPackedRegHandlerSTQ(u32* data) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + *(u32*)&gs.q = data[2]; +} + +void __fastcall GIFPackedRegHandlerUV(u32* data) +{ + gs.vertexregs.u = data[0] & 0x3fff; + gs.vertexregs.v = data[1] & 0x3fff; +} + +void __forceinline KICK_VERTEX2() +{ + if (++gs.primC >= (int)g_primmult[prim->prim]) + { + if (!(g_GameSettings&GAME_XENOSPECHACK) || !ZeroGS::vb[prim->ctxt].zbuf.zmsk) + (*ZeroGS::drawfn[prim->prim])(); + gs.primC -= g_primsub[prim->prim]; + } +} + +void __forceinline KICK_VERTEX3() +{ + if (++gs.primC >= (int)g_primmult[prim->prim]) + { + gs.primC -= g_primsub[prim->prim]; + if (prim->prim == 5) + { + /* tri fans need special processing */ + if (gs.nTriFanVert == gs.primIndex) + gs.primIndex = (gs.primIndex+1) % ARRAYSIZE(gs.gsvertex); + } + } +} + +void __fastcall GIFPackedRegHandlerXYZF2(u32* data) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = (data[2] >> 4) & 0xffffff; + gs.vertexregs.f = (data[3] >> 4) & 0xff; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1) % ARRAYSIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void __fastcall GIFPackedRegHandlerXYZ2(u32* data) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = data[2]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1) % ARRAYSIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void __fastcall GIFPackedRegHandlerFOG(u32* data) +{ + gs.vertexregs.f = (data[3]&0xff0)>>4; +} + +void __fastcall GIFPackedRegHandlerA_D(u32* data) +{ + if((data[2] & 0xff) < 100) + g_GIFRegHandlers[data[2] & 0xff](data); + else + GIFRegHandlerNull(data); +} + +void __fastcall GIFPackedRegHandlerNOP(u32* data) +{ +} + +extern int g_PrevBitwiseTexX, g_PrevBitwiseTexY; + +void tex0Write(int i, u32 *data) +{ + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + if( m_Blocks[psm].bpp == 0 ) { + // kh and others + return; + } + + ZeroGS::vb[i].uNextTex0Data[0] = data[0]; + ZeroGS::vb[i].uNextTex0Data[1] = data[1]; + ZeroGS::vb[i].bNeedTexCheck = 1; + + // don't update unless necessary + if( PSMT_ISCLUT(psm) ) { + if( ZeroGS::CheckChangeInClut(data[1], psm) ) { + // loading clut, so flush whole texture + ZeroGS::vb[i].FlushTexData(); + } + // check if csa is the same!! (ffx bisaid island, grass) + else if( (data[1]&0x1f780000) != (ZeroGS::vb[i].uCurTex0Data[1]&0x1f780000) ) { + ZeroGS::Flush(i); // flush any previous entries + } + } +} + +void tex2Write(int i, u32 *data) +{ + tex0Info& tex0 = ZeroGS::vb[i].tex0; + + if( ZeroGS::vb[i].bNeedTexCheck ) + ZeroGS::vb[i].FlushTexData(); + + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + u32* s_uTex0Data = ZeroGS::vb[i].uCurTex0Data; + + // don't update unless necessary + if( (s_uTex0Data[0]&0x03f00000) == (data[0]&0x03f00000) ) { // psm is the same + + if( PSMT_ISCLUT(psm) ) { + // have to write the CLUT again if changed + if( (s_uTex0Data[1]&0x1fffffe0) == (data[1]&0x1fffffe0) ) { + + if( data[1]&0xe0000000 ) { + tex0.cld = (data[1]>>29)&7; + ZeroGS::texClutWrite(i); + // invalidate to make sure target didn't change! + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + + return; + } + + // CSAs have to be the same! +// if( (data[1]&0xe0000000) == 0 ) { +// +// if( (s_uTex0Data[1]&0x1f100000) != (data[1]&0x1f100000) ) +// ZeroGS::Flush(i); +// +// // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! +// ZeroGS::vb[i].uCurTex0Data[1] = (ZeroGS::vb[i].uCurTex0Data[1]&0xe087ffff)|(data[1]&0x1f780000); +// +// if( ZeroGS::vb[i].tex0.cpsm <= 1 ) ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0xf; +// else ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0x1f; +// +// ZeroGS::vb[i].tex0.cpsm = (data[1] >> 19) & 0xe; +// +// ZeroGS::vb[i].bVarsTexSync = FALSE; +// return; +// } + + // fall through + } + else { + //ZeroGS::vb[i].bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + ZeroGS::vb[i].bTexConstsSync = FALSE; + + s_uTex0Data[0] = (s_uTex0Data[0]&~0x03f00000)|(psm<<20); + s_uTex0Data[1] = (s_uTex0Data[1]&0x1f)|(data[1]&~0x1f); + + tex0.psm = psm; + + if( PSMT_ISCLUT(tex0.psm) ) { + tex0.cbp = (data[1] >> 5) & 0x3fff; + tex0.cpsm = (data[1] >> 19) & 0xe; + tex0.csm = (data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (data[1] >> 24) & 0xf; + else tex0.csa = (data[1] >> 24) & 0x1f; + + tex0.cld = (data[1] >> 29) & 0x7; + ZeroGS::texClutWrite(i); + } +} + +__forceinline void frameWrite(int i, u32 *data) +{ + frameInfo& gsfb = ZeroGS::vb[i].gsfb; + + if( (gsfb.fbp == ((data[0] ) & 0x1ff) * 32) && + (gsfb.fbw == ((data[0] >> 16) & 0x3f) * 64) && + gsfb.psm == ((data[0] >> 24) & 0x3f) && + (gsfb.fbm == data[1]) ) { + return; + } + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gsfb.fbp = ((data[0] ) & 0x1ff) * 32; + gsfb.fbw = ((data[0] >> 16) & 0x3f) * 64; + gsfb.psm = (data[0] >> 24) & 0x3f; + gsfb.fbm = data[1]; + + if (gsfb.fbw > 0) { + + gsfb.fbh = (1024*1024-64*gsfb.fbp) / gsfb.fbw; + gsfb.fbh &= ~0x1f; + if( gsfb.psm & 2 ) + gsfb.fbh *= 2; + if( gsfb.fbh > 1024 ) gsfb.fbh = 1024; + } + else gsfb.fbh = 0; + + if( gsfb.psm == 1 ) gsfb.fbm |= 0xff000000; + else if( gsfb.psm & 2 ) { + + } + + ZeroGS::vb[i].bNeedFrameCheck = 1; +} + +__forceinline void testWrite(int i, u32 *data) +{ + pixTest* test = &ZeroGS::vb[i].test; + + if( (*(u32*)test & 0x0007ffff) == (data[0] & 0x0007ffff) ) + return; + + ZeroGS::Flush(i); + *(u32*)test = data[0]; + +// test.ate = (data[0] ) & 0x1; +// test.atst = (data[0] >> 1) & 0x7; +// test.aref = (data[0] >> 4) & 0xff; +// test.afail = (data[0] >> 12) & 0x3; +// test.date = (data[0] >> 14) & 0x1; +// test.datm = (data[0] >> 15) & 0x1; +// test.zte = (data[0] >> 16) & 0x1; +// test.ztst = (data[0] >> 17) & 0x3; +} + +__forceinline void clampWrite(int i, u32 *data) +{ + clampInfo& clamp = ZeroGS::vb[i].clamp; + + if( s_uClampData[i] != data[0] || ((clamp.minv>>8)|(clamp.maxv<<2)) != (data[1]&0x0fff) ) { + +// if( ZeroGS::vb[i].bNeedTexCheck ) +// ZeroGS::vb[i].FlushTexData(); + + ZeroGS::Flush(i); + s_uClampData[i] = data[0]; + + clamp.wms = (data[0] ) & 0x3; + clamp.wmt = (data[0] >> 2) & 0x3; + clamp.minu = (data[0] >> 4) & 0x3ff; + clamp.maxu = (data[0] >> 14) & 0x3ff; + clamp.minv =((data[0] >> 24) & 0xff) | ((data[1] & 0x3) << 8); + clamp.maxv = (data[1] >> 2) & 0x3ff; + + ZeroGS::vb[i].bTexConstsSync = FALSE; + } +} + +void __fastcall GIFRegHandlerNull(u32* data) +{ +#ifdef _DEBUG + if( (((uptr)&data[2])&0xffff) == 0 ) + return; + + // 0x7f happens on a lot of games + if( data[2] != 0x7f && (data[0] || data[1]) ) { + DEBUG_LOG("Unexpected reg handler %x %x %x\n", data[0], data[1], data[2]); + } +#endif +} + +void __fastcall GIFRegHandlerPRIM(u32 *data) { + if (data[0] & ~0x3ff) { + //WARN_LOG("warning: unknown bits in prim %8.8lx_%8.8lx\n", data[1], data[0]); + } + + gs.nTriFanVert = gs.primIndex; + gs.primC = 0; + prim->prim = (data[0]) & 0x7; + gs._prim[0].prim = (data[0]) & 0x7; + gs._prim[1].prim = (data[0]) & 0x7; + gs._prim[1]._val = (data[0]>>3)&0xff; + + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerRGBAQ(u32* data) +{ + gs.rgba = data[0]; + gs.vertexregs.rgba = data[0]; + *(u32*)&gs.vertexregs.q = data[1]; +} + +void __fastcall GIFRegHandlerST(u32* data) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + //*(u32*)&gs.q = data[2]; +} + +void __fastcall GIFRegHandlerUV(u32* data) +{ + gs.vertexregs.u = (data[0]) & 0x3fff; + gs.vertexregs.v = (data[0] >> 16) & 0x3fff; +} + +void __fastcall GIFRegHandlerXYZF2(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void __fastcall GIFRegHandlerXYZ2(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void __fastcall GIFRegHandlerTEX0_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + tex0Write(0, data); +} + +void __fastcall GIFRegHandlerTEX0_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + tex0Write(1, data); +} + +void __fastcall GIFRegHandlerCLAMP_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + clampWrite(0, data); +} + +void __fastcall GIFRegHandlerCLAMP_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + clampWrite(1, data); +} + +void __fastcall GIFRegHandlerFOG(u32* data) +{ + //gs.gsvertex[gs.primIndex].f = (data[1] >> 24); // shift to upper bits + gs.vertexregs.f = data[1]>>24; +} + +void __fastcall GIFRegHandlerXYZF3(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void __fastcall GIFRegHandlerXYZ3(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void __fastcall GIFRegHandlerNOP(u32* data) +{ +} + +void tex1Write(int i, u32* data) +{ + tex1Info& tex1 = ZeroGS::vb[i].tex1; + + if( conf.bilinear == 1 && (tex1.mmag != ((data[0] >> 5) & 0x1) || tex1.mmin != ((data[0] >> 6) & 0x7)) ) { + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + tex1.lcm = (data[0] ) & 0x1; + tex1.mxl = (data[0] >> 2) & 0x7; + tex1.mmag = (data[0] >> 5) & 0x1; + tex1.mmin = (data[0] >> 6) & 0x7; + tex1.mtba = (data[0] >> 9) & 0x1; + tex1.l = (data[0] >> 19) & 0x3; + tex1.k = (data[1] >> 4) & 0xff; +} + +void __fastcall GIFRegHandlerTEX1_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + + tex1Write(0, data); +} + +void __fastcall GIFRegHandlerTEX1_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) + return; + + tex1Write(1, data); +} + +void __fastcall GIFRegHandlerTEX2_1(u32* data) +{ + tex2Write(0, data); +} + +void __fastcall GIFRegHandlerTEX2_2(u32* data) +{ + tex2Write(1, data); +} + +void __fastcall GIFRegHandlerXYOFFSET_1(u32* data) +{ + // eliminator low 4 bits for now + ZeroGS::vb[0].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[0].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[0].offset.x &= ~15; +// ZeroGS::vb[0].offset.y &= ~15; +// } +} + +void __fastcall GIFRegHandlerXYOFFSET_2(u32* data) +{ + ZeroGS::vb[1].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[1].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[1].offset.x &= ~15; +// ZeroGS::vb[1].offset.y &= ~15; +// } +} + +void __fastcall GIFRegHandlerPRMODECONT(u32* data) +{ + gs.prac = data[0] & 0x1; + prim = &gs._prim[gs.prac]; + + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerPRMODE(u32* data) +{ + gs._prim[0]._val = (data[0]>>3)&0xff; + + if (gs.prac == 0) + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerTEXCLUT(u32* data) +{ + if( ZeroGS::vb[0].bNeedTexCheck ) + ZeroGS::vb[0].FlushTexData(); + if( ZeroGS::vb[1].bNeedTexCheck ) + ZeroGS::vb[1].FlushTexData(); + gs.clut.cbw = ((data[0] ) & 0x3f) * 64; + gs.clut.cou = ((data[0] >> 6) & 0x3f) * 16; + gs.clut.cov = (data[0] >> 12) & 0x3ff; +} + +void __fastcall GIFRegHandlerSCANMSK(u32* data) +{ +// ZeroGS::Flush(0); +// ZeroGS::Flush(1); +// ZeroGS::ResolveC(&ZeroGS::vb[0]); +// ZeroGS::ResolveZ(&ZeroGS::vb[0]); + + gs.smask = data[0] & 0x3; +} + +void __fastcall GIFRegHandlerMIPTBP1_1(u32* data) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[0].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP1_2(u32* data) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[1].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP2_1(u32* data) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[0].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP2_2(u32* data) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[1].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerTEXA(u32* data) +{ + texaInfo newinfo; + newinfo.aem = (data[0] >> 15) & 0x1; + newinfo.ta[0] = data[0] & 0xff; + newinfo.ta[1] = data[1] & 0xff; + + if( *(u32*)&newinfo != *(u32*)&gs.texa ) { + ZeroGS::Flush(0); + ZeroGS::Flush(1); + *(u32*)&gs.texa = *(u32*)&newinfo; + gs.texa.fta[0] = newinfo.ta[0]/255.0f; + gs.texa.fta[1] = newinfo.ta[1]/255.0f; + + ZeroGS::vb[0].bTexConstsSync = FALSE; + ZeroGS::vb[1].bTexConstsSync = FALSE; + } +} + +void __fastcall GIFRegHandlerFOGCOL(u32* data) +{ + ZeroGS::SetFogColor(data[0]&0xffffff); +} + +void __fastcall GIFRegHandlerTEXFLUSH(u32* data) +{ + ZeroGS::SetTexFlush(); +} + +void __fastcall GIFRegHandlerSCISSOR_1(u32* data) +{ + Rect2& scissor = ZeroGS::vb[0].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(0); + scissor = newscissor; + + ZeroGS::vb[0].bNeedFrameCheck = 1; + } +} + +void __fastcall GIFRegHandlerSCISSOR_2(u32* data) +{ + Rect2& scissor = ZeroGS::vb[1].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(1); + scissor = newscissor; + + // flush everything + ZeroGS::vb[1].bNeedFrameCheck = 1; + } +} + +void __fastcall GIFRegHandlerALPHA_1(u32* data) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(WORD*)&newalpha != *(WORD*)&ZeroGS::vb[0].alpha ) { + ZeroGS::Flush(0); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(WORD*)&ZeroGS::vb[0].alpha = *(WORD*)&newalpha; + } +} + +void __fastcall GIFRegHandlerALPHA_2(u32* data) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(WORD*)&newalpha != *(WORD*)&ZeroGS::vb[1].alpha ) { + ZeroGS::Flush(1); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(WORD*)&ZeroGS::vb[1].alpha = *(WORD*)&newalpha; + } +} + +void __fastcall GIFRegHandlerDIMX(u32* data) +{ +} + +void __fastcall GIFRegHandlerDTHE(u32* data) +{ + gs.dthe = data[0] & 0x1; +} + +void __fastcall GIFRegHandlerCOLCLAMP(u32* data) +{ + gs.colclamp = data[0] & 0x1; +} + +void __fastcall GIFRegHandlerTEST_1(u32* data) +{ + testWrite(0, data); +} + +void __fastcall GIFRegHandlerTEST_2(u32* data) +{ + testWrite(1, data); +} + +void __fastcall GIFRegHandlerPABE(u32* data) +{ + //ZeroGS::SetAlphaChanged(0, GPUREG_PABE); + //ZeroGS::SetAlphaChanged(1, GPUREG_PABE); + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gs.pabe = *data & 0x1; +} + +void __fastcall GIFRegHandlerFBA_1(u32* data) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[0].fba.fba = *data & 0x1; +} + +void __fastcall GIFRegHandlerFBA_2(u32* data) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[1].fba.fba = *data & 0x1; +} + +void __fastcall GIFRegHandlerFRAME_1(u32* data) +{ + frameWrite(0, data); +} + +void __fastcall GIFRegHandlerFRAME_2(u32* data) +{ + frameWrite(1, data); +} + +void __fastcall GIFRegHandlerZBUF_1(u32* data) +{ + zbufInfo& zbuf = ZeroGS::vb[0].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[0].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[0].zprimmask = 0xffff; + + ZeroGS::vb[0].bNeedZCheck = 1; +} + +void __fastcall GIFRegHandlerZBUF_2(u32* data) +{ + zbufInfo& zbuf = ZeroGS::vb[1].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[1].bNeedZCheck = 1; + + ZeroGS::vb[1].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[1].zprimmask = 0xffff; +} + +void __fastcall GIFRegHandlerBITBLTBUF(u32* data) +{ + gs.srcbufnew.bp = ((data[0] ) & 0x3fff);// * 64; + gs.srcbufnew.bw = ((data[0] >> 16) & 0x3f) * 64; + gs.srcbufnew.psm = (data[0] >> 24) & 0x3f; + gs.dstbufnew.bp = ((data[1] ) & 0x3fff);// * 64; + gs.dstbufnew.bw = ((data[1] >> 16) & 0x3f) * 64; + gs.dstbufnew.psm = (data[1] >> 24) & 0x3f; + + if (gs.dstbufnew.bw == 0) gs.dstbufnew.bw = 64; +} + +void __fastcall GIFRegHandlerTRXPOS(u32* data) +{ + gs.trxposnew.sx = (data[0] ) & 0x7ff; + gs.trxposnew.sy = (data[0] >> 16) & 0x7ff; + gs.trxposnew.dx = (data[1] ) & 0x7ff; + gs.trxposnew.dy = (data[1] >> 16) & 0x7ff; + gs.trxposnew.dir = (data[1] >> 27) & 0x3; +} + +void __fastcall GIFRegHandlerTRXREG(u32* data) +{ + gs.imageWtemp = data[0]&0xfff; + gs.imageHtemp = data[1]&0xfff; +} + +void __fastcall GIFRegHandlerTRXDIR(u32* data) +{ + // terminate any previous transfers + switch( gs.imageTransfer ) { + case 0: // host->loc + gs.imageTransfer = -1; + break; + case 1: // loc->host + ZeroGS::TerminateLocalHost(); + break; + } + + gs.srcbuf = gs.srcbufnew; + gs.dstbuf = gs.dstbufnew; + gs.trxpos = gs.trxposnew; + gs.imageTransfer = data[0] & 0x3; + gs.imageWnew = gs.imageWtemp; + gs.imageHnew = gs.imageHtemp; + + if( gs.imageWnew > 0 && gs.imageHnew > 0 ) { + switch(gs.imageTransfer) { + case 0: // host->loc + ZeroGS::InitTransferHostLocal(); + break; + + case 1: // loc->host + + ZeroGS::InitTransferLocalHost(); + break; + case 2: + + ZeroGS::TransferLocalLocal(); + break; + + case 3: + gs.imageTransfer = -1; + break; + + default: assert(0); + } + } + else { +#ifndef RELEASE_TO_PUBLIC + //WARN_LOG("ZeroGS: dummy transfer\n"); +#endif + gs.imageTransfer = -1; + } +} + +static u32 oldhw[4]; +void __fastcall GIFRegHandlerHWREG(u32* data) +{ + if( gs.imageTransfer == 0 ) { + ZeroGS::TransferHostLocal(data, 2); + } + else { +#ifndef RELEASE_TO_PUBLIC + ERROR_LOG("ZeroGS: HWREG!? %8.8x_%8.8x\n", data[0], data[1]); + //assert(0); +#endif + } +} + +extern int g_GSMultiThreaded; + +void __fastcall GIFRegHandlerSIGNAL(u32* data) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->SIGID = (SIGLBLID->SIGID&~data[1])|(data[0]&data[1]); + +// if (gs.CSRw & 0x1) CSR->SIGNAL = 1; +// if (!IMR->SIGMSK && GSirq) +// GSirq(); + + if (gs.CSRw & 0x1) { + CSR->SIGNAL = 1; + //gs.CSRw &= ~1; + } + if (!IMR->SIGMSK && GSirq) + GSirq(); + } +} + +void __fastcall GIFRegHandlerFINISH(u32* data) +{ + if(!g_GSMultiThreaded) { + + if (gs.CSRw & 0x2) + CSR->FINISH = 1; + if (!IMR->FINISHMSK && GSirq) + GSirq(); + +// if( gs.CSRw & 2 ) { +// //gs.CSRw &= ~2; +// //CSR->FINISH = 0; +// +// +// } +// CSR->FINISH = 1; +// +// if( !IMR->FINISHMSK && GSirq ) +// GSirq(); + } +} + +void __fastcall GIFRegHandlerLABEL(u32* data) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->LBLID = (SIGLBLID->LBLID&~data[1])|(data[0]&data[1]); + } +} + + +// special execute buffers +//ExecuteBufferXeno g_ebXeno; +// +//ExecuteBufferXeno::ExecuteBufferXeno() +//{ +// clampdata[0] = clampdata[1] = 0; +// tex0data[0] = tex0data[1] = 0; +// tex1data[0] = tex1data[1] = 0; +// bCanExecute = true; +// curprim._val = 0; +//} +// +//void ExecuteBufferXeno::Execute() +//{ +// if( vertices.size() == 0 || !bCanExecute) +// return; +// +// bCanExecute = false; +// ZeroGS::Flush(0); +// ZeroGS::Flush(1); +// +// int oldC = gs.primC; +// int ctx = curprim.ctxt; +// +// Vertex oldverts[3]; +// oldverts[0] = gs.gsvertex[0]; +// oldverts[1] = gs.gsvertex[1]; +// oldverts[2] = gs.gsvertex[2]; +// +// u32 oldtex0[2]; +// tex1Info oldtex1 = ZeroGS::vb[ctx].tex1; +// clampInfo oldclamp = ZeroGS::vb[ctx].clamp; +// oldtex0[0] = ZeroGS::vb[ctx].uNextTex0Data[0]; +// oldtex0[1] = ZeroGS::vb[ctx].uNextTex0Data[1]; +// +// int oldmask = ZeroGS::vb[ctx].zbuf.zmsk; +// ZeroGS::vb[ctx].zbuf.zmsk = 1; +// tex0Write(0, tex0data); +// tex1Write(0, tex1data); +// clampWrite(0, clampdata); +// ZeroGS::vb[ctx].bTexConstsSync = FALSE; +// gs.primC = 3; +// u32 oldprim = prim->_val; +// prim->_val = curprim._val; +// for(int i = 0; i < (int)vertices.size(); i += 3) { +// gs.gsvertex[0] = vertices[i]; +// gs.gsvertex[1] = vertices[i+1]; +// gs.gsvertex[2] = vertices[i+2]; +// (*ZeroGS::drawfn[4])(); // draw a triangle +// } +// vertices.resize(0); +// +// ZeroGS::Flush(ctx); +// +// ZeroGS::vb[ctx].zbuf.zmsk = oldmask; +// gs.primC = oldC; +// gs.gsvertex[0] = oldverts[0]; +// gs.gsvertex[1] = oldverts[1]; +// gs.gsvertex[2] = oldverts[2]; +// ZeroGS::vb[ctx].clamp = oldclamp; +// ZeroGS::vb[ctx].tex1 = oldtex1; +// tex0Write(0, oldtex0); +// ZeroGS::vb[ctx].bTexConstsSync = FALSE; +// prim->_val = oldprim; +// bCanExecute = true; +//} +// +//void ExecuteBufferXeno::SetTex0(u32* data) +//{ +// if( data[0] != tex0data[0] || (data[1]&0x1fffffff) != (tex0data[1]&0x1fffffff) ) +// Execute(); +// +// tex0data[0] = data[0]; +// tex0data[1] = data[1]; +//} +// +//void ExecuteBufferXeno::SetTex1(u32* data) +//{ +// if( data[0] != tex1data[0] ) +// Execute(); +// +// tex1data[0] = data[0]; +// tex1data[1] = data[1]; +//} +// +//void ExecuteBufferXeno::SetClamp(u32* data) +//{ +// if( data[0] != clampdata[0] || (data[1]&0xfff) != clampdata[1] ) +// Execute(); +// +// clampdata[0] = data[0]; +// clampdata[1] = data[1]&0xfff; +//} +// +//void ExecuteBufferXeno::SetTri() +//{ +// if( prim->_val != curprim._val ) +// Execute(); +// curprim._val = prim->_val; +// vertices.push_back(gs.gsvertex[0]); +// vertices.push_back(gs.gsvertex[1]); +// vertices.push_back(gs.gsvertex[2]); +//} diff --git a/plugins/zerogs/dx/Regs.h b/plugins/zerogs/dx/Regs.h new file mode 100644 index 0000000000..6ec859a6b3 --- /dev/null +++ b/plugins/zerogs/dx/Regs.h @@ -0,0 +1,122 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __GSREGS_H__ +#define __GSREGS_H__ + +typedef void (__fastcall *GIFRegHandler)(u32* data); + +void __fastcall GIFPackedRegHandlerNull(u32* data); +void __fastcall GIFPackedRegHandlerRGBA(u32* data); +void __fastcall GIFPackedRegHandlerSTQ(u32* data); +void __fastcall GIFPackedRegHandlerUV(u32* data); +void __fastcall GIFPackedRegHandlerXYZF2(u32* data); +void __fastcall GIFPackedRegHandlerXYZ2(u32* data); +void __fastcall GIFPackedRegHandlerFOG(u32* data); +void __fastcall GIFPackedRegHandlerA_D(u32* data); +void __fastcall GIFPackedRegHandlerNOP(u32* data); + +void __fastcall GIFRegHandlerNull(u32* data); +void __fastcall GIFRegHandlerPRIM(u32* data); +void __fastcall GIFRegHandlerRGBAQ(u32* data); +void __fastcall GIFRegHandlerST(u32* data); +void __fastcall GIFRegHandlerUV(u32* data); +void __fastcall GIFRegHandlerXYZF2(u32* data); +void __fastcall GIFRegHandlerXYZ2(u32* data); +void __fastcall GIFRegHandlerTEX0_1(u32* data); +void __fastcall GIFRegHandlerTEX0_2(u32* data); +void __fastcall GIFRegHandlerCLAMP_1(u32* data); +void __fastcall GIFRegHandlerCLAMP_2(u32* data); +void __fastcall GIFRegHandlerFOG(u32* data); +void __fastcall GIFRegHandlerXYZF3(u32* data); +void __fastcall GIFRegHandlerXYZ3(u32* data); +void __fastcall GIFRegHandlerNOP(u32* data); +void __fastcall GIFRegHandlerTEX1_1(u32* data); +void __fastcall GIFRegHandlerTEX1_2(u32* data); +void __fastcall GIFRegHandlerTEX2_1(u32* data); +void __fastcall GIFRegHandlerTEX2_2(u32* data); +void __fastcall GIFRegHandlerXYOFFSET_1(u32* data); +void __fastcall GIFRegHandlerXYOFFSET_2(u32* data); +void __fastcall GIFRegHandlerPRMODECONT(u32* data); +void __fastcall GIFRegHandlerPRMODE(u32* data); +void __fastcall GIFRegHandlerTEXCLUT(u32* data); +void __fastcall GIFRegHandlerSCANMSK(u32* data); +void __fastcall GIFRegHandlerMIPTBP1_1(u32* data); +void __fastcall GIFRegHandlerMIPTBP1_2(u32* data); +void __fastcall GIFRegHandlerMIPTBP2_1(u32* data); +void __fastcall GIFRegHandlerMIPTBP2_2(u32* data); +void __fastcall GIFRegHandlerTEXA(u32* data); +void __fastcall GIFRegHandlerFOGCOL(u32* data); +void __fastcall GIFRegHandlerTEXFLUSH(u32* data); +void __fastcall GIFRegHandlerSCISSOR_1(u32* data); +void __fastcall GIFRegHandlerSCISSOR_2(u32* data); +void __fastcall GIFRegHandlerALPHA_1(u32* data); +void __fastcall GIFRegHandlerALPHA_2(u32* data); +void __fastcall GIFRegHandlerDIMX(u32* data); +void __fastcall GIFRegHandlerDTHE(u32* data); +void __fastcall GIFRegHandlerCOLCLAMP(u32* data); +void __fastcall GIFRegHandlerTEST_1(u32* data); +void __fastcall GIFRegHandlerTEST_2(u32* data); +void __fastcall GIFRegHandlerPABE(u32* data); +void __fastcall GIFRegHandlerFBA_1(u32* data); +void __fastcall GIFRegHandlerFBA_2(u32* data); +void __fastcall GIFRegHandlerFRAME_1(u32* data); +void __fastcall GIFRegHandlerFRAME_2(u32* data); +void __fastcall GIFRegHandlerZBUF_1(u32* data); +void __fastcall GIFRegHandlerZBUF_2(u32* data); +void __fastcall GIFRegHandlerBITBLTBUF(u32* data); +void __fastcall GIFRegHandlerTRXPOS(u32* data); +void __fastcall GIFRegHandlerTRXREG(u32* data); +void __fastcall GIFRegHandlerTRXDIR(u32* data); +void __fastcall GIFRegHandlerHWREG(u32* data); +void __fastcall GIFRegHandlerSIGNAL(u32* data); +void __fastcall GIFRegHandlerFINISH(u32* data); +void __fastcall GIFRegHandlerLABEL(u32* data); + +// special buffers that delay executing some insturctions +//#include +// +//class ExecuteBuffer +//{ +//public: +// virtual void Execute()=0; +//}; +// +//class ExecuteBufferXeno : public ExecuteBuffer +//{ +//public: +// ExecuteBufferXeno(); +// virtual void Execute(); +// +// void SetTex0(u32* data); +// void SetTex1(u32* data); +// void SetClamp(u32* data); +// void SetTri(); +// +// u32 clampdata[2]; +// u32 tex0data[2]; +// u32 tex1data[2]; +// primInfo curprim; +// +// std::vector vertices; +// bool bCanExecute; +//}; +// +//extern ExecuteBufferXeno g_ebXeno; + +#endif diff --git a/plugins/zerogs/dx/Win32/Conf.cpp b/plugins/zerogs/dx/Win32/Conf.cpp new file mode 100644 index 0000000000..e887ad3e81 --- /dev/null +++ b/plugins/zerogs/dx/Win32/Conf.cpp @@ -0,0 +1,117 @@ +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include + +#include "GS.h" +#include "Win32.h" + +extern HINSTANCE hInst; + + +void SaveConfig() { + + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\zerogs.ini"); + + sprintf(szValue,"%u",conf.interlace); + WritePrivateProfileString("Settings", "Interlace",szValue,szIniFile); + sprintf(szValue,"%u",conf.aa); + WritePrivateProfileString("Settings", "Antialiasing",szValue,szIniFile); + sprintf(szValue,"%u",conf.bilinear); + WritePrivateProfileString("Settings", "Bilinear",szValue,szIniFile); + sprintf(szValue,"%u",conf.options); + WritePrivateProfileString("Settings", "Options",szValue,szIniFile); + sprintf(szValue,"%u",conf.gamesettings); + WritePrivateProfileString("Settings", "AdvancedOptions",szValue,szIniFile); +} + +void LoadConfig() { + + FILE *fp; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + memset(&conf, 0, sizeof(conf)); + conf.interlace = 0; // on, mode 1 + conf.mrtdepth = 1; + conf.options = 0; + conf.bilinear = 1; + conf.width = 640; + conf.height = 480; + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\zerogs.ini"); + fp=fopen("inis\\zerogs.ini","rt"); + if (!fp) + { + CreateDirectory("inis",NULL); + SaveConfig();//save and return + return ; + } + fclose(fp); + + GetPrivateProfileString("Settings", "Interlace", NULL, szValue, 20, szIniFile); + conf.interlace = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Antialiasing", NULL, szValue, 20, szIniFile); + conf.aa = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Options", NULL, szValue, 20, szIniFile); + conf.options = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "AdvancedOptions", NULL, szValue, 20, szIniFile); + conf.gamesettings = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Bilinear", NULL, szValue, 20, szIniFile); + conf.bilinear = strtoul(szValue, NULL, 10); + + if( conf.aa < 0 || conf.aa > 4 ) conf.aa = 0; + + switch(conf.options&GSOPTION_WINDIMS) { + case GSOPTION_WIN640: + conf.width = 640; + conf.height = 480; + break; + case GSOPTION_WIN800: + conf.width = 800; + conf.height = 600; + break; + case GSOPTION_WIN1024: + conf.width = 1024; + conf.height = 768; + break; + case GSOPTION_WIN1280: + conf.width = 1280; + conf.height = 960; + break; + case GSOPTION_WIN960W: + conf.width = 960; + conf.height = 540; + break; + case GSOPTION_WIN1280W: + conf.width = 1280; + conf.height = 720; + break; + case GSOPTION_WIN1920W: + conf.width = 1920; + conf.height = 1080; + break; + } + + // turn off all hacks by defaultof + conf.options &= ~(GSOPTION_FULLSCREEN|GSOPTION_WIREFRAME|GSOPTION_CAPTUREAVI); + conf.options |= GSOPTION_LOADED; + + if( conf.width <= 0 || conf.height <= 0 ) { + conf.width = 640; + conf.height = 480; + } +} diff --git a/plugins/zerogs/dx/Win32/GSsoftdx.def b/plugins/zerogs/dx/Win32/GSsoftdx.def new file mode 100644 index 0000000000..aca9c7a7a7 --- /dev/null +++ b/plugins/zerogs/dx/Win32/GSsoftdx.def @@ -0,0 +1,35 @@ +; Declares the module parameters for the DLL. + +;LIBRARY "ZeroGS" + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + GSinit @5 + GSshutdown @6 + GSopen @7 + GSclose @8 + GSgifTransfer1 @13 + GSgifTransfer2 @14 + GSgifTransfer3 @15 + GSreadFIFO @16 + GSvsync @17 + GSmakeSnapshot @18 + GSkeyEvent @19 + GSfreeze @20 + GSconfigure @21 + GStest @22 + GSabout @23 + GSreadFIFO2 @28 + GSirqCallback @29 + GSsetBaseMem @30 + GSwriteCSR @31 + GSchangeSaveState @32 + GSreset @33 + GSgifSoftReset @34 + GSsetFrameSkip @35 + GSsetGameCRC @36 + GSgetLastTag @37 + GSsetupRecording @38 \ No newline at end of file diff --git a/plugins/zerogs/dx/Win32/Win32.cpp b/plugins/zerogs/dx/Win32/Win32.cpp new file mode 100644 index 0000000000..25bc1f68d1 --- /dev/null +++ b/plugins/zerogs/dx/Win32/Win32.cpp @@ -0,0 +1,269 @@ +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include +#include +#include + +#include "resrc1.h" + +#include "GS.h" +#include "Win32.h" + +#include +using namespace std; + +extern int g_nPixelShaderVer; +HINSTANCE hInst=NULL; +static int prevbilinearfilter = 0; + +void CALLBACK GSkeyEvent(keyEvent *ev) { +// switch (ev->event) { +// case KEYPRESS: +// switch (ev->key) { +// case VK_PRIOR: +// if (conf.fps) fpspos++; break; +// case VK_NEXT: +// if (conf.fps) fpspos--; break; +// case VK_END: +// if (conf.fps) fpspress = 1; break; +// case VK_DELETE: +// conf.fps = 1 - conf.fps; +// break; +// } +// break; +// } +} + +#include "Win32/resource.h" + +BOOL CALLBACK LoggingDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, FALSE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOG)) + conf.log = 1; + else conf.log = 0; + + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +map mapConfOpts; +#define PUT_CONF(id) mapConfOpts[IDC_CONFOPT_##id] = 0x##id; + +void OnInitDialog(HWND hW) +{ + if( !(conf.options & GSOPTION_LOADED) ) + LoadConfig(); + + CheckDlgButton(hW, IDC_CONFIG_INTERLACE, conf.interlace); + CheckDlgButton(hW, IDC_CONFIG_BILINEAR, !!conf.bilinear); + CheckDlgButton(hW, IDC_CONFIG_DEPTHWRITE, conf.mrtdepth); + CheckRadioButton(hW,IDC_CONFIG_AANONE,IDC_CONFIG_AA16, IDC_CONFIG_AANONE+conf.aa); + CheckDlgButton(hW, IDC_CONFIG_WIREFRAME, (conf.options&GSOPTION_WIREFRAME)?1:0); + CheckDlgButton(hW, IDC_CONFIG_CAPTUREAVI, (conf.options&GSOPTION_CAPTUREAVI)?1:0); + CheckDlgButton(hW, IDC_CONFIG_FULLSCREEN, (conf.options&GSOPTION_FULLSCREEN)?1:0); + //CheckDlgButton(hW, IDC_CONFIG_FFX, (conf.options&GSOPTION_FFXHACK)?1:0); + CheckDlgButton(hW, IDC_CONFIG_BMPSS, (conf.options&GSOPTION_BMPSNAP)?1:0); + CheckRadioButton(hW,IDC_CONF_WIN640, IDC_CONF_WIN1920W, IDC_CONF_WIN640+((conf.options&GSOPTION_WINDIMS)>>4)); + + prevbilinearfilter = conf.bilinear; + + mapConfOpts.clear(); + PUT_CONF(00000001); + PUT_CONF(00000002); + PUT_CONF(00000004); + PUT_CONF(00000008); + PUT_CONF(00000010); + PUT_CONF(00000020); + PUT_CONF(00000040); + PUT_CONF(00000080); + PUT_CONF(00000200); + PUT_CONF(00000400); + PUT_CONF(00000800); + PUT_CONF(00001000); + PUT_CONF(00002000); + PUT_CONF(00004000); + PUT_CONF(00008000); + PUT_CONF(00010000); + PUT_CONF(00020000); + PUT_CONF(00040000); + PUT_CONF(00080000); + PUT_CONF(00100000); + PUT_CONF(00200000); + PUT_CONF(01000000); + PUT_CONF(02000000); + PUT_CONF(04000000); + PUT_CONF(08000000); + + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + CheckDlgButton(hW, it->first, (conf.gamesettings&it->second)?1:0); + } +} + +void OnOK(HWND hW) { + + u32 newinterlace = IsDlgButtonChecked(hW, IDC_CONFIG_INTERLACE); + + if( !conf.interlace ) conf.interlace = newinterlace; + else if( !newinterlace ) conf.interlace = 2; // off + + conf.bilinear = IsDlgButtonChecked(hW, IDC_CONFIG_BILINEAR); + // restore + if( conf.bilinear && prevbilinearfilter ) + conf.bilinear = prevbilinearfilter; + + if( SendDlgItemMessage(hW,IDC_CONFIG_AANONE,BM_GETCHECK,0,0) ) { + conf.aa = 0; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA2,BM_GETCHECK,0,0) ) { + conf.aa = 1; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA4,BM_GETCHECK,0,0) ) { + conf.aa = 2; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA8,BM_GETCHECK,0,0) ) { + conf.aa = 3; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA16,BM_GETCHECK,0,0) ) { + conf.aa = 4; + } + else conf.aa = 0; + + conf.options = 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_CAPTUREAVI) ? GSOPTION_CAPTUREAVI : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_WIREFRAME) ? GSOPTION_WIREFRAME : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FULLSCREEN) ? GSOPTION_FULLSCREEN : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_BMPSS) ? GSOPTION_BMPSNAP : 0; + + conf.gamesettings = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + if( IsDlgButtonChecked(hW, it->first) ) + conf.gamesettings |= it->second; + } + GSsetGameCRC(g_LastCRC, conf.gamesettings); + + if( SendDlgItemMessage(hW,IDC_CONF_WIN640,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN640; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN800,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN800; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1024,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1024; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN960W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN960W; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280W; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1920W,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1920W; + + SaveConfig(); + EndDialog(hW, FALSE); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + OnInitDialog(hW); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + OnOK(hW); + return TRUE; + case IDC_CONFOPT_COMPUTEOR: + { + int value = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + if( IsDlgButtonChecked(hW, it->first) ) + value|= it->second; + } + char str[20]; + sprintf(str, "%.8x", value); + SetWindowText(GetDlgItem(hW, IDC_CONFOPT_IDS), str); + break; + } + case IDC_CONF_DEFAULT: + { + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + CheckDlgButton(hW, it->first, 0); + } + break; + } + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + + //ZeroGS uses floating point render targets because A8R8G8B8 format is not sufficient for ps2 blending and this requires alpha blending on floating point render targets + //There might be a problem with pixel shader precision with older geforce models (textures will look blocky). + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +s32 CALLBACK GStest() { + return 0; +} + +void CALLBACK GSabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + +static char *err = "Error Loading Symbol"; +static int errval; + +void *SysLoadLibrary(char *lib) { + return LoadLibrary(lib); +} + +void *SysLoadSym(void *lib, char *sym) { + void *tmp = GetProcAddress((HINSTANCE)lib, sym); + if (tmp == NULL) errval = 1; + else errval = 0; + return tmp; +} + +char *SysLibError() { + if (errval) { errval = 0; return err; } + return NULL; +} + +void SysCloseLibrary(void *lib) { + FreeLibrary((HINSTANCE)lib); +} diff --git a/plugins/zerogs/dx/Win32/Win32.h b/plugins/zerogs/dx/Win32/Win32.h new file mode 100644 index 0000000000..45322b3d01 --- /dev/null +++ b/plugins/zerogs/dx/Win32/Win32.h @@ -0,0 +1,9 @@ +#ifndef __WIN32_H__ +#define __WIN32_H__ + +#include "resrc1.h" +#include "Win32/resource.h" + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#endif /* __WIN32_H__ */ diff --git a/plugins/zerogs/dx/Win32/aviUtil.h b/plugins/zerogs/dx/Win32/aviUtil.h new file mode 100644 index 0000000000..945fd3d68a --- /dev/null +++ b/plugins/zerogs/dx/Win32/aviUtil.h @@ -0,0 +1,484 @@ +#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame. + +#include +using namespace std; + +#include +#include +#include + +BOOL AVI_Init() +{ + /* first let's make sure we are running on 1.1 */ + WORD wVer = HIWORD(VideoForWindowsVersion()); + if (wVer < 0x010a){ + /* oops, we are too old, blow out of here */ + //MessageBeep(MB_ICONHAND); + MessageBox(NULL, "Cant't init AVI File - Video for Windows version is to old", "Error", MB_OK|MB_ICONSTOP); + return FALSE; + } + + AVIFileInit(); + + return TRUE; +} + +BOOL AVI_FileOpenWrite(PAVIFILE * pfile, const char *filename) +{ + HRESULT hr = AVIFileOpen(pfile, // returned file pointer + filename, // file name + OF_WRITE | OF_CREATE, // mode to open file with + NULL); // use handler determined + // from file extension.... + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +DWORD getFOURCC(const char* value) +{ + if(_stricmp(value, "DIB") == 0) + { + return mmioFOURCC(value[0],value[1],value[2],' '); + } + else if((_stricmp(value, "CVID") == 0) + || (_stricmp(value, "IV32") == 0) + || (_stricmp(value, "MSVC") == 0) + || (_stricmp(value, "IV50") == 0)) + { + return mmioFOURCC(value[0],value[1],value[2],value[3]); + } + else + { + return NULL; + } +} + +// Fill in the header for the video stream.... +// The video stream will run in rate ths of a second.... +BOOL AVI_CreateStream(PAVIFILE pfile, PAVISTREAM * ps, int rate, // sample/second + unsigned long buffersize, int rectwidth, int rectheight, + const char* _compressor) +{ + AVISTREAMINFO strhdr; + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeVIDEO;// stream type + strhdr.fccHandler = getFOURCC(_compressor); + //strhdr.fccHandler = 0; // no compression! + //strhdr.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //strhdr.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //strhdr.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //strhdr.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //strhdr.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //strhdr.dwFlags = AVISTREAMINFO_DISABLED; + //strhdr.dwCaps = + //strhdr.wPriority = + //strhdr.wLanguage = + strhdr.dwScale = 1; + strhdr.dwRate = rate; // rate fps + //strhdr.dwStart = + //strhdr.dwLength = + //strhdr.dwInitialFrames = + strhdr.dwSuggestedBufferSize = buffersize; + strhdr.dwQuality = -1; // use the default + //strhdr.dwSampleSize = + SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream + (int) rectwidth, + (int) rectheight); + //strhdr.dwEditCount = + //strhdr.dwFormatChangeCount = + //strcpy(strhdr.szName, "Full Frames (Uncompressed)"); + + // And create the stream; + HRESULT hr = AVIFileCreateStream(pfile, // file pointer + ps, // returned stream pointer + &strhdr); // stream header + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +string getFOURCCVAsString(DWORD value) +{ + string returnValue = ""; + if( value == 0 ) + return returnValue; + + DWORD ch0 = value & 0x000000FF; + returnValue.push_back((char) ch0); + DWORD ch1 = (value & 0x0000FF00)>>8; + returnValue.push_back((char) ch1); + DWORD ch2 = (value & 0x00FF0000)>>16; + returnValue.push_back((char) ch2); + DWORD ch3 = (value & 0xFF000000)>>24; + returnValue.push_back((char) ch3); + + return returnValue; +} + +string dumpAVICOMPRESSOPTIONS(AVICOMPRESSOPTIONS opts) +{ + char tmp[255]; + string returnValue = "Dump of AVICOMPRESSOPTIONS\n"; + + returnValue += "DWORD fccType = streamtype("; returnValue += getFOURCCVAsString(opts.fccType); returnValue += ")\n"; + returnValue += "DWORD fccHandler = "; returnValue += getFOURCCVAsString(opts.fccHandler); returnValue += "\n"; + + _snprintf(tmp, 255, "DWORD dwKeyFrameEvery = %d\n", opts.dwKeyFrameEvery); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwQuality = %d\n", opts.dwQuality); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwBytesPerSecond = %d\n", opts.dwBytesPerSecond); + returnValue += tmp; + + if((opts.dwFlags & AVICOMPRESSF_DATARATE) == AVICOMPRESSF_DATARATE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_DATARATE\n");} + else if((opts.dwFlags & AVICOMPRESSF_INTERLEAVE) == AVICOMPRESSF_INTERLEAVE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_INTERLEAVE\n");} + else if((opts.dwFlags & AVICOMPRESSF_KEYFRAMES) == AVICOMPRESSF_KEYFRAMES){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_KEYFRAMES\n");} + else if((opts.dwFlags & AVICOMPRESSF_VALID) == AVICOMPRESSF_VALID){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_VALID\n");} + else {_snprintf(tmp, 255, "DWORD dwFlags = Unknown(%d)\n", opts.dwFlags);} + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpFormat = %d\n", opts.lpFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbFormat = %d\n", opts.cbFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpParms = %d\n", opts.lpParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbParms = %d\n", opts.cbParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwInterleaveEvery = %d\n", opts.dwInterleaveEvery); + returnValue += tmp; + + return returnValue; +} + +BOOL AVI_SetOptions(PAVISTREAM * ps, PAVISTREAM * psCompressed, LPBITMAPINFOHEADER lpbi, + const char* _compressor) +{ + + AVICOMPRESSOPTIONS opts; + AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts}; + + memset(&opts, 0, sizeof(opts)); + opts.fccType = streamtypeVIDEO; + opts.fccHandler = getFOURCC(_compressor); + //opts.fccHandler = 0; + //opts.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //opts.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //opts.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //opts.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //opts.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //opts.dwKeyFrameEvery = 5; + //opts.dwQuality + //opts.dwBytesPerSecond + //opts.dwFlags = AVICOMPRESSF_KEYFRAMES; + //opts.lpFormat + //opts.cbFormat + //opts.lpParms + //opts.cbParms + //opts.dwInterleaveEvery + + /* display the compression options dialog box if specified compressor is unknown */ + if(getFOURCC(_compressor) == NULL) + { + if (!AVISaveOptions(NULL, 0, 1, ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts)) + { + return FALSE; + } + + //printf("%s", dumpAVICOMPRESSOPTIONS(opts)); + //MessageBox(NULL, dumpAVICOMPRESSOPTIONS(opts).c_str(), "AVICOMPRESSOPTIONS", MB_OK); + } + + HRESULT hr = AVIMakeCompressedStream(psCompressed, *ps, &opts, NULL); + if (hr != AVIERR_OK) { + return FALSE; + } + + hr = AVIStreamSetFormat(*psCompressed, 0, + lpbi, // stream format + lpbi->biSize // format size + + lpbi->biClrUsed * sizeof(RGBQUAD) + ); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_SetText(PAVIFILE pfile, PAVISTREAM psText, char *szText, int width, int height, int TextHeight) +{ + // Fill in the stream header for the text stream.... + AVISTREAMINFO strhdr; + DWORD dwTextFormat; + // The text stream is in 60ths of a second.... + + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeTEXT; + strhdr.fccHandler = mmioFOURCC('D', 'R', 'A', 'W'); + strhdr.dwScale = 1; + strhdr.dwRate = 60; + strhdr.dwSuggestedBufferSize = sizeof(szText); + SetRect(&strhdr.rcFrame, 0, (int) height, + (int) width, (int) height + TextHeight); // #define TEXT_HEIGHT 20 + + // ....and create the stream. + HRESULT hr = AVIFileCreateStream(pfile, &psText, &strhdr); + if (hr != AVIERR_OK) { + return FALSE; + } + + dwTextFormat = sizeof(dwTextFormat); + hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat)); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddFrame(PAVISTREAM psCompressed, int time, LPBITMAPINFOHEADER lpbi) +{ + int ImageSize = lpbi->biSizeImage; + if (ImageSize == 0) + { + if (lpbi->biBitCount == 24) + { + ImageSize = lpbi->biWidth * lpbi->biHeight * 3; + } + } + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + time, // time of this frame + 1, // number to write + (LPBYTE) lpbi + // pointer to data + lpbi->biSize + + lpbi->biClrUsed * sizeof(RGBQUAD), + ImageSize, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddText(PAVISTREAM psText, int time, char *szText) +{ + int iLen = strlen(szText); + + HRESULT hr = AVIStreamWrite(psText, + time, + 1, + szText, + iLen + 1, + AVIIF_KEYFRAME, + NULL, + NULL); + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +BOOL AVI_CloseStream(PAVISTREAM ps, PAVISTREAM psCompressed, PAVISTREAM psText) +{ + if (ps) + AVIStreamClose(ps); + + if (psCompressed) + AVIStreamClose(psCompressed); + + if (psText) + AVIStreamClose(psText); + + + + return TRUE; +} + +BOOL AVI_CloseFile(PAVIFILE pfile) +{ + if (pfile) + AVIFileClose(pfile); + + return TRUE; +} + +BOOL AVI_Exit() +{ + AVIFileExit(); + + return TRUE; +} + + + + + + + + + + + + + + + + +/* Here are the additional functions we need! */ + + +static PAVIFILE pfile = NULL; +static PAVISTREAM ps = NULL; +static PAVISTREAM psCompressed = NULL; +static int count = 0; + + +// Initialization... +bool START_AVI(const char* file_name) +{ + if(! AVI_Init()) + { + //printf("Error - AVI_Init()\n"); + return false; + } + + if(! AVI_FileOpenWrite(&pfile, file_name)) + { + //printf("Error - AVI_FileOpenWrite()\n"); + return false; + } + + return true; +} + +bool ADD_FRAME_FROM_DIB_TO_AVI(const char* _compressor, int _frameRate, int width, int height, int bits, void* pdata) +{ + if(count == 0) + { + if(! AVI_CreateStream(pfile, &ps, _frameRate, + width*height/bits, + width, + height, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + return false; + } + + BITMAPINFOHEADER bi; + memset(&bi, 0, sizeof(bi)); + bi.biSize = sizeof(BITMAPINFOHEADER); + bi.biWidth = width; + bi.biHeight = height; + bi.biPlanes = 1; + bi.biBitCount = bits; + bi.biCompression = BI_RGB; + bi.biSizeImage = width * height * bits /8; + if(! AVI_SetOptions(&ps, &psCompressed, &bi, _compressor)) + { + return false; + } + } + + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + count, // time of this frame + 1, // number to write + pdata, + width*height/8, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + count++; + return true; +} + +//Now we can add frames +// ie. ADD_FRAME_FROM_DIB_TO_AVI(yourDIB, "CVID", 25); +bool ADD_FRAME_FROM_DIB_TO_AVI(HANDLE dib, const char* _compressor, int _frameRate) +{ + LPBITMAPINFOHEADER lpbi; + if(count == 0) + { + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_CreateStream(pfile, &ps, _frameRate, + (unsigned long) lpbi->biSizeImage, + (int) lpbi->biWidth, + (int) lpbi->biHeight, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + GlobalUnlock(lpbi); + return false; + } + + if(! AVI_SetOptions(&ps, &psCompressed, lpbi, _compressor)) + { + //printf("Error - AVI_SetOptions()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + } + + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_AddFrame(psCompressed, count * 1, lpbi)) + { + //printf("Error - AVI_AddFrame()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + count++; + return true; +} + +// The end... +bool STOP_AVI() +{ + if(! AVI_CloseStream(ps, psCompressed, NULL)) + { + //printf("Error - AVI_CloseStream()\n"); + return false; + } + + if(! AVI_CloseFile(pfile)) + { + //printf("Error - AVI_CloseFile()\n"); + return false; + } + + if(! AVI_Exit()) + { + //printf("Error - AVI_Exit()\n"); + return false; + } + + return true; +} + diff --git a/plugins/zerogs/dx/Win32/plugin.def b/plugins/zerogs/dx/Win32/plugin.def new file mode 100644 index 0000000000..49ad02b7dc --- /dev/null +++ b/plugins/zerogs/dx/Win32/plugin.def @@ -0,0 +1,31 @@ +EXPORTS + GSabout = GSabout@0 @90 + GSclose = GSclose@0 @91 + GSconfigure = GSconfigure@0 @92 + GSfreeze = GSfreeze@8 @93 + GSgetDriverInfo = GSgetDriverInfo@4 @94 + GSgifTransfer1 = GSgifTransfer1@8 @95 + GSgifTransfer2 = GSgifTransfer2@8 @96 + GSgifTransfer3 = GSgifTransfer3@8 @97 + GSinit = GSinit@0 @99 + GSirqCallback = GSirqCallback@4 @101 + GSkeyEvent = GSkeyEvent@4 @102 + GSmakeSnapshot = GSmakeSnapshot@4 @103 + GSopen = GSopen@8 @104 + GSprintf = GSprintf@0 @105 + GSread16 = GSread16@4 @106 + GSread32 = GSread32@4 @107 + GSread64 = GSread64@4 @108 + GSread8 = GSread8@4 @109 + GSreadFIFO = GSreadFIFO@4 @110 + GSreset @111 + GSshutdown = GSshutdown@0 @112 + GStest = GStest@0 @113 + GSvsync = GSvsync@0 @115 + GSwrite16 = GSwrite16@8 @117 + GSwrite32 = GSwrite32@8 @118 + GSwrite64 = GSwrite64@12 @119 + GSwrite8 = GSwrite8@8 @120 + PS2EgetLibName = PS2EgetLibName@0 @128 + PS2EgetLibType = PS2EgetLibType@0 @129 + PS2EgetLibVersion2 = PS2EgetLibVersion2@4 @130 diff --git a/plugins/zerogs/dx/Win32/ps2fx.dat b/plugins/zerogs/dx/Win32/ps2fx.dat new file mode 100644 index 0000000000000000000000000000000000000000..8189b0692c56b3fcd900b8f3f7e2e376b08eb8ba GIT binary patch literal 3457692 zcmdR%eL$sC*YJ0Bs#BfnRHyH+Q=OVVPTwITgoca|(-0FHlbMW|#)J?W8bSy$A;g4c zgh6P?=q6-@5JCuz$p~?WkeT;)tv%zupXZPFeV*r^_kHKSkMo;tUHe*l?Y-Atd!1`v z4)IpWw!$fJ)*v5bQsK(im8yW#;Qk%72bmnW=N+YH z;as?LRH-^-@?hH-e}@l%dq1Vj9lhbH38k9R?NGRO7yqFAFoUO+a>9qh9Y3K1GDpKD zb6VyYga1N5>MVwbv2YK3EL?ALQH5Mv3io-rs2cP+33m9osA-IUGHeZS5!)_-lWkm! z%<1rGn2WS`8Qc`@BJHh!d+jdL-ZNmU!$sO#1*;SnRfcZofMuC3YM6Rf!uC8DH3zSP z!wz;)4ai&ow;k@H`YB%nmlnCG0(7p0TaIy2)$m$)cCm|^N2VU0InhN8!I#2)WiF~1 z8HSWnLTOnS-5?Ni>gG1VXfxgaZwIWrMAOSAGxSx${E(G zXxv40QRe_W^#y$g{{!y*8k-<91eblQ>wE)l{(-T948vXJ|4h5!H(~3qj34CRgZuw< zQT6cqaGr~+nni|bz&%}66#e)CT;%1dW{?>-Wc*!~8QngE3qo8~BjumN{gJLx=NE8w zoU5uu<{Nk{*;O?mvkR`sU@%kXl)*W!DjEJ3ZaUCa%_B1dHx_U&%9%o{_6S#1gFZjQ z<3+Bj4gRN5UhJx>k^ci8JKj}n_$O>x;wtT(hx<=)mG&~_RNLuVH>Q~?taMeQ*xwzt zt#Xxd+-)sGHV*m||AnuM8_YIcLG>O&u< zqUyO(*BK7awYsVyWFp{!HrfS8!du&2)gbcmaNT{bsufOvOtsr+p+Q&GjLd;>>9DKnK;|HL`dwEQMxFVF z{D-s)W~!^APh6Fa`Wxw<@(EY*|LftNNo>V8O;wG%_y_u5WAJYJf@^PpZ9k#|OtV$b zKdB#?7I^SiSMmQh!R9~c3uG{Xn%IMFxz`{Qom>(GhMk#`@v+zX+@2X)LzgZt%%&;{WLe zV|<0k%}u2Q}0+{FLC2X|iV zCboSa?z@z0(VuQpRaffvehS;J(d`|Fi>}q}{S5BBUbmO-RIN9=iT~dTPcoql|NjlV z^)5H@|3)`=-{&U&{|DIdkem2_x>-$Zb`$?U14ljPCjS2?xCtj?`2RV$@fkPq|G&e< z&%25Lr~6gwi`uq-!lr+?iT`)SG?v%g#Q(d&VQ;#L|2M&1Z@Y>AXNahZ_uOQjTHx-F z=of733m1QmO|U=1MOA+7CjQ?a?wUdeWJ2JYAGJ&<+=O#8{J$|qqvqVi|1+f2#Gh{B z{~1Qi4U>%3IN0i868|3$S9zJl|0fvoOj5)Dr@~o*Ch`Aia7n01>Sw5_$q1A9|8%%3 z#w7kf56*X(#Q!tw)NHCr#?^sva+XQ_|3Pr`0VeVPhrvAsCh`A=!=p!-#Qzt<^@~j6 z{~4O9=vb5Ze`BqkJVDoaEF4y55`VZD9y*nF@qHYh&SfU?)eKoxvfLzoZwWlO(j@-B z4DMS^yXe!U@aP35@&6TuOr1&mzcH+bFE@$*KNBuluj@Pup1am0{+}VPs&6)l|6c`9 z-%f@6zuMr9vN&NqXaLpEM$Tw3$smD#?|1X29pVsZY z9Pa4T?KRfvl78LZD`3Zf)~yL1dDSHTe*@gb;5Xt5riz+*SKHw_xcVcL_iXOy zbMqE>@@x8z?^ZsYyG-K$Z-tw_Gl~B<##X^kx=yB(YW~$E{{L>c^bgv__dR?H_n5^0 zKM0#l?&AM9!EIjd;{UtgPG5KN|4ctM8sIMezXu)$mTzx9_A}gN{P@5H%iWdXn=SC<3hIYx zo*G{1uAE%!2hXi`SGBM|T)l=mnZGu;>mqm6#dk2D;>+D-%!I(TSGlWd!T@Sgd1~>t> zZ*do&X~bc5TisO=xW1mq@Jq2*(q`S<`L*dfh z^cV7n!Gk~0MwqTu_5Y;5_%7sA`@7cR2zcvWY>s`7hV29xO~@YucUe57EyZxJzlW@| z3!Y6)EJq<&<| z;QA~NvDH#|IL||IYjrw2w$MYy|1#KexQ80x+6qJF2n4VX!%Gbpc}QQJ30sf#5L=xE zw;xZPh*iPUOFUFR-{NWr24nfU+DZfymdQmk)4x97+9iQqMPc=uK zGjQc^v;`f0f+zpF{?`I`2!veFiT(j z3AcopRUy~T!^7cbi39(Fi=)kIkbCWcE%9dAzu;2UbP{z^kBLuvx>?pTcX%|{tOk(x zfZOtEII^AwA8M9yiwjocN10{s;{_KkHmf$o{NT}(^}TS%s{K^6DnTD(PEMX~R?Tn# zTyv&bjZl9eT(H8dreR#RO0MQwzQg!TU!e62hlkghWo|~md6$?awv2?wF4NcI*45xu zW*Gy~hJ2H5S3F#QqgndGaQ7{(X4QcX#ym+zVI$5=gjKs)*=b`EY`+&fz$^)>;z6_Y zmlH1AjQ)J5^BI4_EHOd`Jk?7Zk7W|lR1A)NIUHmCkW4EbGVWo5ry2si&gId(IanUSB(vj062 z?)rs$u?8IlH_e$8Bz`y!wpqNC8GQ`D5asWsY%og{ zdj~J^w|x)pH$X|&bzTxDTnM*c?j`ZV zI=HscOMG%2JbI0n_`{3fqU*fG$FlS)XN#BYPcMNTw^Gix;ZrQ_USe04VO4&gm-x&p zVdo|*0}JFU7D?*TS7Idg=8MZhBekV2sPzSLsLWb3I)9 zhL`xa8{n$9y(Ip<5w3opK4Sc|8vKcus-*3=!b6{X$^QK|xc5u+XZ+j__e@ehGRByW z`qoS0kUQXx@3n3$|H?e8`}ZEBd`|a~F(&%|^iszD@?LmqkM4{6;1)M;vHAUQp&918 zi_ff|x6J#8U`w#Ktcef9J>lNs_a1@EW4vYVcEb%0Z<#ln;oekl)q#BoFH~u+zV-=t z<{)p;VJjSU2=eGd*rCb}^OjiUDcE$BxA?lJ;lX3P)iB?Ed|FTNmVClCxMYd9_~hr| zwo|-iul)i%bsF;6ryuS;(_4+hFT$-Wyrqtp;o{ZavaY=X=dbaWJ~DhJs-t(5Y?rXT{LvNWolW^3h+Ri)S@h`lU(TBVFG<~Dn z{++?!X?><)%a7i&wtf$H{H*o)0q*|ITgLW}M)^Fp<$IP-i<^%!=FKmBEZ#n{7W@j^ z{C&j#{{|=9d{hhHb9{Oud{jN(zw>d%`KU4MLwKi5sXo&7y|6XYM{HvBL068CtQ{_J z;ekGq&vAvz58)Rj`peDWLhj4A@u@tS^9hB+ zuJDokKonfoqx*{xSxviJB;H#DH(4wa4;&451z2P)J_a5Mv52oKhU=m& z;zy5#O%98iVf>r`&pIt~FT!gTmSd6JX(>E-fJODvu9M*UgDnyho(y*%W|6V91Rgkw z`|@4RXJWBM_Q9vY_EL-FXHJKwmRQsX^(=$?PPItvQ30FIu*g_C1I|C&qKq+hHlLz% zEz%c+@~ZCwi<;-!D!BJTi!x!)bBywfEs`H2#8>$Z78y&c;Li0H>8~1iw%MYLd3-)R zc8f*TU{6ASRdk0%_KR!a{=2aQGPQ8e0~R$7uZ5etEvkU=b1^*lq`ucBaM5!XWk!d3 zxa0+k?6oh2D_*jw7V2jU!M;!Hf4NbzLNi8>!M11d?oJM2>1E>O8%!Et_t=Q9qxk5 zBYh?Rb06H0ps&3j?pok0ZRs>*QjtfW2jG%)U&;SG2sdT>O8mA7RtNe@EY=N|75GZd zVKdxb=qvf3EpYWwzLGO}6s|uSdD_(j4=?tWnCdaO>O^0OF`t6Fmio#bmhF>@I^9?D zKfSR14C-erJ!8mM`bxa_EIeK1D{JC&aNoI(*S7iq?iuiv zIQA2`?=@e^|9lEh@9>rU&$uD;7WHGF&kP>XeepRwGpcR%1zi8J?ypIB_zPdj|LlaD zchYw5`wcwwt*^vgyWrvL<4PCtMorCo$)oQ6A|h`Jdn6FuR}3g+E}G;3qkXKjGvgv#{qt_hjoLU3;iVjV}gqhrGD(=4tEv$Nxa7vR~0StlXbxp zPF_qo@}@${z|O_+hf&Q<0ttaw#O>$ zB0t%`gu=a->b8Wz;|+eY$7I{AiW>bS=8S-6n*3x9ii9Vw_mjBJ4!5`Jw#UJyJN#sB z#=~iv~+nxqTJ)!k+!bMN{$zFqPx$1sK z>yrVOJ?|&^pG-skCF;aJdGOX({UkO%03LnQPxeFy!VM$z9rig0uKEDokk5zPKJ}CR z$ieW$mwuA}ISj7Yt?zX>Z2r+t@;`-e!OwoO-#G&A`2{;r=aF#LAAYizAswLd_i`=u z7sHe8{-WoxhP=1G%uUh+YTnmh@;}GH%>n*$Z3$cv;xBeS9xjRWmv)g#P!n&=$T|^65NB-)j}zz1m-5RMHmYVErZkb1rPU z&|hNC)o|D){<7Ae2NyT^OYB(-7hXeKu;E&G@H&5)n-{_(H~7n5gOrB~yP5itse`+3 z^OrGs5nQ&>U-CbsKUD9%{?Zqh!!-~3Oa8~m<@G#7TbN&0z{#8aWp8^WJpC9pp-$2z zYWOMYq`!>4cl|bhS<5!Sy)R)~WUhtl2K^ z@8|knx4`vZ`%C_(6(0P?U-mn-?CI5399QC8W>}76;&9huf{q6AZA6n15;GVty zGB@vrZEjY{|J(!jd06FIWAE4HW0f&L`bPCwt3rCTP6SV z5Im7!m3Z%ASfyAc|MLi3kYSbn>VfkPu*zEY7~Fq|RrUyv!$XBuiNQz-DcjLj8Mj;E z?h>oyf1ZTPmslnL^DLZSq3`vaQNG+NF=`*I&ap~tzYU(Owo1%NI!ReCuuA^t1w($F zRq{UraP?)B(?|b+w_a(L{Ljm9(|Yd3`t=H2)nt|Y&mi32Y?V0VRoHQpRpNvlaQ*F8 zi67pCXE$O)#>_B0e>Zl6--508S;gPJ4R<_<4Y}_-aQ-7O{WS`YK4z8t&j$uSjjfRR z5U%LMCh$k_Oh0x*ehi*}89Trq!%=ToWek1}cfPBy{Q^$@Q0p)O7krF7`g{pjj9VpE z`3jz$z=qWSHQce&D*1#dxOAFvLix9b%#2lh@^08MOaD^OcW~uz$Rjfi+vcq@N4|&0 zRDi5Iq}7N`10;U!u=BE?O8MYcZ)hwY4xn@;@GMmdTgzLTvko?af@X$`=(bL%5wCxU%{12&2Rr_Or#0f{j$-f53x^@&C_NVTnB13*p zfcQhwohr&TP<-ss273ld{^uCjX`!5Ws>I-+K=HSvK~-ybp!mHL;D(q$8E+@TbqRs8 z#*rRXlPQ6c|2YY+&I*+L&na-}!GW@#o(h*77AQKD!=pz8O0I(xs;XWTDE{qqxNdQv zOLh<+P>V7Sr#ZZIU622Gf?8X6|m#%K$$yL@cha^u`{Vy)qh@~ z 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

=J*c6EkPKB#ZNRhar94;+Ok+}3U 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šy&l~ZSM&KdGv=5E1Hc~o2(X%s)lZ=5He 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 SdnNM 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

C?IwZ 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 + + + + + + + diff --git a/plugins/zerogs/dx/Win32/vsprops/postBuild.tmpl b/plugins/zerogs/dx/Win32/vsprops/postBuild.tmpl new file mode 100644 index 0000000000..b0f9fb472f --- /dev/null +++ b/plugins/zerogs/dx/Win32/vsprops/postBuild.tmpl @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%\%3-r$WCREV$$WCMODS?m:$%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/zerogs/dx/Win32/vsprops/postBuild.unknown b/plugins/zerogs/dx/Win32/vsprops/postBuild.unknown new file mode 100644 index 0000000000..360b05cad5 --- /dev/null +++ b/plugins/zerogs/dx/Win32/vsprops/postBuild.unknown @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%%3%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/zerogs/dx/Win32/vsprops/preBuild.cmd b/plugins/zerogs/dx/Win32/vsprops/preBuild.cmd new file mode 100644 index 0000000000..fea16bd143 --- /dev/null +++ b/plugins/zerogs/dx/Win32/vsprops/preBuild.cmd @@ -0,0 +1,20 @@ +@echo off + +rem Usage: preBuild.cmd ProjectSrcDir VspropsDir +rem +rem ProjectSrcDir - $(ProjectDir)\.. - Directory of project source code. +rem VspropsDir - $(PrjectDir)\vsprops - Directory of this script and its counterparts. + +SubWCRev.exe %1 %2\svnrev_template.h %1\svnrev.h +if not ERRORLEVEL 0 ( + echo Automatic revision update unavailable, using generic template instead. + echo You can safely ignore this message - see svnrev.h for details. + copy /Y %2\svnrev_unknown.h %1\svnrev.h + copy /Y %2\postBuild.unknown %2\postBuild.cmd +) else ( + SubWCRev.exe %1 %2\postBuild.tmpl %2\postBuild.cmd +) + +rem Clear the error level -- this allows compilation to continue if SubWCRev failed. + +set ERRORLEVEL=0 diff --git a/plugins/zerogs/dx/Win32/vsprops/svnrev_template.h b/plugins/zerogs/dx/Win32/vsprops/svnrev_template.h new file mode 100644 index 0000000000..afab6c4fd1 --- /dev/null +++ b/plugins/zerogs/dx/Win32/vsprops/svnrev_template.h @@ -0,0 +1,18 @@ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ +#define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/zerogs/dx/Win32/vsprops/svnrev_unknown.h b/plugins/zerogs/dx/Win32/vsprops/svnrev_unknown.h new file mode 100644 index 0000000000..a2a3703186 --- /dev/null +++ b/plugins/zerogs/dx/Win32/vsprops/svnrev_unknown.h @@ -0,0 +1,23 @@ +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 +#define SVN_MODS "" \ No newline at end of file diff --git a/plugins/zerogs/dx/Win32/zerogs.bmp b/plugins/zerogs/dx/Win32/zerogs.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c4a563f03e97dbb180c469f6ccc06dc0c12f63a8 GIT binary patch literal 921654 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 literal 0 HcmV?d00001 diff --git a/plugins/zerogs/dx/Win32/zerogs.rc b/plugins/zerogs/dx/Win32/zerogs.rc new file mode 100644 index 0000000000..e91d4d21c4 --- /dev/null +++ b/plugins/zerogs/dx/Win32/zerogs.rc @@ -0,0 +1,235 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resrc1.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "resource.h" +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_ZEROGSLOGO BITMAP "zerogs.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// RCDATA +// + +IDR_SHADERS RCDATA "ps2fx.dat" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 427, 385 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + CONTROL "Interlace Enable (toggle with F5)\n there are 2 modes + interlace off",IDC_CONFIG_INTERLACE, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,7,134,18 + CONTROL "Bilinear Filtering (Shift+F5)\n Best quality is on, turn off for speed.",IDC_CONFIG_BILINEAR, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,31,135,18 + CONTROL "None",IDC_CONFIG_AANONE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,19,92,34,11 + CONTROL "2X",IDC_CONFIG_AA2,"Button",BS_AUTORADIOBUTTON,69,92,26,11 + CONTROL "4X",IDC_CONFIG_AA4,"Button",BS_AUTORADIOBUTTON,111,92,28,11 + CONTROL "8X",IDC_CONFIG_AA8,"Button",BS_AUTORADIOBUTTON,69,108,26,11 + CONTROL "16X",IDC_CONFIG_AA16,"Button",BS_AUTORADIOBUTTON,111,108,28,11 + CONTROL "Wireframe rendering (F7)",IDC_CONFIG_WIREFRAME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,129,93,10 + CONTROL "Capture Avi (zerogs.avi) (F12)",IDC_CONFIG_CAPTUREAVI, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,145,109,10 + CONTROL "Save Snapshots as BMPs (default is JPG)",IDC_CONFIG_BMPSS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,162,147,10 + CONTROL "Fullscreen (Alt+Enter)\n to get out press Alt+Enter again",IDC_CONFIG_FULLSCREEN, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,178,146,17 + CONTROL "640 x 480",IDC_CONF_WIN640,"Button",BS_AUTORADIOBUTTON | WS_GROUP,15,233,59,8 + CONTROL "800 x 600",IDC_CONF_WIN800,"Button",BS_AUTORADIOBUTTON,78,233,59,8 + CONTROL "1024 x 768",IDC_CONF_WIN1024,"Button",BS_AUTORADIOBUTTON,15,246,59,8 + CONTROL "1280 x 960",IDC_CONF_WIN1280,"Button",BS_AUTORADIOBUTTON,78,246,59,8 + CONTROL "960 x 540",IDC_CONF_WIN960W,"Button",BS_AUTORADIOBUTTON,14,270,53,8 + CONTROL "1280 x 720",IDC_CONF_WIN1280W,"Button",BS_AUTORADIOBUTTON,77,270,53,8 + CONTROL "1920 x 1080",IDC_CONF_WIN1920W,"Button",BS_AUTORADIOBUTTON,14,283,53,8 + DEFPUSHBUTTON "OK",IDOK,7,364,50,14 + PUSHBUTTON "Cancel",IDCANCEL,94,364,50,14 + GROUPBOX "Anti-aliasing for sharper graphics",IDC_STATIC,7,57,136,66 + GROUPBOX "Default Window Size (no speed impact)",IDC_STATIC,7,223,141,76 + LTEXT "Show Frames Per Second (Shift+F7)",IDC_STATIC,7,314,140,10 + GROUPBOX "Advanced Options",IDC_STATIC,152,7,268,371 + LTEXT "Each option is presented with a unique ID in hex. In order to preserve options across games, go into the game's patch (.pnach) file and type\n zerogs=IDS\nwhere IDS is the OR all of the values in hex for every option you want enabled. ",IDC_STATIC,161,16,252,33 + PUSHBUTTON "Use Defaults (recommended)",IDC_CONF_DEFAULT,159,76,151,14 + CONTROL "Disable alpha testing - 00080000",IDC_CONFOPT_00080000, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,159,104,119,10 + CONTROL "Disable stencil buffer - 00002000\nusually safe to do for simple scenes",IDC_CONFOPT_00002000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,159,114,118,22 + CONTROL "No target CLUT - 00001000\n(use on RE4, or foggy scenes)",IDC_CONFOPT_00001000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,169,120,24 + CONTROL "Disable depth updates - 00000200",IDC_CONFOPT_00000200, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,158,161,125,10 + CONTROL "FFX hack - 00000080\nshows missing geometry",IDC_CONFOPT_00000080, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,190,121,17 + CONTROL "Exact color testing - 00000020\nfixes overbright or shadow/black artifacts (crash n burn)",IDC_CONFOPT_00000020, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,209,119,25 + CONTROL "Tex Target checking - 00000001\nlego racers",IDC_CONFOPT_00000001, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,233,123,22 + CONTROL "Interlace 2X - 00000004\nfixes 2x bigger screen (gradius3)",IDC_CONFOPT_00000004, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,254,119,20 + CONTROL "32 bit render targets - 00200000",IDC_CONFOPT_00200000, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,285,93,117,10 + CONTROL "No Vertical Stripes - 00004000\n try when there's a lot of garbage on screen",IDC_CONFOPT_00004000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,138,111,28 + CONTROL "No depth resolve - 00008000\nmight give z buffer artifacts",IDC_CONFOPT_00008000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,164,121,19 + CONTROL "full 16 bit resolution - 00010000\nuse when half the screen is missing, etc",IDC_CONFOPT_00010000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,185,125,23 + CONTROL "Auto Reset Targs - 00000002\nshadow hearts, samurai warriors (use when game is slow and toggling AA fixes it)",IDC_CONFOPT_00000002, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,283,212,124,32 + CONTROL "Tex Alpha Hack - 00000008\nnightmare before christmas",IDC_CONFOPT_00000008, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,286,252,125,17 + EDITTEXT IDC_CONFOPT_IDS,372,364,48,14,ES_AUTOHSCROLL | ES_READONLY + CONTROL "Resolve Hack #1 - 00000400\nspeeds some games (kingdom hearts)",IDC_CONFOPT_00000400, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,270,135,19 + CONTROL "Resolve Hack #2 - 00000800\nshadow hearts, urbz",IDC_CONFOPT_00000800, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,276,117,17 + CONTROL "Resolve Hack #3 - 00020000\nneopets",IDC_CONFOPT_00020000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,292,125,17 + CONTROL "Fast Update - 00040000\nspeeds some games (okami)",IDC_CONFOPT_00040000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,297,125,17 + PUSHBUTTON "Compute OR of IDS",IDC_CONFOPT_COMPUTEOR,287,364,73,14 + LTEXT "Important options are listed first. Note, setting option here means that they will be ADDED to whatever options are set in each pnach file.",IDC_STATIC,159,50,252,23 + CONTROL "No target resolves - 00000010\nStops all resolving of targets (try this first for really slow games)",IDC_CONFOPT_00000010, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,104,111,33 + CONTROL "Disable Multiple RTs - 00100000",IDC_CONFOPT_00100000, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,159,91,119,10 + CONTROL "No color clamping - 00000040\nSpeeds games up but might be too bright or too dim",IDC_CONFOPT_00000040, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,157,137,123,22 + CONTROL "Specular Highlights - 01000000\nMakes xenosaga graphics faster by removing highlights",IDC_CONFOPT_01000000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,313,125,25 + CONTROL "Partial Targets - 02000000\nReduces artifacts and speeds up some games (mgs3)",IDC_CONFOPT_02000000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,158,319,125,24 + CONTROL "Partial Depth - 04000000\nTries to save the depth target as much as possible (mgs3)",IDC_CONFOPT_04000000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,159,347,125,24 + LTEXT "shortcuts: F6 - next, Shift+F6 - prev",IDC_STATIC,24,71,116,11 + CONTROL "16:9 widescreen (Shift+F9)",IDC_CONFIG_WIDESCREEN, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,199,146,17 + LTEXT "Widescreen:",IDC_STATIC,14,257,89,11 + CONTROL "Relaxed Depth - 08000000\nMight show hidden sprites (xenosaga text)",IDC_CONFOPT_08000000, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,285,338,125,25 +END + +IDD_ABOUT DIALOGEX 0, 0, 182, 78 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About ZeroGS KSOMOS...." +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,57,50,14 + LTEXT "ZeroGS v0.97.1",IDC_STATIC,7,7,160,11 + LTEXT "Thanks to Gabest for some SSE optimizations",IDC_ABOUTTEXT,7,39,152,12 + LTEXT "Author: zerofrog(@gmail.com)",IDC_STATIC,8,23,144,14 +END + +IDD_LOGGING DIALOG 0, 0, 152, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,40,35,50,14 + PUSHBUTTON "Cancel",IDCANCEL,95,35,50,14 + CONTROL "Log",IDC_LOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,60,15,28,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 420 + TOPMARGIN, 7 + BOTTOMMARGIN, 378 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 175 + TOPMARGIN, 7 + BOTTOMMARGIN, 71 + END + + IDD_LOGGING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 145 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resrc1.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""resource.h""\r\n" + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/zerogs/dx/Win32/zerogs_2008.vcproj b/plugins/zerogs/dx/Win32/zerogs_2008.vcproj new file mode 100644 index 0000000000..c4cec906d6 --- /dev/null +++ b/plugins/zerogs/dx/Win32/zerogs_2008.vcproj @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/zerogs/dx/ZeroGSShaders/ZeroGSShaders.vcproj b/plugins/zerogs/dx/ZeroGSShaders/ZeroGSShaders.vcproj new file mode 100644 index 0000000000..e4e6d14f9a --- /dev/null +++ b/plugins/zerogs/dx/ZeroGSShaders/ZeroGSShaders.vcproj @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/zerogs/dx/ZeroGSShaders/copytozerogs.bat b/plugins/zerogs/dx/ZeroGSShaders/copytozerogs.bat new file mode 100644 index 0000000000..0e871997fa --- /dev/null +++ b/plugins/zerogs/dx/ZeroGSShaders/copytozerogs.bat @@ -0,0 +1 @@ +copy .\Release\ZeroGSShaders.exe ..\ZeroGS\ \ No newline at end of file diff --git a/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp b/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp new file mode 100644 index 0000000000..99a631081f --- /dev/null +++ b/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.cpp @@ -0,0 +1,407 @@ +// Builds all possible shader files from ps2hw.fx and stores them in +// a preprocessed database +#include + +#include +#include +#include + +#define SAFE_RELEASE(x) { if( (x) != NULL ) { (x)->Release(); x = NULL; } } + +#include +#include + +using namespace std; + +#include "zerogsshaders.h" + +char* srcfilename = "ps2hw.fx"; +char* dstfilename = "ps2hw.dat"; +DWORD dwFlags = 0; + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +struct SHADERINFO +{ + DWORD type; // 1 - ps, 0 - vs + LPD3DXBUFFER pbuf; +}; + +map mapShaders; + +class ZeroGSShaderInclude : public ID3DXInclude +{ +public: + int context; + int ps2x; // if 0, ps20 only + char* pEffectDir; + + STDMETHOD(Open)(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) + { + const char* pfilename = pFileName; + char strfile[255]; + if( strstr(pFileName, "ps2hw_ctx") != NULL ) { + + _snprintf(strfile, 255, "%sps2hw_ctx%d.fx", pEffectDir, context); + pfilename = strfile; + } +// else if( strstr(pFileName, "ps2hw_ps2x") != NULL ) { +// _snprintf(strfile, 255, "%sps2hw_ps2%c.fx", pEffectDir, ps2x?'x':'0'); +// pfilename = strfile; +// } + else if( strstr(pFileName, "ps2hw.fx") != NULL ) { + _snprintf(strfile, 255, "%s%s", pEffectDir, pFileName); + pfilename = strfile; + } + + FILE* f = fopen(pfilename, "rb"); + + if( f == NULL ) + return E_FAIL; + + fseek(f, 0, SEEK_END); + DWORD size = ftell(f); + fseek(f, 0, SEEK_SET); + char* buffer = new char[size+1]; + fread(buffer, size, 1, f); + buffer[size] = 0; + + *ppData = buffer; + *pBytes = size; + fclose(f); + + return S_OK; + } + + STDMETHOD(Close)(LPCVOID pData) + { + delete[] (char*)pData; + return S_OK; + } +}; + +void LoadShader(int index, const char* name, const char* pshader, D3DXMACRO* pmacros, ID3DXInclude* pInclude) +{ + LPD3DXBUFFER pShader = NULL, pError = NULL; + + HRESULT hr = D3DXCompileShaderFromFile(srcfilename, pmacros, pInclude, name, pshader, dwFlags, &pShader, &pError, NULL); + + if( FAILED(hr) ) + { + printf("Failed to load %s\n%s\n", name, pError->GetBufferPointer()); + SAFE_RELEASE(pShader); + SAFE_RELEASE(pError); + return; + } + + SAFE_RELEASE(pError); + + if( mapShaders.find(index) != mapShaders.end() ) { + printf("two shaders share the same index %d\n", index); + exit(0); + } + + SHADERINFO info; + info.type = name[0] == 'p' ? 0x80000000 : 0; + info.pbuf = pShader; + mapShaders[index] = info; +} + +int main(int argc, char** argv) +{ + printf("usage: [src] [dst] [opts]\n"); + + if( argc >= 2 ) srcfilename = argv[1]; + if( argc >= 3 ) dstfilename = argv[2]; + if( argc >= 4 ) { + dwFlags = atoi(argv[3]); + } + + FILE* fsrc = fopen(srcfilename, "r"); + if( fsrc == NULL ) { + printf("cannot open %s\n", srcfilename); + return 0; + } + fclose(fsrc); + + LoadShader(SH_BITBLTVS, "BitBltVS", "vs_2_0", NULL, NULL); + LoadShader(SH_BITBLTVS|SH_30, "BitBltVS", "vs_3_0", NULL, NULL); + LoadShader(SH_BITBLTPS, "BitBltPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHPS, "BitBltDepthPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHMRTPS, "BitBltDepthMRTPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHTEXPS, "BitBltDepthTexPS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTDEPTHTEXMRTPS, "BitBltDepthTexMRTPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCTARGPS, "CRTCTargPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCPS, "CRTCPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTC24PS, "CRTC24PS", "ps_2_0", NULL, NULL); + LoadShader(SH_ZEROPS, "ZeroPS", "ps_2_0", NULL, NULL); + LoadShader(SH_ZEROPS|SH_30, "ZeroPS", "ps_3_0", NULL, NULL); + LoadShader(SH_BASETEXTUREPS, "BaseTexturePS", "ps_2_0", NULL, NULL); + LoadShader(SH_BITBLTAAPS, "BitBltPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCTARGINTERPS, "CRTCTargInterPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTCINTERPS, "CRTCInterPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CRTC24INTERPS, "CRTC24InterPS", "ps_2_0", NULL, NULL); + LoadShader(SH_CONVERT16TO32PS, "Convert16to32PS", "ps_2_0", NULL, NULL); + LoadShader(SH_CONVERT32TO16PS, "Convert32to16PS", "ps_2_0", NULL, NULL); + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + // load the texture shaders + char str[255], strdir[255]; + + strcpy(strdir, srcfilename); + int i = (int)strlen(strdir); + while(i > 0) { + if( strdir[i-1] == '/' || strdir[i-1] == '\\' ) + break; + --i; + } + + strdir[i] = 0; + + ZeroGSShaderInclude inc; + inc.pEffectDir = strdir; + + D3DXMACRO macros[10]; + memset(macros, 0, sizeof(macros)); + + macros[0].Name = "WRITE_DEPTH"; + macros[0].Definition = "1"; + + for(i = 0; i < ARRAYSIZE(vsshaders); ++i) { + for(int vs30 = 0; vs30 < 2; ++vs30 ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + inc.context = 0; + LoadShader(vsshaders[i]|(vs30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0), pvsshaders[i], vs30 ? "vs_3_0" : "vs_2_0", writedepth ? macros : NULL, &inc); + inc.context = 1; + LoadShader(vsshaders[i]|(vs30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0)|SH_CONTEXT1, pvsshaders[i], vs30 ? "vs_3_0" : "vs_2_0", writedepth ? macros : NULL, &inc); + } + } + } + + const int psshaders[2] = { SH_REGULARPS, SH_REGULARFOGPS }; + const char* ppsshaders[2] = { "RegularPS", "RegularFogPS" }; + + for(i = 0; i < ARRAYSIZE(psshaders); ++i) { + for(int ps30 = 0; ps30 < 2; ++ps30 ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + LoadShader(psshaders[i]|(ps30?SH_30:0)|(writedepth?SH_WRITEDEPTH:0), ppsshaders[i], ps30 ? "ps_3_0" : "ps_2_0", writedepth ? macros : NULL, NULL); + } + } + } + + printf("creating shaders, note that ps2hw_ctx0.fx, and ps2hw_ctx1.fx are required\n"); + + for(int texwrap = 0; texwrap < NUM_TEXWRAPS; ++texwrap ) { + + int macroindex = 0; + memset(macros, 0, sizeof(macros)); + + if( g_pPsTexWrap[texwrap] != NULL ) { + macros[0].Name = g_pPsTexWrap[texwrap]; + macros[0].Definition = "1"; + macroindex++; + } + + for(int context = 0; context < 2; ++context) { + inc.context = context; + + for(int texfilter = 0; texfilter < NUM_FILTERS; ++texfilter) { + for(int fog = 0; fog < 2; ++fog ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + + if( writedepth ) { + macros[macroindex].Name = "WRITE_DEPTH"; + macros[macroindex].Definition = "1"; + macroindex++; + } + else { + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + for(int testaem = 0; testaem < 2; ++testaem ) { + + if( testaem ) { + macros[macroindex].Name = "TEST_AEM"; + macros[macroindex].Definition = "1"; + macroindex++; + } + else { + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + for(int exactcolor = 0; exactcolor < 2; ++exactcolor ) { + + if( exactcolor ) { + macros[macroindex].Name = "EXACT_COLOR"; + macros[macroindex].Definition = "1"; + macroindex++; + } + else { + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + // 32 + sprintf(str, "Texture%s%d_32PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + if( macros[macroindex].Name != NULL ) + printf("error[%d] %s: %d %d %d %d!\n", macroindex, macros[macroindex].Name, texfilter, fog, writedepth, testaem); + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + if( texfilter == 0 ) { + // tex32 + sprintf(str, "Texture%s%d_tex32PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + // clut32 + sprintf(str, "Texture%s%d_clut32PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + // tex32to16 + sprintf(str, "Texture%s%d_tex32to16PS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + if( texfilter == 0 && exactcolor == 0 ) { + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20), str, g_pShaders[SHADER_20], macros, &inc); + } + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + + // tex16to8h + sprintf(str, "Texture%s%d_tex16to8hPS", fog?"Fog":"", texfilter); + inc.ps2x = 0; + + macros[macroindex].Name = "ACCURATE_DECOMPRESSION"; + macros[macroindex].Definition = "1"; + + inc.ps2x = 1; + + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20b), str, g_pShaders[SHADER_20b], macros, &inc); + + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_20a), str, g_pShaders[SHADER_20a], macros, &inc); + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_30), str, g_pShaders[SHADER_30], macros, &inc); + } + } + + --macroindex; + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + --macroindex; + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + + --macroindex; + macros[macroindex].Name = NULL; + macros[macroindex].Definition = NULL; + } + } + } + } + + // create the database + FILE* fdst = fopen(dstfilename, "wb"); + if( fdst == NULL ) { + printf("failed to open %s\n", dstfilename); + return 0; + } + + DWORD num = (DWORD)mapShaders.size(); + fwrite(&num, 4, 1, fdst); + + i = 0; + DWORD totaloffset = 4+sizeof(SHADERHEADER)*num; + for(map::iterator it = mapShaders.begin(); it != mapShaders.end(); ++it, ++i) { + SHADERHEADER h; + h.index = it->first | it->second.type; + h.offset = totaloffset; + h.size = it->second.pbuf->GetBufferSize(); + + fseek(fdst, 4+i*sizeof(SHADERHEADER), SEEK_SET); + fwrite(&h, sizeof(SHADERHEADER), 1, fdst); + + fseek(fdst, totaloffset, SEEK_SET); + fwrite(it->second.pbuf->GetBufferPointer(), it->second.pbuf->GetBufferSize(), 1, fdst); + + totaloffset += it->second.pbuf->GetBufferSize(); + it->second.pbuf->Release(); + } + + fclose(fdst); + + printf("wrote %s\n", dstfilename); + + return 0; +} diff --git a/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.h b/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.h new file mode 100644 index 0000000000..a3742f6931 --- /dev/null +++ b/plugins/zerogs/dx/ZeroGSShaders/zerogsshaders.h @@ -0,0 +1,118 @@ +#define NUM_FILTERS 2 // texture filtering +#define NUM_TYPES 5 // types of texture read modes +#define NUM_TEXWRAPS 4 // texture wrapping + +#define NUM_SHADERS (NUM_FILTERS*NUM_TYPES*NUM_TEXWRAPS*32) // # shaders for a given ps + +#define SHADER_20 0 +#define SHADER_20a 1 +#define SHADER_20b 2 +#define SHADER_30 3 + +// ps == 0, 2.0 +// ps == 1, 2.0a, nvidia +// ps == 2, 2.0b, ati +const static char* g_pShaders[4] = { "ps_2_0", "ps_2_a", "ps_2_b", "ps_3_0" }; +const static char* g_pPsTexWrap[] = { "REPEAT", "CLAMP", "REGION_REPEAT", NULL }; +const static char* g_pTexTypes[] = { "32", "tex32", "clut32", "tex32to16", "tex16to8h" }; + +#define TEXWRAP_REPEAT 0 +#define TEXWRAP_CLAMP 1 +#define TEXWRAP_REGION_REPEAT 2 +#define TEXWRAP_REPEAT_CLAMP 3 + +inline int GET_SHADER_INDEX(int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int context, int ps) +{ + return type + texfilter*NUM_TYPES + NUM_FILTERS*NUM_TYPES*texwrap + NUM_TEXWRAPS*NUM_FILTERS*NUM_TYPES*(fog+2*writedepth+4*testaem+8*exactcolor+16*context+32*ps); +} + +static HRESULT LoadShaderFromType(const char* srcfile, int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int ps, DWORD flags, + IDirect3DDevice9* pd3dDevice, ID3DXInclude* pInclude, IDirect3DPixelShader9** pps) +{ + assert( texwrap < NUM_TEXWRAPS); + assert( type < NUM_TYPES ); + + char str[255]; + sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); + + LPD3DXBUFFER pShader = NULL, pError = NULL; + SAFE_RELEASE(*pps); + + vector macros; + D3DXMACRO dummy; dummy.Definition = NULL; dummy.Name = NULL; + if( g_pPsTexWrap[texwrap] != NULL ) { + D3DXMACRO m; + m.Name = g_pPsTexWrap[texwrap]; + m.Definition = "1"; + macros.push_back(m); + } + if( writedepth ) { + D3DXMACRO m; + m.Name = "WRITE_DEPTH"; + m.Definition = "1"; + macros.push_back(m); + } + if( testaem ) { + D3DXMACRO m; + m.Name = "TEST_AEM"; + m.Definition = "1"; + macros.push_back(m); + } + if( exactcolor ) { + D3DXMACRO m; + m.Name = "EXACT_COLOR"; + m.Definition = "1"; + macros.push_back(m); + } + + macros.push_back(dummy); + HRESULT hr = D3DXCompileShaderFromFile(srcfile, ¯os[0], pInclude, str, g_pShaders[ps], flags, &pShader, &pError, NULL); + + if( FAILED(hr) ) + { + printf("Failed to load %s\n%s\n", str, pError->GetBufferPointer()); + SAFE_RELEASE(pShader); + SAFE_RELEASE(pError); + return hr; + } + + DWORD* ptr = (DWORD*)pShader->GetBufferPointer(); + hr = pd3dDevice->CreatePixelShader(ptr, pps); + SAFE_RELEASE(pShader); + SAFE_RELEASE(pError); + + return hr; +} + +struct SHADERHEADER +{ + DWORD index, offset, size; // if highest bit of index is set, pixel shader +}; + +#define SH_30 0x4000 // or for vs3.0 shaders +#define SH_WRITEDEPTH 0x2000 // depth is written +#define SH_CONTEXT1 0x1000 // context1 is used + +#define SH_REGULARVS 0x8000 +#define SH_TEXTUREVS 0x8001 +#define SH_REGULARFOGVS 0x8002 +#define SH_TEXTUREFOGVS 0x8003 +#define SH_REGULARPS 0x8004 +#define SH_REGULARFOGPS 0x8005 +#define SH_BITBLTVS 0x8006 +#define SH_BITBLTPS 0x8007 +#define SH_BITBLTDEPTHPS 0x8009 +#define SH_CRTCTARGPS 0x800a +#define SH_CRTCPS 0x800b +#define SH_CRTC24PS 0x800c +#define SH_ZEROPS 0x800e +#define SH_BASETEXTUREPS 0x800f +#define SH_BITBLTAAPS 0x8010 +#define SH_CRTCTARGINTERPS 0x8012 +#define SH_CRTCINTERPS 0x8013 +#define SH_CRTC24INTERPS 0x8014 +#define SH_BITBLTDEPTHMRTPS 0x8016 +#define SH_BITBLTDEPTHTEXPS 0x8017 +#define SH_BITBLTDEPTHTEXMRTPS 0x8018 +#define SH_CONVERT16TO32PS 0x8020 +#define SH_CONVERT32TO16PS 0x8021 diff --git a/plugins/zerogs/dx/backup.bat b/plugins/zerogs/dx/backup.bat new file mode 100644 index 0000000000..9da64b07d0 --- /dev/null +++ b/plugins/zerogs/dx/backup.bat @@ -0,0 +1,4 @@ +@echo off +call parsedate +set TIMESTAMP=%month%%day%%year:~2,3% +winrar u ZeroGS%TIMESTAMP%.zip *.h *.cpp Win32\*.sln Win32\*.vcproj Win32\*.suo Win32\*.bat Win32\*.cpp Win32\*.h Win32\*.def *.asm *.fx *.bat zerogs.psd ZeroGSShaders.exe x86\*.* Win32\*.rc Win32\*.bmp Win32\*.dat ..\ZeroGSShaders\*.h ..\ZeroGSShaders\*.cpp \ No newline at end of file diff --git a/plugins/zerogs/dx/buildshaders.bat b/plugins/zerogs/dx/buildshaders.bat new file mode 100644 index 0000000000..401b5f258d --- /dev/null +++ b/plugins/zerogs/dx/buildshaders.bat @@ -0,0 +1,3 @@ +ZeroGSShaders.exe ps2hw.fx ps2fx.dat +del Win32\ps2fx.dat Win32\Release\*.res Win32\Debug\*.res +move /y ps2fx.dat Win32\ps2fx.dat \ No newline at end of file diff --git a/plugins/zerogs/dx/common.h b/plugins/zerogs/dx/common.h new file mode 100644 index 0000000000..280d62a70c --- /dev/null +++ b/plugins/zerogs/dx/common.h @@ -0,0 +1,1142 @@ +/** + * @file common.h + * common internal api header. + */ + +#ifndef COMMON_H +#define COMMON_H + +#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# define CONFIG_WIN32 +#endif + +//#define ALT_BITSTREAM_WRITER +//#define ALIGNED_BITSTREAM_WRITER + +#define ALT_BITSTREAM_READER +//#define LIBMPEG2_BITSTREAM_READER +//#define A32_BITSTREAM_READER +#define LIBMPEG2_BITSTREAM_READER_HACK //add BERO + +#ifdef HAVE_AV_CONFIG_H +/* only include the following when compiling package */ +# include "config.h" + +# include +# include +# include +# include +# ifndef __BEOS__ +# include +# else +# include "berrno.h" +# endif +# include + +# ifndef ENODATA +# define ENODATA 61 +# endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include +#ifndef offsetof +# define offsetof(T,F) ((unsigned int)((char *)&((T *)0)->F)) +#endif + +#define AVOPTION_CODEC_BOOL(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_BOOL } +#define AVOPTION_CODEC_DOUBLE(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_DOUBLE, minv, maxv, defval } +#define AVOPTION_CODEC_FLAG(name, help, field, flag, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_FLAG, flag, 0, defval } +#define AVOPTION_CODEC_INT(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_INT, minv, maxv, defval } +#define AVOPTION_CODEC_STRING(name, help, field, str, val) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_STRING, .defval = val, .defstr = str } +#define AVOPTION_CODEC_RCOVERRIDE(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_RCOVERRIDE, .defval = 0, .defstr = NULL } +#define AVOPTION_SUB(ptr) { .name = NULL, .help = (const char*)ptr } +#define AVOPTION_END() AVOPTION_SUB(NULL) + +struct AVOption; +#ifdef HAVE_MMX +extern const struct AVOption avoptions_common[3 + 5]; +#else +extern const struct AVOption avoptions_common[3]; +#endif +extern const struct AVOption avoptions_workaround_bug[11]; + +#endif /* HAVE_AV_CONFIG_H */ + +/* Suppress restrict if it was not defined in config.h. */ +#ifndef restrict +# define restrict +#endif + +#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define always_inline __attribute__((always_inline)) inline +#else +# define always_inline inline +#endif + +#ifdef CONFIG_WIN32 + +/* windows */ + +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +typedef signed char int8_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; + +# ifndef __MINGW32__ +# define int64_t_C(c) (c ## i64) +# define uint64_t_C(c) (c ## i64) + +# define inline __inline + +# else +# define int64_t_C(c) (c ## LL) +# define uint64_t_C(c) (c ## ULL) +# endif /* __MINGW32__ */ + +# ifdef _DEBUG +# define DEBUG +# endif + +# define snprintf _snprintf +# define vsnprintf _vsnprintf + +/* CONFIG_WIN32 end */ +#elif defined (CONFIG_OS2) +/* OS/2 EMX */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +#ifdef USE_FASTMEMCPY +#include "fastmemcpy.h" +#endif + +#include + +#endif /* HAVE_AV_CONFIG_H */ + +/* CONFIG_OS2 end */ +#else + +/* unix */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +# ifdef USE_FASTMEMCPY +# include "fastmemcpy.h" +# endif +# endif /* HAVE_AV_CONFIG_H */ + +#endif /* !CONFIG_WIN32 && !CONFIG_OS2 */ + +#ifdef HAVE_AV_CONFIG_H + +# include "bswap.h" + +# if defined(__MINGW32__) || defined(__CYGWIN__) || \ + defined(__OS2__) || (defined (__OpenBSD__) && !defined(__ELF__)) +# define MANGLE(a) "_" #a +# else +# define MANGLE(a) #a +# endif + +/* debug stuff */ + +# ifndef DEBUG +# define NDEBUG +# endif +# include + +/* dprintf macros */ +# if defined(CONFIG_WIN32) && !defined(__MINGW32__) + +inline void dprintf(const char* fmt,...) {} + +# else + +# ifdef DEBUG +# define dprintf(fmt,args...) printf(fmt, ## args) +# else +# define dprintf(fmt,args...) +# endif + +# endif /* !CONFIG_WIN32 */ + +# define av_abort() do { fprintf(stderr, "Abort at %s:%d\n", __FILE__, __LINE__); abort(); } while (0) + +//rounded divison & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +#define ABS(a) ((a) >= 0 ? (a) : (-(a))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + +extern const uint32_t inverse[256]; + +#ifdef ARCH_X86 +# define FASTDIV(a,b) \ + ({\ + int ret,dmy;\ + asm volatile(\ + "mull %3"\ + :"=d"(ret),"=a"(dmy)\ + :"1"(a),"g"(inverse[b])\ + );\ + ret;\ + }) +#elif defined(CONFIG_FASTDIV) +# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a)*inverse[b])>>32)) +#else +# define FASTDIV(a,b) ((a)/(b)) +#endif + +#ifdef ARCH_X86 +// avoid +32 for shift optimization (gcc should do that ...) +static inline int32_t NEG_SSR32( int32_t a, int8_t s){ + asm ("sarl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +static inline uint32_t NEG_USR32(uint32_t a, int8_t s){ + asm ("shrl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +#else +# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) +# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) +#endif + +/* bit output */ + +struct PutBitContext; + +typedef void (*WriteDataFunc)(void *, uint8_t *, int); + +typedef struct PutBitContext { +#ifdef ALT_BITSTREAM_WRITER + uint8_t *buf, *buf_end; + int index; +#else + uint32_t bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr, *buf_end; +#endif + int64_t data_out_size; /* in bytes */ +} PutBitContext; + +void init_put_bits(PutBitContext *s, + uint8_t *buffer, int buffer_size, + void *opaque, + void (*write_data)(void *, uint8_t *, int)); + +int64_t get_bit_count(PutBitContext *s); /* XXX: change function name */ +void align_put_bits(PutBitContext *s); +void flush_put_bits(PutBitContext *s); +void put_string(PutBitContext * pbc, char *s); + +/* bit input */ + +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; +#ifdef ALT_BITSTREAM_READER + int index; +#elif defined LIBMPEG2_BITSTREAM_READER + uint8_t *buffer_ptr; + uint32_t cache; + int bit_count; +#elif defined A32_BITSTREAM_READER + uint32_t *buffer_ptr; + uint32_t cache0; + uint32_t cache1; + int bit_count; +#endif + int size_in_bits; +} GetBitContext; + +static inline int get_bits_count(GetBitContext *s); + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table)[2]; ///< code, bits + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +#ifdef ARCH_SPARC64 +#define UNALIGNED_STORES_ARE_BAD +#endif + +/* used to avoid missaligned exceptions on some archs (alpha, ...) */ +#ifdef ARCH_X86 +# define unaligned32(a) (*(uint32_t*)(a)) +#else +# ifdef __GNUC__ +static inline uint32_t unaligned32(const void *v) { + struct Unaligned { + uint32_t i; + } __attribute__((packed)); + + return ((const struct Unaligned *) v)->i; +} +# elif defined(__DECC) +static inline uint32_t unaligned32(const void *v) { + return *(const __unaligned uint32_t *) v; +} +# else +static inline uint32_t unaligned32(const void *v) { + return *(const uint32_t *) v; +} +# endif +#endif //!ARCH_X86 + +#ifndef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ + unsigned int bit_buf; + int bit_left; + +#ifdef STATS + st_out_bit_counts[st_current_index] += n; +#endif + // DEBUG_LOG("put_bits=%d %x\n", n, value); + assert(n == 32 || value < (1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + // DEBUG_LOG("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); + /* XXX: optimize */ + if (n < bit_left) { + bit_buf = (bit_buf<> (n - bit_left); +#ifdef UNALIGNED_STORES_ARE_BAD + if (3 & (int) s->buf_ptr) { + s->buf_ptr[0] = bit_buf >> 24; + s->buf_ptr[1] = bit_buf >> 16; + s->buf_ptr[2] = bit_buf >> 8; + s->buf_ptr[3] = bit_buf ; + } else +#endif + *(uint32_t *)s->buf_ptr = be2me_32(bit_buf); + //DEBUG_LOG("bitbuf = %08x\n", bit_buf); + s->buf_ptr+=4; + bit_left+=32 - n; + bit_buf = value; + } + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} +#endif + + +#ifdef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ +# ifdef ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl %0, %%ecx \n\t" + "xorl %%eax, %%eax \n\t" + "shrdl %%cl, %1, %%eax \n\t" + "shrl %%cl, %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "andl $0xFFFFFFFC, %%ecx \n\t" + "bswapl %1 \n\t" + "orl %1, (%2, %%ecx) \n\t" + "bswapl %%eax \n\t" + "addl %3, %0 \n\t" + "movl %%eax, 4(%2, %%ecx) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value<<(-n)) + : "%eax", "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= ((uint32_t *)s->buf)+(index>>5); + + value<<= 32-n; + + ptr[0] |= be2me_32(value>>(index&31)); + ptr[1] = be2me_32(value<<(32-(index&31))); +//if(n>24) DEBUG_LOG("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# else //ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl $7, %%ecx \n\t" + "andl %0, %%ecx \n\t" + "addl %3, %%ecx \n\t" + "negl %%ecx \n\t" + "shll %%cl, %1 \n\t" + "bswapl %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "orl %1, (%%ecx, %2) \n\t" + "addl %3, %0 \n\t" + "movl $0, 4(%%ecx, %2) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value) + : "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= (uint32_t*)(((uint8_t *)s->buf)+(index>>3)); + + ptr[0] |= be2me_32(value<<(32-n-(index&7) )); + ptr[1] = 0; +//if(n>24) DEBUG_LOG("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# endif //!ALIGNED_BITSTREAM_WRITER +} +#endif + + +static inline uint8_t* pbBufPtr(PutBitContext *s) +{ +#ifdef ALT_BITSTREAM_WRITER + return s->buf + (s->index>>3); +#else + return s->buf_ptr; +#endif +} + +/* Bitstream reader API docs: +name + abritary name which is used as prefix for the internal variables + +gb + getbitcontext + +OPEN_READER(name, gb) + loads gb into local variables + +CLOSE_READER(name, gb) + stores local vars in gb + +UPDATE_CACHE(name, gb) + refills the internal cache from the bitstream + after this call at least MIN_CACHE_BITS will be available, + +GET_CACHE(name, gb) + will output the contents of the internal cache, next bit is MSB of 32 or 64 bit (FIXME 64bit) + +SHOW_UBITS(name, gb, num) + will return the nest num bits + +SHOW_SBITS(name, gb, num) + will return the nest num bits and do sign extension + +SKIP_BITS(name, gb, num) + will skip over the next num bits + note, this is equinvalent to SKIP_CACHE; SKIP_COUNTER + +SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache (note SKIP_COUNTER MUST be called before UPDATE_CACHE / CLOSE_READER) + +SKIP_COUNTER(name, gb, num) + will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS) + +LAST_SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache if it is needed for UPDATE_CACHE otherwise it will do nothing + +LAST_SKIP_BITS(name, gb, num) + is equinvalent to SKIP_LAST_CACHE; SKIP_COUNTER + +for examples see get_bits, show_bits, skip_bits, get_vlc +*/ + +static inline int unaligned32_be(const void *v) +{ +#ifdef CONFIG_ALIGN + const uint8_t *p=v; + return (((p[0]<<8) | p[1])<<16) | (p[2]<<8) | (p[3]); +#else + return be2me_32( unaligned32(v)); //original +#endif +} + +#ifdef ALT_BITSTREAM_READER +# define MIN_CACHE_BITS 25 + +# define OPEN_READER(name, gb)\ + int name##_index= (gb)->index;\ + int name##_cache= 0;\ + +# define CLOSE_READER(name, gb)\ + (gb)->index= name##_index;\ + +# define UPDATE_CACHE(name, gb)\ + name##_cache= unaligned32_be( ((uint8_t *)(gb)->buffer)+(name##_index>>3) ) << (name##_index&0x07);\ + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +// FIXME name? +# define SKIP_COUNTER(name, gb, num)\ + name##_index += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) ; + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return s->index; +} +#elif defined LIBMPEG2_BITSTREAM_READER +//libmpeg2 like reader + +# define MIN_CACHE_BITS 17 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + int name##_cache= (gb)->cache;\ + uint8_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache= name##_cache;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +#ifdef LIBMPEG2_BITSTREAM_READER_HACK + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= (int)be2me_16(*(uint16_t*)name##_buffer_ptr) << name##_bit_count;\ + ((uint16_t*)name##_buffer_ptr)++;\ + name##_bit_count-= 16;\ + }\ + +#else + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= ((name##_buffer_ptr[0]<<8) + name##_buffer_ptr[1]) << name##_bit_count;\ + name##_buffer_ptr+=2;\ + name##_bit_count-= 16;\ + }\ + +#endif + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +# define SKIP_COUNTER(name, gb, num)\ + name##_bit_count += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_BITS(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) SKIP_CACHE(name, gb, num) + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return (s->buffer_ptr - s->buffer)*8 - 16 + s->bit_count; +} + +#elif defined A32_BITSTREAM_READER + +# define MIN_CACHE_BITS 32 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + uint32_t name##_cache0= (gb)->cache0;\ + uint32_t name##_cache1= (gb)->cache1;\ + uint32_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache0= name##_cache0;\ + (gb)->cache1= name##_cache1;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count > 0){\ + const uint32_t next= be2me_32( *name##_buffer_ptr );\ + name##_cache0 |= NEG_USR32(next,name##_bit_count);\ + name##_cache1 |= next<buffer_ptr - s->buffer)*8 - 32 + s->bit_count; +} + +#endif + +/** + * read mpeg1 dc style vlc (sign bit + mantisse with no MSB). + * if MSB not set it is negative + * @param n length in bits + * @author BERO + */ +static inline int get_xbits(GetBitContext *s, int n){ + register int tmp; + register int32_t cache; + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + cache = GET_CACHE(re,s); + if ((int32_t)cache<0) { //MSB=1 + tmp = NEG_USR32(cache,n); + } else { + // tmp = (-1<index+=n for the ALT_READER :)) + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + LAST_SKIP_BITS(re, s, n) + CLOSE_READER(re, s) +} + +static inline unsigned int get_bits1(GetBitContext *s){ +#ifdef ALT_BITSTREAM_READER + int index= s->index; + uint8_t result= s->buffer[ index>>3 ]; + result<<= (index&0x07); + result>>= 8 - 1; + index++; + s->index= index; + + return result; +#else + return get_bits(s, 1); +#endif +} + +static inline unsigned int show_bits1(GetBitContext *s){ + return show_bits(s, 1); +} + +static inline void skip_bits1(GetBitContext *s){ + skip_bits(s, 1); +} + +void init_get_bits(GetBitContext *s, + const uint8_t *buffer, int buffer_size); + +int check_marker(GetBitContext *s, const char *msg); +void align_get_bits(GetBitContext *s); +int init_vlc(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size); +void free_vlc(VLC *vlc); + +/** + * + * if the vlc code is invalid and max_depth=1 than no bits will be removed + * if the vlc code is invalid and max_depth>1 than the number of bits removed + * is undefined + */ +#define GET_VLC(code, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + code = table[index][0];\ + n = table[index][1];\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + if(max_depth > 2 && n < 0){\ + LAST_SKIP_BITS(name, gb, nb_bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + }\ + }\ + SKIP_BITS(name, gb, n)\ +} + +#define GET_RL_VLC(level, run, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + level = table[index].level;\ + n = table[index].len;\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + level;\ + level = table[index].level;\ + n = table[index].len;\ + }\ + run= table[index].run;\ + SKIP_BITS(name, gb, n)\ +} + +// deprecated, dont use get_vlc for new code, use get_vlc2 instead or use GET_VLC directly +static inline int get_vlc(GetBitContext *s, VLC *vlc) +{ + int code; + VLC_TYPE (*table)[2]= vlc->table; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, vlc->bits, 3) + + CLOSE_READER(re, s) + return code; +} + +/** + * parses a vlc code, faster then get_vlc() + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be readed to completly + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + */ +static always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, bits, max_depth) + + CLOSE_READER(re, s) + return code; +} + +//#define TRACE + +#ifdef TRACE + +static inline void print_bin(int bits, int n){ + int i; + + for(i=n-1; i>=0; i--){ + DEBUG_LOG("%d", (bits>>i)&1); + } + for(i=n; i<24; i++) + DEBUG_LOG(" "); +} + +static inline int get_bits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int r= get_bits(s, n); + + print_bin(r, n); + DEBUG_LOG("%5d %2d %3d bit @%5d in %s %s:%d\n", r, n, r, get_bits_count(s)-n, file, func, line); + return r; +} +static inline int get_vlc_trace(GetBitContext *s, VLC_TYPE (*table)[2], int bits, int max_depth, char *file, char *func, int line){ + int show= show_bits(s, 24); + int pos= get_bits_count(s); + int r= get_vlc2(s, table, bits, max_depth); + int len= get_bits_count(s) - pos; + int bits2= show>>(24-len); + + print_bin(bits2, len); + + DEBUG_LOG("%5d %2d %3d vlc @%5d in %s %s:%d\n", bits2, len, r, pos, file, func, line); + return r; +} +static inline int get_xbits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int show= show_bits(s, n); + int r= get_xbits(s, n); + + print_bin(show, n); + DEBUG_LOG("%5d %2d %3d xbt @%5d in %s %s:%d\n", show, n, r, get_bits_count(s)-n, file, func, line); + return r; +} + +#define get_bits(s, n) get_bits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_bits1(s) get_bits_trace(s, 1, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_xbits(s, n) get_xbits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc(s, vlc) get_vlc_trace(s, (vlc)->table, (vlc)->bits, 3, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc2(s, tab, bits, max) get_vlc_trace(s, tab, bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__) + +#define tprintf printf + +#else //TRACE +#define tprintf(_arg...) {} +#endif + +/* define it to include statistics code (useful only for optimizing + codec efficiency */ +//#define STATS + +#ifdef STATS + +enum { + ST_UNKNOWN, + ST_DC, + ST_INTRA_AC, + ST_INTER_AC, + ST_INTRA_MB, + ST_INTER_MB, + ST_MV, + ST_NB, +}; + +extern int st_current_index; +extern unsigned int st_bit_counts[ST_NB]; +extern unsigned int st_out_bit_counts[ST_NB]; + +void print_stats(void); +#endif + +/* misc math functions */ +extern const uint8_t ff_log2_tab[256]; + +static inline int av_log2(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + +static inline int av_log2_16bit(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + + +/* median of 3 */ +static inline int mid_pred(int a, int b, int c) +{ + int vmin, vmax; + vmax = vmin = a; + if (b < vmin) + vmin = b; + else + vmax = b; + + if (c < vmin) + vmin = c; + else if (c > vmax) + vmax = c; + + return a + b + c - vmin - vmax; +} + +static inline int clip(int a, int amin, int amax) +{ + if (a < amin) + return amin; + else if (a > amax) + return amax; + else + return a; +} + +/* math */ +extern const uint8_t ff_sqrt_tab[128]; + +int64_t ff_gcd(int64_t a, int64_t b); + +static inline int ff_sqrt(int a) +{ + int ret=0; + int s; + int ret_sq=0; + + if(a<128) return ff_sqrt_tab[a]; + + for(s=15; s>=0; s--){ + int b= ret_sq + (1<<(s*2)) + (ret<>31;\ + level= (level^mask)-mask; +#endif + + +#if __CPU__ >= 686 && !defined(RUNTIME_CPUDETECT) +#define COPY3_IF_LT(x,y,a,b,c,d)\ +asm volatile (\ + "cmpl %0, %3 \n\t"\ + "cmovl %3, %0 \n\t"\ + "cmovl %4, %1 \n\t"\ + "cmovl %5, %2 \n\t"\ + : "+r" (x), "+r" (a), "+r" (c)\ + : "r" (y), "r" (b), "r" (d)\ +); +#else +#define COPY3_IF_LT(x,y,a,b,c,d)\ +if((y)<(x)){\ + (x)=(y);\ + (a)=(b);\ + (c)=(d);\ +} +#endif + +#ifdef ARCH_X86 +static inline long long rdtsc() +{ + long long l; + asm volatile( "rdtsc\n\t" + : "=A" (l) + ); + return l; +} + +#define START_TIMER \ +static uint64_t tsum=0;\ +static int tcount=0;\ +static int tskip_count=0;\ +uint64_t tend;\ +uint64_t tstart= rdtsc();\ + +#define STOP_TIMER(id) \ +tend= rdtsc();\ +if(tcount<2 || tend - tstart < 4*tsum/tcount){\ + tsum+= tend - tstart;\ + tcount++;\ +}else\ + tskip_count++;\ +if(256*256*256*64%(tcount+tskip_count)==0){\ + fprintf(stderr, "%Ld dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\ +} +#endif + +#define CLAMP_TO_8BIT(d) ((d > 0xff) ? 0xff : (d < 0) ? 0 : d) + +/* avoid usage of various functions */ +#define malloc please_use_av_malloc +#define free please_use_av_free +#define realloc please_use_av_realloc + +#define CHECKED_ALLOCZ(p, size)\ +{\ + p= av_mallocz(size);\ + if(p==NULL && (size)!=0){\ + perror("malloc");\ + goto fail;\ + }\ +} + +#endif /* HAVE_AV_CONFIG_H */ + +#endif /* COMMON_H */ diff --git a/plugins/zerogs/dx/common/PS2Edefs.h b/plugins/zerogs/dx/common/PS2Edefs.h new file mode 100644 index 0000000000..1f65fc02b9 --- /dev/null +++ b/plugins/zerogs/dx/common/PS2Edefs.h @@ -0,0 +1,885 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/zerogs/dx/common/PS2Etypes.h b/plugins/zerogs/dx/common/PS2Etypes.h new file mode 100644 index 0000000000..59be1c3de4 --- /dev/null +++ b/plugins/zerogs/dx/common/PS2Etypes.h @@ -0,0 +1,219 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/zerogs/dx/memcpy_amd.cpp b/plugins/zerogs/dx/memcpy_amd.cpp new file mode 100644 index 0000000000..9d22f60f36 --- /dev/null +++ b/plugins/zerogs/dx/memcpy_amd.cpp @@ -0,0 +1,479 @@ +/****************************************************************************** + + Copyright (c) 2001 Advanced Micro Devices, Inc. + + LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY + EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, + NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY + PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY + DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, + BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR + INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY + OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION + OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY + NOT APPLY TO YOU. + + AMD does not assume any responsibility for any errors which may appear in the + Materials nor any responsibility to support or update the Materials. AMD retains + the right to make changes to its test specifications at any time, without notice. + + NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any + further information, software, technical information, know-how, or show-how + available to you. + + So that all may benefit from your experience, please report any problems + or suggestions about this software to 3dsdk.support@amd.com + + AMD Developer Technologies, M/S 585 + Advanced Micro Devices, Inc. + 5900 E. Ben White Blvd. + Austin, TX 78741 + 3dsdk.support@amd.com +******************************************************************************/ + +#include + +/***************************************************************************** +MEMCPY_AMD.CPP +******************************************************************************/ + +// Very optimized memcpy() routine for AMD Athlon and Duron family. +// This code uses any of FOUR different basic copy methods, depending +// on the transfer size. +// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or +// "Streaming Store"), and also uses the software prefetch instructions, +// be sure you're running on Athlon/Duron or other recent CPU before calling! + +#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". + +#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch +// Next is a copy that uses the MMX registers to copy 8 bytes at a time, +// also using the "unrolled loop" optimization. This code uses +// the software prefetch instruction to get the data into the cache. + +#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" + +#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch +#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. + +//#include + +// Inline assembly syntax for use with Visual C++ +#ifdef _WIN32 +#include +#endif + +extern "C" { + +#include "PS2Etypes.h" + +#if defined(_MSC_VER) && !defined(__x86_64__) + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ + __asm { + mov ecx, [n] ; number of bytes to copy + mov edi, [dest] ; destination + mov esi, [src] ; source + mov ebx, ecx ; keep a copy of count + + cld + cmp ecx, TINY_BLOCK_COPY + jb $memcpy_ic_3 ; tiny? skip mmx copy + + cmp ecx, 32*1024 ; don't align between 32k-64k because + jbe $memcpy_do_align ; it appears to be slower + cmp ecx, 64*1024 + jbe $memcpy_align_done +$memcpy_do_align: + mov ecx, 8 ; a trick that's faster than rep movsb... + sub ecx, edi ; align destination to qword + and ecx, 111b ; get the low bits + sub ebx, ecx ; update copy count + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_align_done + jmp ecx ; jump to array of movsb's + +align 4 + movsb + movsb + movsb + movsb + movsb + movsb + movsb + movsb + +$memcpy_align_done: ; destination is dword aligned + mov ecx, ebx ; number of bytes left to copy + shr ecx, 6 ; get 64-byte block count + jz $memcpy_ic_2 ; finish the last few bytes + + cmp ecx, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy + jae $memcpy_uc_test + +// This is small block copy that uses the MMX registers to copy 8 bytes +// at a time. It uses the "unrolled loop" optimization, and also uses +// the software prefetch instruction to get the data into the cache. +align 16 +$memcpy_ic_1: ; 64-byte block copies, in-cache copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0, [esi+0] ; read 64 bits + movq mm1, [esi+8] + movq [edi+0], mm0 ; write 64 bits + movq [edi+8], mm1 ; note: the normal movq writes the + movq mm2, [esi+16] ; data to cache; a cache line will be + movq mm3, [esi+24] ; allocated as needed, to store the data + movq [edi+16], mm2 + movq [edi+24], mm3 + movq mm0, [esi+32] + movq mm1, [esi+40] + movq [edi+32], mm0 + movq [edi+40], mm1 + movq mm2, [esi+48] + movq mm3, [esi+56] + movq [edi+48], mm2 + movq [edi+56], mm3 + + add esi, 64 ; update source pointer + add edi, 64 ; update destination pointer + dec ecx ; count down + jnz $memcpy_ic_1 ; last 64-byte block? + +$memcpy_ic_2: + mov ecx, ebx ; has valid low 6 bits of the byte count +$memcpy_ic_3: + shr ecx, 2 ; dword count + and ecx, 1111b ; only look at the "remainder" bits + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_last_few + jmp ecx ; jump to array of movsd's + +$memcpy_uc_test: + cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy + jae $memcpy_bp_1 + +$memcpy_64_test: + or ecx, ecx ; tail end of block prefetch will jump here + jz $memcpy_ic_2 ; no more 64-byte blocks left + +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +align 16 +$memcpy_uc_1: ; 64-byte blocks, uncached copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0,[esi+0] ; read 64 bits + add edi,64 ; update destination pointer + movq mm1,[esi+8] + add esi,64 ; update source pointer + movq mm2,[esi-48] + movntq [edi-64], mm0 ; write 64 bits, bypassing the cache + movq mm0,[esi-40] ; note: movntq also prevents the CPU + movntq [edi-56], mm1 ; from READING the destination address + movq mm1,[esi-32] ; into the cache, only to be over-written + movntq [edi-48], mm2 ; so that also helps performance + movq mm2,[esi-24] + movntq [edi-40], mm0 + movq mm0,[esi-16] + movntq [edi-32], mm1 + movq mm1,[esi-8] + movntq [edi-24], mm2 + movntq [edi-16], mm0 + dec ecx + movntq [edi-8], mm1 + jnz $memcpy_uc_1 ; last 64-byte block? + + jmp $memcpy_ic_2 ; almost done + +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. +$memcpy_bp_1: ; large blocks, block prefetch copy + + cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? + jl $memcpy_64_test ; no, back to regular uncached copy + + mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X + add esi, CACHEBLOCK * 64 ; move to the top of the block +align 16 +$memcpy_bp_2: + mov edx, [esi-64] ; grab one address per cache line + mov edx, [esi-128] ; grab one address per cache line + sub esi, 128 ; go reverse order to suppress HW prefetcher + dec eax ; count down the cache lines + jnz $memcpy_bp_2 ; keep grabbing more lines into cache + + mov eax, CACHEBLOCK ; now that it's in cache, do the copy +align 16 +$memcpy_bp_3: + movq mm0, [esi ] ; read 64 bits + movq mm1, [esi+ 8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + add esi, 64 ; update source pointer + movntq [edi ], mm0 ; write 64 bits, bypassing cache + movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU + movntq [edi+16], mm2 ; from READING the destination address + movntq [edi+24], mm3 ; into the cache, only to be over-written, + movntq [edi+32], mm4 ; so that also helps performance + movntq [edi+40], mm5 + movntq [edi+48], mm6 + movntq [edi+56], mm7 + add edi, 64 ; update dest pointer + + dec eax ; count down + + jnz $memcpy_bp_3 ; keep copying + sub ecx, CACHEBLOCK ; update the 64-byte block count + jmp $memcpy_bp_1 ; keep processing chunks + +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". Then it handles the last few bytes. +align 4 + movsd + movsd ; perform last 1-15 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + movsd + movsd ; perform last 1-7 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + +$memcpy_last_few: ; dword aligned from before movsd's + mov ecx, ebx ; has valid low 2 bits of the byte count + and ecx, 11b ; the last few cows must come home + jz $memcpy_final ; no more, let's leave + rep movsb ; the last 1, 2, or 3 bytes + +$memcpy_final: + emms ; clean up the MMX state + sfence ; flush the write buffer + mov eax, [dest] ; ret value = destination pointer + + } +} + +// mmx memcpy implementation, size has to be a multiple of 8 +// returns 0 is equal, nonzero value if not equal +// ~10 times faster than standard memcmp +// (zerofrog) +u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +{ + assert( (cmpsize&7) == 0 ); + + __asm { +push esi + mov ecx, cmpsize + mov edx, src1 + mov esi, src2 + + cmp ecx, 32 + jl Done4 + + // custom test first 8 to make sure things are ok + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + movq mm2, [esi+16] + pmovmskb eax, mm0 + movq mm3, [esi+24] + + // check if eq + cmp eax, 0xff + je NextComp + mov eax, 1 + jmp End + +NextComp: + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je ContinueTest + mov eax, 1 + jmp End + + cmp ecx, 64 + jl Done8 + +Cmp8: + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pcmpeqd mm4, [edx+32] + pand mm0, mm2 + pcmpeqd mm5, [edx+40] + pand mm0, mm3 + pcmpeqd mm6, [edx+48] + pand mm0, mm4 + pcmpeqd mm7, [edx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + je Continue + mov eax, 1 + jmp End + +Continue: + sub ecx, 64 + add esi, 64 + add edx, 64 +ContinueTest: + cmp ecx, 64 + jge Cmp8 + +Done8: + test ecx, 0x20 + jz Done4 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je Done4 + mov eax, 1 + jmp End + +Done4: + cmp ecx, 24 + jne Done2 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done2: + cmp ecx, 16 + jne Done1 + + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done1: + cmp ecx, 8 + jne Done + + mov eax, [esi] + mov esi, [esi+4] + cmp eax, [edx] + je Next + mov eax, 1 + jmp End + +Next: + cmp esi, [edx+4] + setne al + jmp End + +Done: + xor eax, eax + +End: + pop esi + emms + } +} + +#else // _MSC_VER +// assume gcc or mingw or win x64 + +#include +#include + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ +memcpy(dest, src, n); +return dest; +} + + +#endif + +} diff --git a/plugins/zerogs/dx/ps2hw.fx b/plugins/zerogs/dx/ps2hw.fx new file mode 100644 index 0000000000..1bccf1b7a9 --- /dev/null +++ b/plugins/zerogs/dx/ps2hw.fx @@ -0,0 +1,993 @@ +// Cg Shaders for PS2 GS emulation + +// divides by z for every pixel, instead of in vertex shader +// fixes kh textures +#define PERSPECTIVE_CORRECT_TEX + +//#define TEST_AEM // tests AEM for black pixels +//#define REGION_REPEAT // set if texture wrapping mode is region repeat +//#define WRITE_DEPTH // set if depth is also written in a MRT +//#define ACCURATE_DECOMPRESSION // set for less capable hardware ATI Radeon 9000 series +//#define EXACT_COLOR // make sure the output color is clamped to 1/255 boundaries (for alpha testing) + +#ifdef PERSPECTIVE_CORRECT_TEX +#define TEX_XY tex.xy/tex.z +#define TEX_DECL float3 +#else +#define TEX_XY tex.xy +#define TEX_DECL float2 +#endif + +#ifdef WRITE_DEPTH +#define DOZWRITE(x) x +#else +#define DOZWRITE(x) +#endif + +#include "ps2hw_ctx0.fx" + +// used to get the tiled offset into a page given the linear offset +texture g_txBlocks; +texture g_txBilinearBlocks; +texture g_txSrc; + +texture g_txConv16to32; +texture g_txConv32to16; + +// for region_repeat mode +texture g_txBitwiseANDX; +texture g_txBitwiseANDY; +texture g_txCLUT; + +sampler g_sSrcFinal : register(s2) = sampler_state { + Texture = ; + MipFilter = LINEAR; + MinFilter = LINEAR; + MagFilter = LINEAR; + AddressU = Clamp; + AddressV = Clamp; +}; + +sampler g_sBlocks : register(s3) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +sampler g_sBilinearBlocks : register(s4) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +sampler g_sConv16to32 : register(s4) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +sampler3D g_sConv32to16 : register(s4) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +sampler g_sBitwiseANDX : register(s5) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +sampler g_sBitwiseANDY : register(s6) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +// used only on rare cases where the render target is PSMT8H +sampler g_sCLUT : register(s2) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Wrap; + AddressV = Wrap; +}; + +// global pixel shader constants +float4 g_fInvTexDims : register(c22); // similar to g_fClutOff +float3 g_fFogColor : register(c23); + +// used for rectblitting +float4 g_fBitBltZ : register(c24); + +half4 g_fOneColor : register(c25); // col*.xxxy+.zzzw + +// vertex shader constants +float4 g_fBitBltPos : register(c4); +float4 g_fZ : register(c5); // transforms d3dcolor z into float z +float2 g_fZNorm : register(c6); +float4 g_fBitBltTex : register(c7); + +// pixel shader consts +// .z is used for the addressing fn +half4 g_fExactColor : register(c27) = half4(0.5,0.5/256.0f,0,1/255.0f); +float3 g_fBilinear : register(c28) = float3(-0.7f, -0.65f, 0.9); +float4 g_fZBias : register(c29) = half4(1.0f/256.0f, 1.0004f, 1, 0.5); +float4 g_fc0 : register(c30) = float4(0,1, 0.001, 0.5f); // also for vs +float4 g_fMult : register(c31) = float4(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f); + +// vertex shader consts +float4 g_fBitBltTrans : register(c31) = float4(0.5f, -0.5f, 0.5, 0.5 + 0.4/416.0f); + +// given a local tex coord, returns the coord in the memory +float2 ps2memcoord(float2 realtex) +{ + float4 off; + + // block off + realtex.xy = realtex.xy * g_fTexDims.xy + g_fTexDims.zw; + realtex.xy = (realtex.xy - frac(realtex.xy)) * g_fMult.zw; + float2 fblock = frac(realtex.xy); + off.xy = realtex.xy-fblock.xy; + +#ifdef ACCURATE_DECOMPRESSION + off.zw = tex2D(g_sBlocks, g_fTexBlock.xy*fblock + g_fTexBlock.zw).xw; + off.x = dot(off.xyw, g_fTexOffset.xyw); + float f = frac(off.x); + float fadd = g_fTexOffset.z * off.z; + off.w = off.x + fadd; + off.x = frac(f + fadd); + off.w -= off.x; +#else + off.z = tex2D(g_sBlocks, g_fTexBlock.xy*fblock + g_fTexBlock.zw).r; + + // combine the two + off.x = dot(off.xyz, g_fTexOffset.xyz)+g_fTexOffset.w; + off.x = modf(off.x, off.w); +#endif + + off.y = off.w * g_fPageOffset.y + g_fPageOffset.x; + return off.xy; +} + +// find all texcoords for bilinear filtering +// assume that orgtex are already on boundaries +void ps2memcoord4(float4 orgtex, out float4 off0, out float4 off1) +{ + //float4 off0, off1, off2, off3; + float4 realtex; + + // block off + realtex = (orgtex * g_fTexDims.xyxy + g_fTexDims.zwzw);// * g_fMult.zwzw; + float4 fblock = frac(realtex.xyzw); + float4 ftransblock = g_fTexBlock.xyxy*fblock + g_fTexBlock.zwzw; + realtex -= fblock; + + float4 transvals = g_fTexOffset.x * realtex.xzxz + g_fTexOffset.y * realtex.yyww + g_fTexOffset.w; + + float4 colors;// = tex2D(g_sBilinearBlocks, ftransblock.xy); + + // this is faster on ffx ingame + colors.x = tex2D(g_sBlocks, ftransblock.xy).r; + colors.y = tex2D(g_sBlocks, ftransblock.zy).r; + colors.z = tex2D(g_sBlocks, ftransblock.xw).r; + colors.w = tex2D(g_sBlocks, ftransblock.zw).r; + + float4 fr, rem; + +#ifdef ACCURATE_DECOMPRESSION + fr = frac(transvals); + float4 fadd = colors * g_fTexOffset.z; + rem = transvals + fadd; + fr = frac(fr + fadd); + rem -= fr; +#else + transvals += colors * g_fTexOffset.z; + + fr = modf(transvals, rem); +#endif + + rem = rem * g_fPageOffset.y + g_fPageOffset.x; + + // combine + off0 = g_fc0.yxyx * fr.xxyy + g_fc0.xyxy * rem.xxyy; + off1 = g_fc0.yxyx * fr.zzww + g_fc0.xyxy * rem.zzww; +} + +void ps2memcoord4_fast(float4 orgtex, out float4 off0, out float4 off1) +{ + float4 realtex; + + realtex = (orgtex * g_fTexDims.xyxy + g_fTexDims.zwzw);// * g_fMult.zwzw; + float4 fblock = frac(realtex.xyzw); + float2 ftransblock = g_fTexBlock.xy*fblock.xy + g_fTexBlock.zw; + realtex -= fblock; + + float4 transvals = g_fTexOffset.x * realtex.xzxz + g_fTexOffset.y * realtex.yyww + g_fTexOffset.w; + + float4 colors = tex2D(g_sBilinearBlocks, ftransblock.xy); + float4 fr, rem; + +#ifdef ACCURATE_DECOMPRESSION + fr = frac(transvals); + float4 fadd = colors * g_fTexOffset.z; + rem = transvals + fadd; + fr = frac(fr + fadd); + rem -= fr; +#else + transvals += colors * g_fTexOffset.z; + + fr = modf(transvals, rem); +#endif + + rem = rem * g_fPageOffset.y + g_fPageOffset.x; + + off0 = g_fc0.yxyx * fr.xxyy + g_fc0.xyxy * rem.xxyy; + off1 = g_fc0.yxyx * fr.zzww + g_fc0.xyxy * rem.zzww; +} + +// Wrapping modes +#if defined(REPEAT) + +float2 ps2addr(float2 coord) +{ + return frac(coord.xy); +} + +#elif defined(CLAMP) + +float2 ps2addr(float2 coord) +{ + return clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw); +} + +#elif defined(REGION_REPEAT) + +// computes the local tex coord along with addressing modes +float2 ps2addr(float2 coord) +{ + float2 final = frac(clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw)); + + if( TexWrapMode.x > g_fBilinear.z ) // region repeat mode for x (umsk&x)|ufix + final.x = tex2D(g_sBitwiseANDX, abs(coord.x)*TexWrapMode.z).x * g_fClampExts.x + g_fClampExts.z; + if( TexWrapMode.y > g_fBilinear.z ) // region repeat mode for x (vmsk&x)|vfix + final.y = tex2D(g_sBitwiseANDY, abs(coord.y)*TexWrapMode.w).x * g_fClampExts.y + g_fClampExts.w; + + return final; +} + +#else + +float2 ps2addr(float2 coord) +{ + return frac(clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw)); +} + +#endif + +half4 tex2DPS_32(float2 tex0) +{ + return tex2D(g_sMemory, ps2memcoord(tex0).xy); +} + +// use when texture is not tiled +half4 tex2DPS_tex32(float2 tex0) +{ + return tex2D(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw)*g_fZBias.zzzw+g_fPageOffset.w; +} + +// use when texture is not tiled +half4 tex2DPS_clut32(float2 tex0) +{ + float index = tex2D(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw).a+g_fPageOffset.w; + return tex1D(g_sCLUT, index*g_fExactColor.x+g_fExactColor.y); +} + +// use when texture is not tiled and converting from 32bit to 16bit +// don't convert on the block level, only on the column level +// so every other 8 pixels, use the upper bits instead of lower +half4 tex2DPS_tex32to16(float2 tex0) +{ + bool upper = false; + tex0.y += g_fPageOffset.z; + float2 ffrac = fmod(tex0, g_fTexOffset.xy); + //tex0.xy = g_fc0.ww * (tex0.xy + ffrac); + tex0.y += ffrac.y; + + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + upper = true; + } + if( ffrac.y >= g_fTexOffset.w ) { + tex0.y -= g_fTexOffset.y; + tex0.x += g_fTexOffset.z; + } + + half4 color = tex2D(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw)*g_fZBias.zzzw+g_fPageOffset.w; + float2 uv = upper ? color.xw : color.zy; + return tex2D(g_sConv16to32, uv+g_fPageOffset.xy).zyxw; +} + +// used when a 16 bit texture is used an 8h +half4 tex2DPS_tex16to8h(float2 tex0) +{ + float4 final; + float2 ffrac = fmod(tex0+g_fPageOffset.zw, g_fTexOffset.xy); + //tex0.xy = g_fPageOffset.xy * tex0.xy - ffrac * g_fc0.yw; + tex0.y += g_fPageOffset.y * ffrac.y; + + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + tex0.y += g_fTexOffset.w; + } + + float4 upper = tex2D(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw); + + // only need alpha + float index = tex3D(g_sConv32to16, upper.zyx-g_fc0.z).y + upper.w*g_fc0.w*g_fc0.w; + return tex1D(g_sCLUT, index+g_fExactColor.y); +} + +// used when a 16 bit texture is used a 32bit one +half4 tex2DPS_tex16to32(float2 tex0) +{ + float4 final; + float2 ffrac = fmod(tex0+g_fPageOffset.zw, g_fTexOffset.xy); + //tex0.xy = g_fPageOffset.xy * tex0.xy - ffrac * g_fc0.yw; + tex0.y += g_fPageOffset.y * ffrac.y; + + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + tex0.y += g_fTexOffset.w; + } + + float fconst = g_fc0.w*g_fc0.w; + float4 lower = tex2D(g_sSrcFinal, g_fTexDims.xy*tex0); + float4 upper = tex2D(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw); + + final.zy = tex3D(g_sConv32to16, lower.zyx).xy + lower.ww*fconst; + final.xw = tex3D(g_sConv32to16, upper.zyx).xy + upper.ww*fconst; + return final; +} + +//half4 f; +//f.w = old.y > (127.2f/255.0f) ? 1 : 0; +//old.y -= 0.5f * f.w; +//f.xyz = frac(old.yyx*half3(2.002*255.0f/256.0f, 64.025f*255.0f/256.0f, 8.002*255.0f/256.0f)); +//f.y += old.x * (0.25f*255.0f/256.0f); + +//////////////////////////////// +// calculates the texture color +//////////////////////////////// + +#define decl_ps2shade(num) \ +decl_ps2shade_##num(_32); \ +decl_ps2shade_##num(_tex32); \ +decl_ps2shade_##num(_clut32); \ +decl_ps2shade_##num(_tex32to16); \ +decl_ps2shade_##num(_tex16to8h); \ + +// nearest +#define decl_ps2shade_0(bit) \ +half4 ps2shade0##bit( TEX_DECL tex) \ +{ \ + return tex2DPS##bit( ps2addr(TEX_XY)); \ +} \ + +// do fast memcoord4 calcs when textures behave well +#ifdef REPEAT +#define PS2MEMCOORD4 ps2memcoord4 +#else +#define PS2MEMCOORD4 ps2memcoord4 +#endif + +#define decl_BilinearFilter(bit, addrfn) \ +half4 BilinearFilter##bit(float2 tex0) \ +{ \ + float4 off0, off1; \ + float4 ftex; \ + float2 ffrac; \ + ftex.xy = tex0 + g_fBilinear.xy * g_fRealTexDims.zw; \ + ffrac = frac(ftex.xy*g_fRealTexDims.xy); \ + ftex.xy -= ffrac.xy * g_fRealTexDims.zw; \ + \ + ftex.zw = ps2addr(ftex.xy + g_fRealTexDims.zw); \ + ftex.xy = ps2addr(ftex.xy); \ + \ + PS2MEMCOORD4(ftex, off0, off1); \ + half4 c0 = tex2D(g_sMemory, off0.xy); \ + half4 c1 = tex2D(g_sMemory, off0.zw); \ + half4 c2 = tex2D(g_sMemory, off1.xy); \ + half4 c3 = tex2D(g_sMemory, off1.zw); \ + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y ); \ +} \ + +decl_BilinearFilter(_32, ps2addr); +decl_BilinearFilter(_tex32, ps2addr); +decl_BilinearFilter(_clut32, ps2addr); +decl_BilinearFilter(_tex32to16, ps2addr); +decl_BilinearFilter(_tex16to8h, ps2addr); + +//TODO! For mip maps, only apply when LOD >= 0 +// lcm == 0, LOD = log(1/Q)*L + K, lcm == 1, LOD = K + +// bilinear +#define decl_ps2shade_1(bit) \ +half4 ps2shade1##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +// nearest, mip nearest +#define decl_ps2shade_2(bit) \ +half4 ps2shade2##bit(TEX_DECL tex) \ +{ \ + return tex2DPS##bit( ps2addr(TEX_XY)); \ +} \ + +// nearest, mip linear +#define decl_ps2shade_3(bit) \ +half4 ps2shade3##bit(TEX_DECL tex) \ +{ \ + return tex2DPS##bit(ps2addr(TEX_XY)); \ +} \ + +// linear, mip nearest +#define decl_ps2shade_4(bit) \ +half4 ps2shade4##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +// linear, mip linear +#define decl_ps2shade_5(bit) \ +half4 ps2shade5##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +decl_ps2shade(0); +decl_ps2shade(1); +decl_ps2shade(2); +decl_ps2shade(3); +decl_ps2shade(4); +decl_ps2shade(5); + +half4 ps2CalcShade(half4 texcol, half4 color) +{ +#ifdef TEST_AEM + if( dot(texcol.xyzw, g_fTestBlack.xyzw) <= g_fc0.z ) + texcol.w = g_fc0.x; + else +#endif + texcol.w = texcol.w * fTexAlpha.y + fTexAlpha.x; + + texcol = texcol * (fTexAlpha2.zzzw * color + fTexAlpha2.xxxy) + fTexAlpha.zzzw * color.wwww; + + return texcol; +} + +// final ops on the color +#ifdef EXACT_COLOR + +half4 ps2FinalColor(half4 col) +{ + // g_fOneColor has to scale by 255 + half4 temp = col * g_fOneColor.xxxy + g_fOneColor.zzzw; + temp.w = floor(temp.w)*g_fExactColor.w; + return temp; +} + +#else +half4 ps2FinalColor(half4 col) +{ + return col * g_fOneColor.xxxy + g_fOneColor.zzzw; +} +#endif + +//////////////// +// Techniques // +//////////////// + +// technique to copy a rectangle from source to target +struct VSOUT_ +{ + float4 pos : POSITION; + half4 color : COLOR0; + DOZWRITE(float4 z : TEXCOORD0;) +}; + +struct VSOUT_T +{ + float4 pos : POSITION; + half4 color : COLOR0; + TEX_DECL tex : TEXCOORD0; + DOZWRITE(float4 z : TEXCOORD1;) +}; + +struct VSOUT_F +{ + float4 pos : POSITION; + half4 color : COLOR0; + float fog : TEXCOORD0; + DOZWRITE(float4 z : TEXCOORD1;) +}; + +struct VSOUT_TF +{ + float4 pos : POSITION; + half4 color : COLOR0; + TEX_DECL tex : TEXCOORD0; + half fog : TEXCOORD1; + DOZWRITE(float4 z : TEXCOORD2;) +}; + +// just smooth shadering +VSOUT_ RegularVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : TEXCOORD0 + ) +{ + VSOUT_ o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; // 1 + o.color = color; + + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) + return o; +} + +void RegularPS(VSOUT_ i, out half4 c0 : COLOR0 +#ifdef WRITE_DEPTH + , out float4 c1 : COLOR1 +#endif + ) +{ + // whenever outputting depth, make sure to mult by 255/256 and 1 + c0 = ps2FinalColor(i.color); + DOZWRITE(c1 = i.z;) +} + +technique Regular { + pass p0 { + VertexShader = compile vs_3_0 RegularVS(); + PixelShader = compile ps_3_0 RegularPS(); + } +}; + +// diffuse texture mapping +VSOUT_T TextureVS(float4 pos : POSITION, + half4 color : COLOR0, + float3 tex0 : TEXCOORD1, + float4 z : TEXCOORD0) +{ + VSOUT_T o; + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x + g_fZNorm.y; + o.pos.w = g_fc0.y; + o.color = color; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) +#ifdef PERSPECTIVE_CORRECT_TEX + o.tex = tex0; +#else + o.tex = tex0.xy/tex0.z; +#endif + return o; +} + +#ifdef WRITE_DEPTH + +#define DECL_TEXPS(num, bit) \ +void Texture##num##bit##PS(VSOUT_T i, out half4 c0 : COLOR0, out float4 c1 : COLOR1) \ +{ \ + c0 = ps2FinalColor(ps2CalcShade(ps2shade##num##bit(i.tex), i.color)); \ + c1 = i.z; \ +} \ + +#else + +#define DECL_TEXPS(num, bit) \ +void Texture##num##bit##PS(VSOUT_T i, out half4 c0 : COLOR0) \ +{ \ + c0 = ps2FinalColor(ps2CalcShade(ps2shade##num##bit(i.tex), i.color)); \ +} \ + +#endif + +#define DECL_TEXPS_(num) \ +DECL_TEXPS(num, _32); \ +DECL_TEXPS(num, _tex32); \ +DECL_TEXPS(num, _clut32); \ +DECL_TEXPS(num, _tex32to16); \ +DECL_TEXPS(num, _tex16to8h); \ + +DECL_TEXPS_(0); +DECL_TEXPS_(1); +DECL_TEXPS_(2); +DECL_TEXPS_(3); +DECL_TEXPS_(4); +DECL_TEXPS_(5); + +// special functions for limitations on ps20 +technique Texture { + pass p0 { + VertexShader = compile vs_2_0 TextureVS(); + PixelShader = compile ps_2_a Texture0_32PS(); + } +} + +VSOUT_F RegularFogVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : TEXCOORD0) +{ + VSOUT_F o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) + o.color = color; + o.fog = pos.z; + return o; +} + +void RegularFogPS(VSOUT_F i, out half4 c0 : COLOR0 +#ifdef WRITE_DEPTH + , out float4 c1 : COLOR1 +#endif + ) +{ + half4 c; + c.xyz = lerp(g_fFogColor.xyz, i.color.xyz, i.fog); \ + c.w = i.color.w; + c0 = ps2FinalColor(c); + DOZWRITE(c1 = i.z;) +} + +technique RegularFog { + pass p0 { + VertexShader = compile vs_2_0 RegularFogVS(); + PixelShader = compile ps_2_a RegularFogPS(); + } +}; + +VSOUT_TF TextureFogVS(float4 pos : POSITION, + half4 color : COLOR0, + float3 tex0 : TEXCOORD1, + float4 z : TEXCOORD0) +{ + VSOUT_TF o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; + o.color = color; + o.fog = pos.z; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) +#ifdef PERSPECTIVE_CORRECT_TEX + o.tex = tex0; +#else + o.tex = tex0.xy/tex0.z; +#endif + return o; +} + +#ifdef WRITE_DEPTH + +#define DECL_TEXFOGPS(num, bit) \ +void TextureFog##num##bit##PS(VSOUT_TF i, out half4 c0 : COLOR0, out float4 c1 : COLOR1 ) \ +{ \ + half4 c = ps2CalcShade(ps2shade##num##bit(i.tex), i.color); \ + c.xyz = lerp(g_fFogColor.xyz, c.xyz, i.fog); \ + c0 = ps2FinalColor(c); \ + c1 = i.z; \ +} \ + +#else + +#define DECL_TEXFOGPS(num, bit) \ +void TextureFog##num##bit##PS(VSOUT_TF i, out half4 c0 : COLOR0) \ +{ \ + half4 c = ps2CalcShade(ps2shade##num##bit(i.tex), i.color); \ + c.xyz = lerp(g_fFogColor.xyz, c.xyz, i.fog); \ + c0 = ps2FinalColor(c); \ +} \ + +#endif + +#define DECL_TEXFOGPS_(num) \ +DECL_TEXFOGPS(num, _32); \ +DECL_TEXFOGPS(num, _tex32); \ +DECL_TEXFOGPS(num, _clut32); \ +DECL_TEXFOGPS(num, _tex32to16); \ +DECL_TEXFOGPS(num, _tex16to8h); \ + +DECL_TEXFOGPS_(0); +DECL_TEXFOGPS_(1); +DECL_TEXFOGPS_(2); +DECL_TEXFOGPS_(3); +DECL_TEXFOGPS_(4); +DECL_TEXFOGPS_(5); + +technique TextureFog { + pass p0 { + VertexShader = compile vs_2_0 TextureFogVS(); + PixelShader = compile ps_2_a TextureFog0_32PS(); + } +}; + +//------------------------------------------------------- +// Techniques not related to the main primitive commands +half4 BilinearBitBlt(float2 tex0) +{ + float4 ftex; + float2 ffrac; + + ffrac.xy = frac(tex0*g_fRealTexDims.xy); + ftex.xy = tex0 - ffrac.xy * g_fRealTexDims.zw; + ftex.zw = ftex.xy + g_fRealTexDims.zw; + + float4 off0, off1; + ps2memcoord4_fast(ftex, off0, off1); + half4 c0 = tex2D(g_sMemory, off0.xy); + half4 c1 = tex2D(g_sMemory, off0.zw); + half4 c2 = tex2D(g_sMemory, off1.xy); + half4 c3 = tex2D(g_sMemory, off1.zw); + + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y ); +} + +void BitBltVS(in float4 pos : POSITION, + in half4 tex0 : TEXCOORD0, + in float3 tex : TEXCOORD1, + out float4 opos : POSITION, + out float2 otex0 : TEXCOORD0, + out float2 ointerpos : TEXCOORD1) +{ + opos.xy = pos.xy * g_fBitBltPos.xy + g_fBitBltPos.zw; + ointerpos = opos.xy * g_fBitBltTrans.xy + g_fBitBltTrans.zw; + opos.zw = g_fc0.xy; + otex0 = tex * g_fBitBltTex.xy + g_fBitBltTex.zw; +} + +half4 BitBltPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return tex2D(g_sMemory, ps2memcoord(tex0).xy)*g_fOneColor.xxxy; +} + +// used when AA +half4 BitBltAAPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return BilinearBitBlt(tex0)*g_fOneColor.xxxy; +} + +void BitBltDepthPS(in float2 tex0 : TEXCOORD0, + out float4 c : COLOR0, + out float depth : DEPTH) +{ + c = tex2D(g_sMemory, ps2memcoord(tex0)); + + depth = log(g_fc0.y+dot(c, g_fBitBltZ))*g_fOneColor.w; + c += g_fZBias.y; +} + +void BitBltDepthMRTPS(in float2 tex0 : TEXCOORD0, + out half4 c0 : COLOR0, + out float4 c1 : COLOR1, + out float depth : DEPTH) +{ + c1 = tex2D(g_sMemory, ps2memcoord(tex0)); + + depth = log(g_fc0.y+dot(c1, g_fBitBltZ))*g_fOneColor.w; + c1 += g_fZBias.y; + c0 = g_fc0.x; +} + +// no swizzling +void BitBltDepthTexPS(in float2 tex0 : TEXCOORD0, + out float4 c : COLOR0, + out float depth : DEPTH) +{ + c = tex2D(g_sSrcFinal, tex0); + + depth = log(g_fc0.y+dot(c-g_fZBias.y, g_fBitBltZ))*g_fOneColor.w; + //c += g_fZBias.y; +} + +// no swizzling +void BitBltDepthTexMRTPS(in float2 tex0 : TEXCOORD0, + out half4 c0 : COLOR0, + out float4 c1 : COLOR1, + out float depth : DEPTH) +{ + c1 = tex2D(g_sSrcFinal, tex0); + + depth = log(g_fc0.y+dot(c1-g_fZBias.y, g_fBitBltZ))*g_fOneColor.w; + //c1 += g_fZBias.y; + c0 = g_fc0.x; +} + +technique BitBlt { + pass p0 { + VertexShader = compile vs_1_1 BitBltVS(); + PixelShader = compile ps_2_0 BitBltDepthMRTPS(); + } +} + +/*static const float BlurKernel[9] = { + 0.027601, + 0.066213, + 0.123701, + 0.179952, + 0.205065, + 0.179952, + 0.123701, + 0.066213, + 0.027601 +};*/ + +half4 BilinearFloat16(float2 tex0) +{ + /*float4 ffrac, ftex; + ffrac.xy = frac(tex0); + ftex.xy = (tex0 - ffrac.xy) * g_fInvTexDims.xy + g_fInvTexDims.zw; + ftex.zw = ftex.xy + g_fInvTexDims.xy; + + half4 c0 = tex2D(g_sSrcFinal, ftex.xy); + half4 c1 = tex2D(g_sSrcFinal, ftex.zy); + half4 c2 = tex2D(g_sSrcFinal, ftex.xw); + half4 c3 = tex2D(g_sSrcFinal, ftex.zw); + + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y );*/ + return tex2D(g_sSrcFinal, tex0.xy); +// return 0.55f * tex2D(g_sSrcFinal, tex0.xy) + +// 0.15f * tex2D(g_sSrcFinal, tex0.xy+g_fInvTexDims.xz) + +// 0.15f * tex2D(g_sSrcFinal, tex0.xy+g_fInvTexDims.zy) + +// 0.15f * tex2D(g_sSrcFinal, tex0.xy+g_fInvTexDims.xy); +} + +half4 CRTCTargInterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float finter = tex1D(g_sBitwiseANDX, ointerpos.y).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = BilinearFloat16(tex0); + c.w = g_fc0.w*c.w * g_fOneColor.x + g_fOneColor.y; + return c.zyxw; +} + +half4 CRTCTargPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float4 c = BilinearFloat16(tex0); + c.w = g_fc0.w*c.w * g_fOneColor.x + g_fOneColor.y; + return c.zyxw; +} + +half4 CRTCInterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + float finter = tex1D(g_sBitwiseANDX, ointerpos.y).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = BilinearBitBlt(filtcoord); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c.zyxw; +} + +half4 CRTCPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float2 filtcoord = (tex0/*-frac(tex0)*/)*g_fInvTexDims.xy+g_fInvTexDims.zw; + half4 c = BilinearBitBlt(filtcoord); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c.zyxw; +} + +half4 CRTC24InterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + float finter = tex1D(g_sBitwiseANDX, ointerpos.y).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = tex2D(g_sMemory, ps2memcoord(filtcoord).xy).x; + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c.zyxw; +} + +half4 CRTC24PS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + half4 c = tex2D(g_sMemory, ps2memcoord(filtcoord).xy).x; + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c.zyxw; +} + +technique CRTC { + pass p0 { + VertexShader = compile vs_1_1 BitBltVS(); + PixelShader = compile ps_2_0 CRTCTargInterPS(); + } +} + +half4 ZeroPS() : COLOR +{ + return g_fOneColor.x; +} + +half4 BaseTexturePS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return tex2D(g_sSrcFinal, tex0) * g_fOneColor; +} + +// inverse of 32->16bit conversion +half4 Convert16to32PS(float2 tex0 : TEXCOORD0) : COLOR +{ + float4 final; + float2 ffrac = fmod(tex0+g_fTexDims.zw, g_fTexOffset.xy); + tex0.y += g_fTexDims.y * ffrac.y; + + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + tex0.y += g_fTexOffset.w; + } + + float4 lower = tex2D(g_sSrcFinal, tex0); + float4 upper = tex2D(g_sSrcFinal, tex0+g_fPageOffset.xy); + + //return half4(frac(32*tex0.x),frac(7*tex0.y),0,1); + final.zy = tex3D(g_sConv32to16, lower.zyx).xy + lower.ww*g_fPageOffset.zw; + final.xw = tex3D(g_sConv32to16, upper.zyx).xy + upper.ww*g_fPageOffset.zw; + return final; +} + +// use when texture is not tiled and converting from 32bit to 16bit +// one condition is that the converted texture has to keep the same block configuration +// every 16 32bit horz pixels gets converted to 16x2 16bit horz pixels. +// the first row is the first 8 pixels, the second row is the last 8 pixels +// the last 8 columns are the upper bits +half4 Convert32to16PS(float2 tex0 : TEXCOORD0) : COLOR +{ + bool upper = false; + float2 ffrac = fmod(tex0+g_fTexDims.zw, g_fTexOffset.xy); + //tex0 += g_fTexDims.xy * ffrac; + //tex0.y += g_fTexDims.y * ffrac.y; + tex0.y += ffrac.y; + //tex0.x -= g_fc0.w*ffrac.x; + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + upper = true; + } + if( ffrac.y >= g_fTexOffset.w ) { + tex0.y -= g_fTexOffset.y; + tex0.x += g_fTexOffset.z; + } + + //return half4(frac(32*tex0.x),frac(7*tex0.y),0,1); + half4 color = tex2D(g_sSrcFinal, tex0)*g_fc0.yyyw; + float2 uv = upper ? color.xw : color.zy; + return tex2D(g_sConv16to32, uv*g_fPageOffset.xy+g_fPageOffset.zw).zyxw*g_fOneColor; +} diff --git a/plugins/zerogs/dx/ps2hw_ctx0.fx b/plugins/zerogs/dx/ps2hw_ctx0.fx new file mode 100644 index 0000000000..0e2b100f20 --- /dev/null +++ b/plugins/zerogs/dx/ps2hw_ctx0.fx @@ -0,0 +1,33 @@ +// main ps2 memory, each pixel is stored in 32bit color +texture g_txMem0; + +sampler g_sMemory : register(s0) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Clamp; + AddressV = Clamp; +}; + +// per context pixel shader constants +half4 fTexAlpha2 : register(c2); + +float4 g_fTexOffset : register(c4); // converts the page and block offsets into the mem addr/1024 +float4 g_fTexDims : register(c6); // mult by tex dims when accessing the block texture +float4 g_fTexBlock : register(c8); + +float4 g_fClampExts : register(c10); // if clamping the texture, use (minu, minv, maxu, maxv) +float4 TexWrapMode : register(c12); // 0 - repeat/clamp, 1 - region rep (use fRegRepMask) + +float4 g_fRealTexDims : register(c14); // tex dims used for linear filtering (w,h,1/w,1/h) + +// (alpha0, alpha1, 1 if highlight2 and tcc is rgba, 1-y) +half4 g_fTestBlack : register(c16); // used for aem bit + +float4 g_fPageOffset : register(c18); + +half4 fTexAlpha : register(c20); + +// vertex shader constants +float4 g_fPosXY : register(c2); \ No newline at end of file diff --git a/plugins/zerogs/dx/ps2hw_ctx1.fx b/plugins/zerogs/dx/ps2hw_ctx1.fx new file mode 100644 index 0000000000..f9423a9019 --- /dev/null +++ b/plugins/zerogs/dx/ps2hw_ctx1.fx @@ -0,0 +1,32 @@ +texture g_txMem1; + +sampler g_sMemory : register(s1) = sampler_state { + Texture = ; + MipFilter = POINT; + MinFilter = POINT; + MagFilter = POINT; + AddressU = Clamp; + AddressV = Clamp; +}; + +// per context pixel shader constants +half4 fTexAlpha2 : register(c3); + +float4 g_fTexOffset : register(c5); // converts the page and block offsets into the mem addr/1024 +float4 g_fTexDims : register(c7); // mult by tex dims when accessing the block texture +float4 g_fTexBlock : register(c9); + +float4 g_fClampExts : register(c11); // if clamping the texture, use (minu, minv, maxu, maxv) +float4 TexWrapMode : register(c13); // 0 - repeat/clamp, 1 - region rep (use fRegRepMask) + +float4 g_fRealTexDims : register(c15); // tex dims used for linear filtering (w,h,1/w,1/h) + +// (alpha0, alpha1, 1 if highlight2 and tcc is rgba, 1-y) +half4 g_fTestBlack : register(c17); // used for aem bit + +float4 g_fPageOffset : register(c19); + +half4 fTexAlpha : register(c21); + +// vertex shader constants +float4 g_fPosXY : register(c3); \ No newline at end of file diff --git a/plugins/zerogs/dx/targets.cpp b/plugins/zerogs/dx/targets.cpp new file mode 100644 index 0000000000..ea8bd8af88 --- /dev/null +++ b/plugins/zerogs/dx/targets.cpp @@ -0,0 +1,3729 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "x86.h" +#include "Regs.h" +#include "zerogs.h" +#include "resource.h" + +#include "targets.h" + +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +extern int g_GameSettings; +using namespace ZeroGS; +extern int g_TransferredToGPU; +extern BOOL g_bIsLost; +extern LPD3DTEX ptexConv16to32; + +#ifdef RELEASE_TO_PUBLIC +#define INC_RESOLVE() +#else +#define INC_RESOLVE() ++g_nResolve +extern u32 g_nResolve; +extern BOOL g_bSaveTrans; +#endif + +namespace ZeroGS { + CRenderTargetMngr s_RTs, s_DepthRTs; + CBitwiseTextureMngr s_BitwiseTextures; + CMemoryTargetMngr g_MemTargs; + + extern BYTE s_AAx, s_AAy; + extern BYTE bIndepWriteMasks; + extern BOOL s_bBeginScene; + extern D3DFORMAT g_RenderFormat; + extern DXVEC4 g_vdepth; + extern int icurctx; + + extern LPD3DVS pvsBitBlt; + extern LPD3DPS ppsBitBlt[2], ppsBitBltDepth[2], ppsBitBltDepthTex[2], ppsOne; + extern LPD3DPS ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; + extern LPD3DVB pvbRect; +} + +extern LPD3DTEX s_ptexCurSet[2]; +extern LPD3DTEX ptexBilinearBlocks; +extern IDirect3DVolumeTexture9* ptexConv32to16; +BOOL g_bSaveZUpdate = 0; + +//////////////////// +// Render Targets // +//////////////////// +ZeroGS::CRenderTarget::CRenderTarget() : psurf(NULL), psys(NULL), ptex(NULL), ptexFeedback(NULL), psurfFeedback(NULL) +{ + nUpdateTarg = 0; + targoffx = targoffy = 0; +} + +ZeroGS::CRenderTarget::~CRenderTarget() +{ + Destroy(); +} + +CRenderTarget::CRenderTarget(const frameInfo& frame, CRenderTarget& r) +{ + lastused = timeGetTime(); + fbp = frame.fbp; + fbw = frame.fbw; + fbh = frame.fbh; + psm = (u8)frame.psm; + fbm = frame.fbm; + + // find the xy offset + int blockheight = (frame.psm&2) ? 64 : 32; + int scanlinewidth = 0x2000*(fbw>>6); + + // round down to nearest block and scanline + int startheight = ((256*(fbp-r.fbp))/scanlinewidth) * blockheight; + int offset = ((256*(fbp-r.fbp))%scanlinewidth) / 0x2000; + + targoffx = offset*64; + targoffy = startheight; + targheight = r.targheight; + + pmimicparent = &r; + + vposxy.x = 2.0f * (32767.0f / 8.0f) / (float)fbw; + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)targheight; + vposxy.z = -1+(2.0f*(float)targoffx-0.5f)/fbw; + vposxy.w = 1+(-2.0f*(float)targoffy+0.5f)/(float)targheight; + status = 0; + + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + ptex = r.ptex; + if( ptex != NULL ) ptex->AddRef(); + psurf = r.psurf; + if( psurf != NULL ) psurf->AddRef(); + psys = r.psys; + if( psys != NULL ) psys->AddRef(); + + nUpdateTarg = 0; + ptexFeedback = NULL; + psurfFeedback = NULL; +} + +BOOL ZeroGS::CRenderTarget::Create(const frameInfo& frame) +{ + Resolve(); + Destroy(); + + lastused = timeGetTime(); + fbp = frame.fbp; + fbw = frame.fbw; + fbh = frame.fbh; + psm = (u8)frame.psm; + fbm = frame.fbm; + pmimicparent = NULL; + + vposxy.x = 2.0f * (32767.0f / 8.0f) / (float)fbw; + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; + vposxy.z = -1+((float)targoffx-0.5f)/fbw; + vposxy.w = 1+((float)targoffy+0.5f)/fbh; + status = 0; + + if( fbw > 0 && fbh > 0 ) { + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<CreateOffscreenPlainSurface(fbw<GetSurfaceLevel(0, &psurf)); + } + + if( FAILED(hr) ) { + Destroy(); + return FALSE; + } + + targheight = fbh; + status = TS_NeedUpdate; + } + else { + start = end = 0; + } + + return TRUE; +} + +void ZeroGS::CRenderTarget::Destroy() +{ + SAFE_RELEASE(psurf); + SAFE_RELEASE(psys); + SAFE_RELEASE(ptex); + SAFE_RELEASE(ptexFeedback); + SAFE_RELEASE(psurfFeedback); +} + +void ZeroGS::CRenderTarget::SetTarget(int fbplocal, const Rect2& scissor, int context) +{ + int dy = 0; + + if( fbplocal != fbp ) { + DXVEC4 v; + + // will be rendering to a subregion + u32 bpp = (psm&2) ? 2 : 4; + assert( ((256/bpp)*(fbplocal-fbp)) % fbw == 0 ); + assert( fbplocal >= fbp ); + + dy = ((256/bpp)*(fbplocal-fbp)) / fbw; + + v.x = vposxy.x; + v.y = vposxy.y; + v.z = vposxy.z; + v.w = vposxy.w - dy*2.0f/(float)fbh; + SETCONSTF(GPU_POSXY0+context, v); + } + else + SETCONSTF(GPU_POSXY0+context, vposxy); + + RECT rc; + + // set render states + rc.left = scissor.x0>>3; + rc.top = (scissor.y0>>3) + dy; + rc.right = (scissor.x1>>3)+1; + rc.bottom = (scissor.y1>>3)+1+dy; + rc.right = min(rc.right, fbw); + rc.bottom = min(rc.bottom, fbh); + + rc.left += targoffx; rc.right += targoffx; + rc.top += targoffy; rc.bottom += targoffy; + rc.left <<= s_AAx; + rc.top <<= s_AAy; + rc.right <<= s_AAx; + rc.bottom <<= s_AAy; +// rc.right--; +// rc.bottom--; + + scissorrect = rc; +} + +void ZeroGS::CRenderTarget::SetViewport() +{ + D3DVIEWPORT9 view; + view.Width = fbw<SetViewport(&view); +} + +static int g_bSaveResolved = 0; +extern int s_nResolved; + +void ZeroGS::CRenderTarget::Resolve() +{ + if( psurf != NULL && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { + + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( (IsDepth() && !ZeroGS::IsWriteDepth()) || s_nResolved > 10 || (g_GameSettings&GAME_NOTARGETRESOLVE) || targoffx != 0 || targoffy != 0) { + // don't resolve if depths aren't used + status = TS_Resolved; + return; + } + + D3DLOCKED_RECT locksrc; + pd3dDevice->GetRenderTargetData(psurf, psys); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + D3DXSaveSurfaceToFile("resolved.tga", D3DXIFF_TGA, psys, NULL, NULL); + g_bSaveResolved = 0; + } +#endif + + psys->LockRect(&locksrc, NULL, D3DLOCK_READONLY); + _Resolve(locksrc, fbp, fbw, fbh, psm, fbm); + psys->UnlockRect(); + + status = TS_Resolved; + } +} + +void ZeroGS::CRenderTarget::Resolve(int startrange, int endrange) +{ + assert( startrange < end && endrange > start ); // make sure it at least intersects + + if( psurf != NULL && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { + + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + D3DXSaveSurfaceToFile("resolved.tga", D3DXIFF_TGA, psys, NULL, NULL); + g_bSaveResolved = 0; + } +#endif + + if((g_GameSettings&GAME_NOTARGETRESOLVE) || targoffx != 0 || targoffy != 0) { + status = TS_Resolved; + return; + } + + int blockheight = (psm&2) ? 64 : 32; + int resolvefbp = fbp, resolveheight = fbh; + + int scanlinewidth = 0x2000*(fbw>>6); + + // in now way should data be overwritten!, instead resolve less + if( endrange < end ) { + // round down to nearest block and scanline + resolveheight = ((endrange-start)/(0x2000*(fbw>>6))) * blockheight; + if( resolveheight <= 32 ) { + status = TS_Resolved; + return; + } + } + else if( startrange > start ) { + // round up to nearest block and scanline + resolvefbp = startrange + scanlinewidth - 1; + resolvefbp -= resolvefbp % scanlinewidth; + + resolveheight = fbh-((resolvefbp-fbp)*blockheight/scanlinewidth); + if( resolveheight <= 64 ) { // this is a total hack, but kh doesn't resolve now + status = TS_Resolved; + return; + } + + resolvefbp >>= 8; + } + + D3DLOCKED_RECT locksrc; + pd3dDevice->GetRenderTargetData(psurf, psys); + + psys->LockRect(&locksrc, NULL, D3DLOCK_READONLY); + + if( fbp != resolvefbp ) + locksrc.pBits = (u8*)locksrc.pBits + ((resolvefbp-fbp)*256/scanlinewidth)*blockheight*locksrc.Pitch; + + _Resolve(locksrc, resolvefbp, fbw, resolveheight, psm, fbm); + psys->UnlockRect(); + + status = TS_Resolved; + } +} + +void ZeroGS::CRenderTarget::Update(int context, ZeroGS::CRenderTarget* pdepth) +{ + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + assert( targoffx == 0 && targoffy == 0 ); + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + // assume depth already set + //pd3dDevice->SetDepthStencilSurface(psurfDepth); +// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); +// else + pd3dDevice->SetRenderTarget(1, NULL); + + pd3dDevice->SetRenderTarget(0, psurf); + + DXVEC4 v = DXVEC4(1,1,-0.5f/(float)(fbw<second == this ) { + DEBUG_LOG("zerogs: updating self"); + nUpdateTarg = 0; + } + } + else if( ittarg->second == this ) { + DEBUG_LOG("zerogs: updating self"); + nUpdateTarg = 0; + } + } + + if( nUpdateTarg ) { + + pd3dDevice->SetTexture(SAMP_FINAL, ittarg->second->ptex); + + //assert( ittarg->second->fbw == fbw ); + int offset = (fbp-ittarg->second->fbp)*64/fbw; + if( psm & 2 ) // 16 bit + offset *= 2; + + v.x = 1; + v.y = (float)targheight / ittarg->second->fbh; + v.z = 0.25f / (fbw << s_AAx); + v.w = (float)offset / ittarg->second->fbh + 0.25f / (ittarg->second->fbh << s_AAy); + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = v.w = 1; + SETCONSTF(GPU_ONECOLOR, v); + + pd3dDevice->SetPixelShader(ppsBaseTexture); + nUpdateTarg = 0; + } + else { + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + tex0Info texframe; + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + + // write color and zero out stencil buf, always 0 context! + // force bilinear if using AA + SetTexVariablesInt(0, (s_AAx || s_AAy)?2:0, texframe, pmemtarg, 1); + + v = DXVEC4(1,1,0,0); + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = 1; + v.y = 2; + SETCONSTF(GPU_ONECOLOR, v); + + assert( psurf != NULL ); + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + if( ZeroGS::IsWriteDestAlphaTest() ) { + SETRS(D3DRS_STENCILENABLE, TRUE); + SETRS(D3DRS_STENCILWRITEMASK, 0xff); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO); + } + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsBitBlt[s_AAx]); + } + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + // fill stencil buf only + if( ZeroGS::IsWriteDestAlphaTest() && !(g_GameSettings&GAME_NOSTENCIL) ) { + SETRS(D3DRS_COLORWRITEENABLE, 0); + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + SETRS(D3DRS_ALPHAREF, 0xff); + + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILREF, 1); + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + } + + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + +// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); +// else + if( conf.mrtdepth && pdepth != NULL && ZeroGS::IsWriteDepth() ) + pd3dDevice->SetRenderTarget(1, pdepth->psurf); + + status = TS_Resolved; + + // reset since settings changed + vb[0].bVarsTexSync = 0; + ZeroGS::ResetAlphaVariables(); +} + +void ZeroGS::CRenderTarget::ConvertTo32() +{ + LPD3DTEX ptexConv; + LPD3DSURF psurfConv; + + s_RTs.DestroyChildren(this); + + // create + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfConv)); + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + // tex coords, test ffx bikanel island when changing these + float dx = 0.5f / (fbw << s_AAx); + float dy = 0.5f / (fbh << s_AAy); + + DXVEC4 v = DXVEC4(1, 1, -dx, dy); + SETCONSTF(GPU_BITBLTPOS, v); + + v.z = 0.5f*dx; + v.w = 0.5f*dy; + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = 1; + v.w = 1; // since all alpha is mult by 2 + SETCONSTF(GPU_ONECOLOR, v); + + v.x = 16.0f / (float)fbw; + v.y = 64.0f / (float)fbh; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0, v); + + v.x = 8.0f / (float)fbw; + v.y = 0; + v.z = 0; + v.w = 0.25f; + SETCONSTF(GPU_PAGEOFFSET0, v); + + v.x = 1; + v.y = -0.5f; + v.z = 0; + v.w = 0.0001f; + SETCONSTF(GPU_TEXDIMS0, v); + + v.x = 0; + SETCONSTF(GPU_TEXBLOCK0, v); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + // assume depth already set !? + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetRenderTarget(0, psurfConv); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv32to16); + pd3dDevice->SetTexture(SAMP_FINAL, ptex); + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); + + if( s_ptexCurSet[0] == ptex ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == ptex ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + fbh /= 2; // have 16 bit surfaces are usually 2x higher + targheight /= 2; + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsConvert16to32); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + +#ifdef _DEBUG + //g_bSaveZUpdate = 1; + //D3DXSaveSurfaceToFile("tex3.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); + if( g_bSaveZUpdate ) { + // buggy + D3DXSaveSurfaceToFile("tex3.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); + D3DXSaveSurfaceToFile("tex1.tga", D3DXIFF_TGA, psurf, NULL, NULL); + + //LPD3DTEX ptemp; + //pd3dDevice->CreateTexture(fbw, fbh, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptemp, NULL); + + LPD3DSURF ptempsys; + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<GetRenderTargetData(psurf, psys); + + psys->LockRect(&srclock, NULL, D3DLOCK_READONLY); + ptempsys->LockRect(&dstlock, NULL, 0); + DWORD cols[2]; + float tempf[4]; + for(int i = 0; i < fbh; ++i) { + for(int j = 0; j < fbw; ++j) { + D3DXVECTOR4_16F* pdst = (D3DXVECTOR4_16F*)dstlock.pBits + fbw*i + j; + int jj = 2*j - (j%16); + if( (j%16) >=8 ) jj += 8; + int ii = 2*i - (i%8); + if( j >= fbw/2 ) { ii += 8; jj -= fbw; } + D3DXVECTOR4_16F* psrc = (D3DXVECTOR4_16F*)srclock.pBits + fbw*ii + jj; + //D3DXFloat16To32Array(out, (D3DXFLOAT16*)psrc, 4); + cols[0] = Float16ToARGB(psrc[0]); + cols[1] = Float16ToARGB(psrc[8]); + //cols[0] = (cols[0]&0xff00ff00)|((cols[0]&0xff)<<16)|((cols[0]&0xff0000)>>16); + //cols[1] = (cols[1]&0xff00ff00)|((cols[1]&0xff)<<16)|((cols[1]&0xff0000)>>16); + DWORD col = RGBA32to16(cols[0])|(RGBA32to16(cols[1])<<16); + tempf[2] = (col&0xff)/255.0f; + tempf[1] = ((col>>8)&0xff)/255.0f; + tempf[0] = ((col>>16)&0xff)/255.0f; + tempf[3] = 2*(((col>>24)&0xff)/255.0f); + D3DXFloat32To16Array((D3DXFLOAT16*)pdst, tempf, 4); + } + } + psys->UnlockRect(); + ptempsys->UnlockRect(); + + D3DXSaveSurfaceToFile("tex2.tga", D3DXIFF_TGA, ptempsys, NULL, NULL); + +// SAFE_RELEASE(psys); +// psys = ptempsys; +// +// pd3dDevice->UpdateSurface(ptempsys, NULL, psurfConv, NULL); + } +#endif + + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; + vposxy.w = 1+0.5f/fbh; + + // restore + SAFE_RELEASE(ptex); + SAFE_RELEASE(psurf); + SAFE_RELEASE(psys); + SAFE_RELEASE(ptexFeedback); + SAFE_RELEASE(psurfFeedback); + ptex = ptexConv; + psurf = psurfConv; + + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<SetTexture(SAMP_FINAL, NULL); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); // restore + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + status = TS_Resolved; + + // TODO, reset depth? + if( ZeroGS::icurctx >= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +// use when texture is not tiled and converting from 32bit to 16bit +// one condition is that the converted texture has to keep the same block configuration +// every 16 32bit horz pixels gets converted to 16x2 16bit horz pixels. +// the first row is the first 8 pixels, the second row is the last 8 pixels +// the last 8 columns are the upper bits +void ZeroGS::CRenderTarget::ConvertTo16() +{ + LPD3DTEX ptexConv; + LPD3DSURF psurfConv; + + s_RTs.DestroyChildren(this); + + // create + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfConv)); + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + // tex coords, test ffx bikanel island when changing these + float dx = 0.5f / (fbw << s_AAx); + float dy = 0.5f / (fbh << s_AAy); + + DXVEC4 v = DXVEC4(1, 1, -dx, dy); + SETCONSTF(GPU_BITBLTPOS, v); + + v.z = 0.5f*dx; + v.w = 0.5f*dy; + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = 1; + v.w = 2; // since all alpha is mult by 2 + SETCONSTF(GPU_ONECOLOR, v); + + v.x = 16.0f / (float)fbw; + v.y = 32.0f / (float)fbh; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0, v); + + v.x = 256.0f / 255.0f; + v.y = 256.0f / 255.0f; + v.z = 0.05f / 256.0f; + v.w = -0.001f / 256.0f; + SETCONSTF(GPU_PAGEOFFSET0, v); + + v.x = -0.5f; + v.y = 1; + v.z = 0; + v.w = -0.1f/fbh; + SETCONSTF(GPU_TEXDIMS0, v); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + // assume depth already set !? + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetRenderTarget(0, psurfConv); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv16to32); + pd3dDevice->SetTexture(SAMP_FINAL, ptex); + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); + + if( s_ptexCurSet[0] == ptex ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == ptex ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + fbh *= 2; // have 16 bit surfaces are usually 2x higher + targheight *= 2; + + // need to set a dummy target! +// CRenderTargetMngr::MAPTARGETS::iterator itdepth = s_DepthRTs.mapDummyTargs.find( (fbw<<16)|fbh ); +// CDepthTarget* pnewdepth = NULL; +// if( itdepth == s_DepthRTs.mapDummyTargs.end() ) { +// frameInfo frame; +// frame.fbh = fbh; +// frame.fbw = fbw; +// frame.psm = 0x30; //? +// frame.fbw = fbw; +// frame.fbm = 0; +// pnewdepth = new CDepthTarget(); +// pnewdepth->Create(frame); +// s_DepthRTs.mapDummyTargs[(fbw<<16)|fbh] = pnewdepth; +// } +// else pnewdepth = (CDepthTarget*)itdepth->second; +// +// assert( pnewdepth != NULL ); +// pd3dDevice->SetDepthStencilSurface(pnewdepth->pdepth); + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsConvert32to16); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + +#ifdef _DEBUG + //g_bSaveZUpdate = 1; + if( g_bSaveZUpdate ) { + pd3dDevice->GetRenderTargetData(psurf, psys); + + D3DXSaveSurfaceToFile("tex1.tga", D3DXIFF_TGA, psurfConv, NULL, NULL); + + LPD3DSURF ptempsys; + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<LockRect(&srclock, NULL, D3DLOCK_READONLY); + ptempsys->LockRect(&dstlock, NULL, 0); + DWORD col; + float temp[4]; + for(int i = 0; i < fbh; ++i) { + for(int j = 0; j < fbw; ++j) { + D3DXVECTOR4_16F* pdst = (D3DXVECTOR4_16F*)dstlock.pBits + fbw*i + j; + int jj = j; + int upper = 0; + if( (j%16) >=8 ) { + jj -= 8; + upper = 1; + } + int ii = (i - (i%64))/2 + (i%64); + if( (i%64) >= 32 ) { + ii -= 32; + jj += 8; + } + D3DXVECTOR4_16F* psrc = (D3DXVECTOR4_16F*)srclock.pBits + fbw*ii + jj; + //D3DXFloat16To32Array(out, (D3DXFLOAT16*)psrc, 4); + col = Float16ToARGB(psrc[0]); + if( upper ) col >>= 16; + else col &= 0xffff; + col = RGBA16to32(col); + temp[2] = (col&0xff)/255.0f; + temp[1] = ((col>>8)&0xff)/255.0f; + temp[0] = ((col>>16)&0xff)/255.0f; + temp[3] = 2*(((col>>24)&0xff)/255.0f); + D3DXFloat32To16Array((D3DXFLOAT16*)pdst, temp, 4); + + } + } + psys->UnlockRect(); + ptempsys->UnlockRect(); + + D3DXSaveSurfaceToFile("tex2.tga", D3DXIFF_TGA, ptempsys, NULL, NULL); + + SAFE_RELEASE(psys); + psys = ptempsys; + + pd3dDevice->UpdateSurface(ptempsys, NULL, psurfConv, NULL); + } +#endif + + vposxy.y = -2.0f * (32767.0f / 8.0f) / (float)fbh; + vposxy.w = 1+0.5f/fbh; + + // restore + SAFE_RELEASE(ptex); + SAFE_RELEASE(psurf); + SAFE_RELEASE(psys); + SAFE_RELEASE(ptexFeedback); + SAFE_RELEASE(psurfFeedback); + ptex = ptexConv; + psurf = psurfConv; + + V(pd3dDevice->CreateOffscreenPlainSurface(fbw<SetTexture(SAMP_FINAL, NULL); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); // restore + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + status = TS_Resolved; + + // TODO, reset depth? + if( ZeroGS::icurctx >= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +void ZeroGS::CRenderTarget::_CreateFeedback() +{ + if( ptexFeedback == NULL ) { + // create + assert( pmimicparent == NULL ); + + HRESULT hr; + V(pd3dDevice->CreateTexture(fbw<GetSurfaceLevel(0, &psurfFeedback)); + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + + // assume depth already set +// if( conf.mrtdepth && bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); +// else + pd3dDevice->SetRenderTarget(1, NULL); + + // tex coords, test ffx bikanel island when changing these + float dx = 0.5f / (fbw << s_AAx); + float dy = 0.5f / (fbh << s_AAy); + + DXVEC4 v = DXVEC4(1, 1, -dx, dy); + SETCONSTF(GPU_BITBLTPOS, v); + + v.z = 0.5f*dx; + v.w = 0.5f*dy; + SETCONSTF(GPU_BITBLTTEX, v); + + v.x = v.y = v.z = 1; + v.w = 1; // since all alpha is mult by 2 + SETCONSTF(GPU_ONECOLOR, v); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + pd3dDevice->SetRenderTarget(0, psurfFeedback); + pd3dDevice->SetTexture(SAMP_FINAL, ptex); + + if( s_ptexCurSet[0] == ptexFeedback ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == ptexFeedback ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + // render with an AA shader if possible (bilinearly interpolates data) + pd3dDevice->SetPixelShader(ppsBaseTexture); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + // restore + swap(ptex, ptexFeedback); + swap(psurf, psurfFeedback); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + + pd3dDevice->SetTexture(SAMP_FINAL, NULL); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + status |= TS_FeedbackReady; + + // TODO, reset depth? + if( ZeroGS::icurctx >= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + } +} + +ZeroGS::CDepthTarget::CDepthTarget() : CRenderTarget(), pdepth(NULL) {} + +ZeroGS::CDepthTarget::~CDepthTarget() +{ + Destroy(); +} + +BOOL ZeroGS::CDepthTarget::Create(const frameInfo& frame) +{ + if( !CRenderTarget::Create(frame) ) return FALSE; + + if( psm == 0x31 ) fbm = 0xff000000; + else fbm = 0; + + HRESULT hr; + V(pd3dDevice->CreateDepthStencilSurface(fbw<CreateDepthStencilSurface(fbw, fbh, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, FALSE, &pdepth, NULL)); + } + + if( FAILED(hr) ) + return FALSE; + + status = TS_NeedUpdate; + + return TRUE; +} + +void ZeroGS::CDepthTarget::Destroy() +{ + if( pd3dDevice != NULL ) { + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetDepthStencilSurface(NULL); + vb[0].bVarsSetTarg = 0; + vb[1].bVarsSetTarg = 0; + } + + CRenderTarget::Destroy(); + SAFE_RELEASE(pdepth); +} + +extern int g_nDepthUsed; // > 0 if depth is used + +void ZeroGS::CDepthTarget::Resolve() +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() && !(g_GameSettings&GAME_NODEPTHRESOLVE) ) + CRenderTarget::Resolve(); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) || targoffx != 0 || targoffy != 0 ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +void ZeroGS::CDepthTarget::Resolve(int startrange, int endrange) +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() ) CRenderTarget::Resolve(startrange, endrange); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +extern int g_nDepthUpdateCount; + +void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) +{ + assert( !(status & TS_Virtual) ); + + CRenderTarget* pusetarg = NULL; + if( nUpdateTarg ) { + CRenderTargetMngr::MAPTARGETS::iterator ittarg = s_DepthRTs.mapTargets.find(nUpdateTarg); + if( ittarg == s_DepthRTs.mapTargets.end() || ittarg->second == this) { + DEBUG_LOG("zerogs: updating self"); + nUpdateTarg = 0; + } + else pusetarg = ittarg->second; + } + + tex0Info texframe; + CMemoryTarget* pmemtarg = NULL; + if( pusetarg == NULL ) { + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + SETRS(D3DRS_SCISSORTESTENABLE, FALSE); + SETRS(D3DRS_ALPHABLENDENABLE, FALSE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, TRUE); + SETRS(D3DRS_ZWRITEENABLE, TRUE); + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_ZFUNC, D3DCMP_ALWAYS); + + DXVEC4 v = DXVEC4(1,1,-0.5f/(float)(fbw<SetTexture(SAMP_FINAL, pusetarg->ptex); + + //assert( pusetarg->fbw == fbw ); + int offset = (fbp-pusetarg->fbp)*64/fbw; + if( psm & 2 ) // 16 bit + offset *= 2; + + v.x = 1; + v.y = (float)fbh / pusetarg->fbh; + v.z = 0.25f / (fbw << s_AAx); + v.w = (float)offset / pusetarg->fbh + 0.25f / (pusetarg->fbh << s_AAy); + SETCONSTF(GPU_BITBLTTEX, v); + } + else { + // write color and zero out stencil buf, always 0 context! + SetTexVariablesInt(0, 0, texframe, pmemtarg, 1); + + DXVEC4 v = DXVEC4(1,1,0.5f/(float)fbw,0.5f/(float)fbh); + SETCONSTF(GPU_BITBLTTEX, v); + } + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + v.x = 1; + v.y = 2; + v.z = (psm&3)==2?1.0f:0.0f; + v.w = g_filog32; + SETCONSTF(GPU_ONECOLOR, v); + + assert( psurf != NULL ); + + DXVEC4 vdepth = ((255.0f/256.0f)*g_vdepth); + if( psm == PSMT24Z ) vdepth.w = 0; + else if( psm != PSMT32Z ) { vdepth.z = vdepth.w = 0; } + SETCONSTF(GPU_BITBLTZ, ((255.0f/256.0f)*vdepth)); + + assert( pdepth != NULL ); + + if( ZeroGS::IsWriteDepth() && conf.mrtdepth && bIndepWriteMasks) { + // write in MRT1 + pd3dDevice->SetRenderTarget(1, psurf); + pd3dDevice->SetRenderTarget(0, prndr->psurf); + SETRS(D3DRS_COLORWRITEENABLE, 0); + SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + } + else { + // turn off writes? + if( bIndepWriteMasks ) { + pd3dDevice->SetRenderTarget(0, prndr->psurf); + SETRS(D3DRS_COLORWRITEENABLE, 0); + } + else pd3dDevice->SetRenderTarget(0, psurf); + } + + SetViewport(); + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + pd3dDevice->SetDepthStencilSurface(pdepth); + + if( pusetarg != NULL ) { + pd3dDevice->SetPixelShader(ppsBitBltDepthTex[conf.mrtdepth]); + } + else { + pd3dDevice->SetPixelShader(ppsBitBltDepth[conf.mrtdepth]); + } + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + status = TS_Resolved; + + if( conf.mrtdepth && bIndepWriteMasks ) { + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + } + + if( !ZeroGS::IsWriteDepth() ) { + pd3dDevice->SetRenderTarget(1, NULL); + } + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + +#ifdef _DEBUG + if( g_bSaveZUpdate ) { + if( pusetarg != NULL ) + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, pusetarg->ptex, NULL); + else + SaveTex(&texframe, 1); + D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, psurf, NULL, NULL); + } + //pd3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, 0, 0); +#endif +} + +void ZeroGS::CDepthTarget::SetDepthTarget() +{ + pd3dDevice->SetDepthStencilSurface(pdepth); + + if( conf.mrtdepth && ZeroGS::IsWriteDepth() ) + pd3dDevice->SetRenderTarget(1, psurf); +} + +void ZeroGS::CRenderTargetMngr::Destroy() +{ + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) + delete it->second; + mapTargets.clear(); + for(MAPTARGETS::iterator it = mapDummyTargs.begin(); it != mapDummyTargs.end(); ++it) + delete it->second; + mapDummyTargs.clear(); +} + +CRenderTarget* ZeroGS::CRenderTargetMngr::GetTarg(const frameInfo& frame, DWORD opts, int maxposheight) +{ + if( frame.fbw <= 0 || frame.fbh <= 0 ) + return NULL; + + u32 key = frame.fbp|(frame.fbw<<16); + MAPTARGETS::iterator it = mapTargets.find(key); + + // only enforce height if frame.fbh <= 0x1c0 + bool bfound = it != mapTargets.end(); + if( bfound ) { + if( opts&TO_StrictHeight ) { + bfound = it->second->fbh == frame.fbh; + + if( (g_GameSettings&GAME_PARTIALDEPTH) && !bfound ) { + MAPTARGETS::iterator itnew = mapTargets.find(key+1); + if( itnew != mapTargets.end() && itnew->second->fbh == frame.fbh ) { + // found! delete the previous and restore + delete it->second; + mapTargets.erase(it); + + it = mapTargets.insert(MAPTARGETS::value_type(key, itnew->second)).first; // readd + mapTargets.erase(itnew); // delete old + + bfound = true; + } + } + } + else { + if( (frame.psm&2)==(it->second->psm&2) && !(g_GameSettings & GAME_FULL16BITRES) ) + bfound = (frame.fbh > 0x1c0 || it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + } + + if( !bfound ) { + // might be a virtual target + it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + bfound = it != mapTargets.end() && ((opts&TO_StrictHeight) ? it->second->fbh == frame.fbh : it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + + if( bfound && (frame.psm&2) && !(it->second->psm&2) && (g_GameSettings&GAME_FULL16BITRES) ) { + // mgs3 + if( frame.fbh > it->second->fbh ) { + bfound = false; + } + } + + if( bfound ) { + + // can be both 16bit and 32bit + if( (frame.psm&2) != (it->second->psm&2) ) { + // a lot of games do this actually... +#ifdef _DEBUG + WARN_LOG("Really bad formats! %d %d\n", frame.psm, it->second->psm); +#endif + if( !(opts&TO_StrictHeight) ) { + if( !(g_GameSettings & GAME_VSSHACKOFF) ) { + if( it->second->psm & 2 ) { + it->second->status |= CRenderTarget::TS_NeedConvert32; + it->second->fbh /= 2; + it->second->targheight /= 2; + } + else { + it->second->status |= CRenderTarget::TS_NeedConvert16; + it->second->fbh *= 2; + it->second->targheight *= 2; + } + } + } + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + else { + // certain variables have to be reset every time + if( (it->second->psm&~1) != (frame.psm&~1) ) { +#ifndef RELEASE_TO_PUBLIC + WARN_LOG("bad formats 2: %d %d\n", frame.psm, it->second->psm); +#endif + it->second->psm = frame.psm; + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + } + + if( it->second->fbm != frame.fbm ) { + //WARN_LOG("bad fbm: 0x%8.8x 0x%8.8x, psm: %d\n", frame.fbm, it->second->fbm, frame.psm); + } + + it->second->fbm &= frame.fbm; + it->second->psm = frame.psm; // have to convert (ffx2) + + if( (it->first & TARGET_VIRTUAL_KEY) && !(opts&TO_Virtual) ) { + // switch + it->second->lastused = timeGetTime(); + return Promote(it->first&~TARGET_VIRTUAL_KEY); + } + + // check if there exists a more recent target that this target could update from + // only update if target isn't mirrored + bool bCheckHalfCovering = (g_GameSettings&GAME_FULL16BITRES) && (it->second->psm&2) && it->second->fbh +32 < frame.fbh; + + for(MAPTARGETS::iterator itnew = mapTargets.begin(); itnew != mapTargets.end(); ++itnew) { + if( itnew->second != it->second && itnew->second->ptex != it->second->ptex && itnew->second->ptexFeedback != it->second->ptex && + itnew->second->lastused > it->second->lastused && !(itnew->second->status & CRenderTarget::TS_NeedUpdate) ) { + + // if new target totally encompasses the current one + if( itnew->second->start <= it->second->start && itnew->second->end >= it->second->end ) { + it->second->status |= CRenderTarget::TS_NeedUpdate; + it->second->nUpdateTarg = itnew->first; + break; + } + + // if 16bit, then check for half encompassing targets + if( bCheckHalfCovering && itnew->second->start > it->second->start && itnew->second->start < it->second->end && itnew->second->end <= it->second->end+0x2000 ) { + it->second->status |= CRenderTarget::TS_NeedUpdate; + it->second->nUpdateTarg = itnew->first; + break; + } + } + } + + it->second->lastused = timeGetTime(); + + return it->second; + } + + // NOTE: instead of resolving, if current render targ is completely outside of old, can transfer + // the data like that. + + // first search for the target + CRenderTarget* ptarg = NULL; + + // have to change, so recreate (find all intersecting targets and Resolve) + u32 besttarg = 0; + + if( !(opts & CRenderTargetMngr::TO_Virtual) ) { + + int start, end; + GetRectMemAddress(start, end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + if( !(opts & CRenderTargetMngr::TO_StrictHeight) ) { + + if( g_GameSettings&GAME_PARTIALPOINTERS ) { + // if there is a render target that wholly encompasses this one, then use the pointer directly + // this render target also has to be small (mgs3) + if( frame.fbh <= 0x40 ) { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end && (it->second->psm&~1) == (frame.psm&~1) && (it->second->fbp&0xff) == 0 ) { + ptarg = new CRenderTarget(frame, *it->second); + besttarg = it->first; + break; + } + } + } + } + } + + CRenderTarget* pbesttarg = NULL; + + if( besttarg == 0 ) { + // if there is only one intersecting target and it encompasses the current one, update the new render target with + // its data instead of resolving then updating (ffx2). Do not change the original target. + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) { +// if( g_GameSettings&GAME_FASTUPDATE ) { +// besttarg = it->first; +// //break; +// } +// else { + if( (g_GameSettings&GAME_FASTUPDATE) || (it->second->fbw == frame.fbw && + // check depth targets only if partialdepth option + (it->second->fbp != frame.fbp|| ((g_GameSettings&GAME_PARTIALDEPTH)&&(opts&CRenderTargetMngr::TO_DepthBuffer))) ) ) { + + if( besttarg != 0 ) { + besttarg = 0; + break; + } + + if( start >= it->second->start && end <= it->second->end ) { + besttarg = it->first; + pbesttarg = it->second; + } + } +// } + } + } + } + + if( besttarg == 0 ) { + // if none found, resolve all + DestroyAll(start, end, frame.fbw); + } + else if( key == besttarg && pbesttarg != NULL ) { + // add one and store in a different location until best targ is processed + mapTargets.erase(besttarg); + besttarg++; + mapTargets[besttarg] = pbesttarg; + } + } + + if( mapTargets.size() > 8 ) { + // release some resources + it = GetOldestTarg(mapTargets); + + // if more than 5s passed since target used, destroy + if( it->second != vb[0].prndr && it->second != vb[1].prndr && it->second != vb[0].pdepth && it->second != vb[1].pdepth && + timeGetTime()-it->second->lastused > 5000 ) { + DestroyChildren(it->second); + delete it->second; + mapTargets.erase(it); + } + } + + if( ptarg == NULL ) { + // not found yet, so create + + if( mapDummyTargs.size() > 8 ) { + it = GetOldestTarg(mapDummyTargs); + + DestroyChildren(it->second); + delete it->second; + mapDummyTargs.erase(it); + } + + it = mapDummyTargs.find( (frame.fbw<<16)|frame.fbh ); + if( it != mapDummyTargs.end() ) { + ptarg = it->second; + mapDummyTargs.erase(it); + + // restore all setttings + ptarg->psm = frame.psm; + ptarg->fbm = frame.fbm; + ptarg->fbp = frame.fbp; + GetRectMemAddress(ptarg->start, ptarg->end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + ptarg->status = CRenderTarget::TS_NeedUpdate; + } + else { + // create anew + ptarg = (opts&TO_DepthBuffer) ? new CDepthTarget() : new CRenderTarget(); + CRenderTargetMngr* pmngrs[2] = { &s_DepthRTs, this == &s_RTs ? &s_RTs : NULL }; + int cur = 0; + + while( !ptarg->Create(frame) ) { + + // destroy unused targets + if( mapDummyTargs.size() > 0 ) { + it = mapDummyTargs.begin(); + delete it->second; + mapDummyTargs.erase(it); + continue; + } + + if( g_MemTargs.listClearedTargets.size() > 0 ) { + g_MemTargs.DestroyCleared(); + continue; + } + else + if( g_MemTargs.listTargets.size() > 32 ) { + g_MemTargs.DestroyOldest(); + continue; + } + + if( pmngrs[cur] == NULL ) { + cur = !cur; + if( pmngrs[cur] == NULL ) { + WARN_LOG("Out of memory!\n"); + delete ptarg; + return NULL; + } + } + + if( pmngrs[cur]->mapTargets.size() == 0 ) + { + pmngrs[cur] = NULL; + cur = !cur; + continue; + } + + it = GetOldestTarg(pmngrs[cur]->mapTargets); + + DestroyTarg(it->second); + pmngrs[cur]->mapTargets.erase(it); + cur = !cur; + } + } + } + + if( (opts & CRenderTargetMngr::TO_Virtual) ) { + ptarg->status = CRenderTarget::TS_Virtual; + key |= TARGET_VIRTUAL_KEY; + + if( (it = mapTargets.find(key)) != mapTargets.end() ) { + + DestroyTarg(it->second); + it->second = ptarg; + ptarg->nUpdateTarg = besttarg; + return ptarg; + } + } + else + assert( mapTargets.find(key) == mapTargets.end()); + + ptarg->nUpdateTarg = besttarg; + mapTargets[key] = ptarg; + return ptarg; +} + +void CRenderTargetMngr::DestroyChildren(CRenderTarget* ptarg) +{ + if(ptarg == NULL) + return; + + MAPTARGETS::iterator ittarg = mapTargets.begin(); + while(ittarg != mapTargets.end()) { + if( ittarg->second->pmimicparent == ptarg ) { + assert( ittarg->second != ptarg ); + delete ittarg->second; + ittarg = mapTargets.erase(ittarg); + } + else ++ittarg; + } +} + +ZeroGS::CRenderTargetMngr::MAPTARGETS::iterator ZeroGS::CRenderTargetMngr::GetOldestTarg(MAPTARGETS& m) +{ + if( m.size() == 0 ) { + return m.end(); + } + + // release some resources + u32 curtime = timeGetTime(); + MAPTARGETS::iterator itmaxtarg = m.begin(); + for(MAPTARGETS::iterator it = ++m.begin(); it != m.end(); ++it) { + if( itmaxtarg->second->lastused-curtime < it->second->lastused-curtime ) itmaxtarg = it; + } + + return itmaxtarg; +} + +void ZeroGS::CRenderTargetMngr::GetTargs(int start, int end, list& listTargets) const +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) listTargets.push_back(it->second); + } +} + +void ZeroGS::CRenderTargetMngr::Resolve(int start, int end) +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) + it->second->Resolve(); + } +} + +void ZeroGS::CMemoryTargetMngr::Destroy() +{ + listTargets.clear(); + listClearedTargets.clear(); +} + +int memcmp_clut16(u16* pSavedBuffer, u16* pClutBuffer, int clutsize) +{ + assert( (clutsize&31) == 0 ); + + // left > 0 only when csa < 16 + int left = ((u32)pClutBuffer & 2) ? 0 : (((u32)pClutBuffer & 0x3ff)/2) + clutsize - 512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + clutsize -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + + if( left > 0 ) { + pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); + + while(left > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + left -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + } + + return 0; +} + +bool ZeroGS::CMemoryTarget::ValidateClut(const tex0Info& tex0) +{ + assert( tex0.psm == psm && PSMT_ISCLUT(psm) && cpsm == tex0.cpsm ); + + int nClutOffset = 0; + int clutsize = 0; + + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 32 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + + assert( clutsize == clut.size() ); + + if( cpsm <= 1 ) { + // memcmp_mmx doesn't work on x86-64 +#ifdef __x86_64__ + if( memcmp(&clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) +#else + if( memcmp_mmx(&clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) +#endif + return false; + } + else { + if( memcmp_clut16((u16*)&clut[0], (u16*)(ZeroGS::g_pbyGSClut+nClutOffset), clutsize) ) + return false; + } + + return true; +} + +int VALIDATE_THRESH = 8; +u32 TEXDESTROY_THRESH = 16; + +bool ZeroGS::CMemoryTarget::ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex) +{ + if( clearmaxy == 0 ) + return true; + + int checkstarty = max(starttex, clearminy); + int checkendy = min(endtex, clearmaxy); + if( checkstarty >= checkendy ) + return true; + + if( validatecount++ > VALIDATE_THRESH ) { + height = 0; + return false; + } + + // lock and compare + D3DLOCKED_RECT lock; + assert( ptex != NULL ); + + if( memory != NULL ) { + assert( memory->ptr != NULL ); + lock.pBits = memory->ptr; + } + else { + assert( ptexsys != NULL ); + ptexsys->LockRect(0, &lock, NULL, D3DLOCK_READONLY); + } + + // memcmp_mmx doesn't work on x86_64 +#ifdef __x86_64__ + int result = memcmp((u8*)lock.pBits + (checkstarty-realy)*4*GPU_TEXWIDTH, ZeroGS::g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); +#else + int result = memcmp_mmx((u8*)lock.pBits + (checkstarty-realy)*4*GPU_TEXWIDTH, ZeroGS::g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); +#endif + + if( memory == NULL ) + ptexsys->UnlockRect(0); + + if( result == 0 || !bDeleteBadTex ) { + if( result == 0 ) clearmaxy = 0; + return result == 0; + } + + // delete clearminy, clearmaxy range (not the checkstarty, checkendy range) + int newstarty = 0; + if( clearminy <= starty ) { + if( clearmaxy < starty + height) { + // preserve end + height = starty+height-clearmaxy; + starty = clearmaxy; + assert(height > 0); + } + else { + // destroy + height = 0; + } + } + else { + // beginning can be preserved + height = clearminy-starty; + } + + clearmaxy = 0; + assert( starty >= realy && starty+height<=realy+realheight ); + + return false; +} + +// used to build clut textures (note that this is for both 16 and 32 bit cluts) +#define BUILDCLUT() { \ + switch(tex0.psm) { \ + case PSMT8: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/2; ++j) { \ + pdst[0] = pclut[psrc[0]]; \ + pdst[1] = pclut[psrc[1]]; \ + pdst[2] = pclut[psrc[2]]; \ + pdst[3] = pclut[psrc[3]]; \ + pdst[4] = pclut[psrc[4]]; \ + pdst[5] = pclut[psrc[5]]; \ + pdst[6] = pclut[psrc[6]]; \ + pdst[7] = pclut[psrc[7]]; \ + pdst += 8; \ + psrc += 8; \ + } \ + } \ + break; \ + case PSMT4: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH; ++j) { \ + pdst[0] = pclut[psrc[0]&15]; \ + pdst[1] = pclut[psrc[0]>>4]; \ + pdst[2] = pclut[psrc[1]&15]; \ + pdst[3] = pclut[psrc[1]>>4]; \ + pdst[4] = pclut[psrc[2]&15]; \ + pdst[5] = pclut[psrc[2]>>4]; \ + pdst[6] = pclut[psrc[3]&15]; \ + pdst[7] = pclut[psrc[3]>>4]; \ + \ + pdst += 8; \ + psrc += 4; \ + } \ + } \ + break; \ + case PSMT8H: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]]; \ + pdst[1] = pclut[psrc[7]]; \ + pdst[2] = pclut[psrc[11]]; \ + pdst[3] = pclut[psrc[15]]; \ + pdst[4] = pclut[psrc[19]]; \ + pdst[5] = pclut[psrc[23]]; \ + pdst[6] = pclut[psrc[27]]; \ + pdst[7] = pclut[psrc[31]]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HH: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]>>4]; \ + pdst[1] = pclut[psrc[7]>>4]; \ + pdst[2] = pclut[psrc[11]>>4]; \ + pdst[3] = pclut[psrc[15]>>4]; \ + pdst[4] = pclut[psrc[19]>>4]; \ + pdst[5] = pclut[psrc[23]>>4]; \ + pdst[6] = pclut[psrc[27]>>4]; \ + pdst[7] = pclut[psrc[31]>>4]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HL: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]&15]; \ + pdst[1] = pclut[psrc[7]&15]; \ + pdst[2] = pclut[psrc[11]&15]; \ + pdst[3] = pclut[psrc[15]&15]; \ + pdst[4] = pclut[psrc[19]&15]; \ + pdst[5] = pclut[psrc[23]&15]; \ + pdst[6] = pclut[psrc[27]&15]; \ + pdst[7] = pclut[psrc[31]&15]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} \ + +#define TARGET_THRESH 0x500 + +extern int g_MaxTexWidth, g_MaxTexHeight; + +//#define SORT_TARGETS +inline list::iterator ZeroGS::CMemoryTargetMngr::DestroyTargetIter(list::iterator& it) +{ + // find the target and destroy + list::iterator itprev = it; ++it; + listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); + + if( listClearedTargets.size() > TEXDESTROY_THRESH ) { + listClearedTargets.pop_front(); + } + + return it; +} + +#if defined(_MSC_VER) && defined(__x86_64__) +extern "C" void UnswizzleZ16Target(void* dst, void* src, int iters); +#endif + +ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info& tex0, int forcevalidate) +{ + int nbStart, nbEnd; + GetRectMemAddress(nbStart, nbEnd, tex0.psm, 0, 0, tex0.tw, tex0.th, tex0.tbp0, tex0.tbw); + assert( nbStart < nbEnd ); + nbEnd = min(nbEnd, 0x00400000); + + int nClutOffset = 0; + int clutsize = 0; + + if( PSMT_ISCLUT(tex0.psm) ) { + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + } + + int start = nbStart / (4*GPU_TEXWIDTH); + int end = (nbEnd + GPU_TEXWIDTH*4 - 1) / (4*GPU_TEXWIDTH); + assert( start < end ); + + for(list::iterator it = listTargets.begin(); it != listTargets.end();) { + + if( it->starty <= start && it->starty+it->height >= end ) { + + assert( it->psm != 0xd ); + + // using clut, validate that same data + if( PSMT_ISCLUT(it->psm) != PSMT_ISCLUT(tex0.psm) ) { + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( PSMT_ISCLUT(tex0.psm) ) { + assert( it->clut.size() > 0 ); + + if( it->psm != tex0.psm || it->cpsm != tex0.cpsm || it->clut.size() != clutsize ) { + // wrong clut + list::iterator itprev = it; + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( tex0.cpsm <= 1 ) { +#ifdef __x86_64__ + if( memcmp(&it->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) { +#else + if( memcmp_mmx(&it->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize) ) { +#endif + ++it; + continue; + } + } + else { + if( memcmp_clut16((u16*)&it->clut[0], (u16*)(ZeroGS::g_pbyGSClut+nClutOffset), clutsize) ) { + ++it; + continue; + } + } + } + else if( PSMT_IS16BIT(tex0.psm) != PSMT_IS16BIT(it->psm) ) { + + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else ++it; + + continue; + } + + if( forcevalidate ) {//&& listTargets.size() < TARGET_THRESH ) { + // do more validation checking. delete if not been used for a while + if( !it->ValidateTex(tex0, start, end, curstamp > it->usedstamp + 3) ) { + if( it->height <= 0 ) { + + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else ++it; + continue; + } + } + + it->usedstamp = curstamp; + it->validatecount = 0; + + return &(*it); + } +#ifdef SORT_TARGETS + else if( it->starty >= end ) + break; +#endif + ++it; + } + +#ifdef _DEBUG + PRIM_LOG("memtarget: tbp: %x tbw: %x th: %x psm: %x\n", tex0.tbp0, tex0.tbw, tex0.th, tex0.psm); +#endif + + // couldn't find so create + HRESULT hr; + CMemoryTarget* targ; + + D3DFORMAT fmt = D3DFMT_A8R8G8B8; + if( (PSMT_ISCLUT(tex0.psm) && tex0.cpsm > 1) || tex0.psm == PSMCT16 || tex0.psm == PSMCT16S) { + fmt = D3DFMT_A1R5G5B5; + } + + int widthmult = 1; + if( g_MaxTexHeight < 4096 ) { + if( end-start > g_MaxTexHeight ) + widthmult = 2; + } + + int channels = 1; + if( PSMT_ISCLUT(tex0.psm) ) { + if( tex0.psm == PSMT8 ) channels = 4; + else if( tex0.psm == PSMT4 ) channels = 8; + } + else { + if( PSMT_IS16BIT(tex0.psm) ) { + // 16z needs to be a8r8g8b8 + channels = 2; + } + } + + if( listClearedTargets.size() > 0 ) { + + list::iterator itbest = listClearedTargets.begin(); + while(itbest != listClearedTargets.end()) { + + if( end-start <= itbest->realheight && itbest->fmt == fmt && itbest->widthmult == widthmult ) { + + // check channels + int targchannels = 1; + if( PSMT_ISCLUT(itbest->psm) ) { + if( itbest->psm == PSMT8 ) targchannels = 4; + else if( itbest->psm == PSMT4 ) targchannels = 8; + } + else if( PSMT_IS16BIT(itbest->psm) ) { + targchannels = 2; + } + if( targchannels == channels ) + break; + } + ++itbest; + } + + if( itbest != listClearedTargets.end()) { + listTargets.splice(listTargets.end(), listClearedTargets, itbest); + targ = &listTargets.back(); + targ->validatecount = 0; + } + else { + // create a new + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + } + else { + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + + // fill local clut + if( PSMT_ISCLUT(tex0.psm) ) { + assert( clutsize > 0 ); + targ->cpsm = tex0.cpsm; + targ->clut.reserve(256*4); // no matter what + targ->clut.resize(clutsize); + + if( tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(&targ->clut[0], ZeroGS::g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)&targ->clut[0]; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + } + + if( targ->ptex != NULL ) { + + assert( end-start <= targ->realheight && targ->fmt == fmt && targ->widthmult == widthmult ); + // good enough, so init + targ->realy = targ->starty = start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->height = end-start; + } + + if( targ->ptex == NULL ) { + + // not initialized yet + targ->fmt = fmt; + targ->realy = targ->starty = start; + targ->realheight = targ->height = end-start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->widthmult = widthmult; + + // alloc the mem + while( FAILED(pd3dDevice->CreateTexture(GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 1, 0, fmt, D3DPOOL_DEFAULT, &targ->ptex, NULL)) ) { + + if( listClearedTargets.size() > 0 ) + listClearedTargets.pop_front(); + else { + if( listTargets.size() == 0 ) { + DEBUG_LOG("Failed to create %dx%x texture\n", GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult); + channels = 1; + } + DestroyOldest(); + } + } + + // lock + V(pd3dDevice->CreateTexture(GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 1, 0, fmt, D3DPOOL_SYSTEMMEM, &targ->ptexsys, NULL)); + assert( targ->ptexsys != NULL ); + } + +#ifndef RELEASE_TO_PUBLIC + g_TransferredToGPU += GPU_TEXWIDTH * channels * 4 * targ->height; +#endif + + D3DLOCKED_RECT lock; + targ->ptexsys->LockRect(0, &lock, NULL, 0); + + // fill with data + if( PSMT_ISCLUT(tex0.psm) ) { + + if( targ->memory == NULL ) { + targ->memory = new CMemoryTarget::MEMORY(); + targ->memory->ptr = (BYTE*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); + targ->memory->ref = 1; + } + + memcpy_amd(targ->memory->ptr, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); + + u8* psrc = (u8*)(ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + if( tex0.cpsm <= 1 ) { // 32bit + u32* pclut = (u32*)&targ->clut[0]; + u32* pdst = (u32*)lock.pBits; + + BUILDCLUT(); + } + else { + u16* pclut = (u16*)&targ->clut[0]; + u16* pdst = (u16*)lock.pBits; + + BUILDCLUT(); + } + } + else { + if( tex0.psm == PSMT16Z || tex0.psm == PSMT16SZ ) { + + if( targ->memory == NULL ) { + targ->memory = new CMemoryTarget::MEMORY(); + targ->memory->ptr = (BYTE*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); + targ->memory->ref = 1; + } + + memcpy_amd(targ->memory->ptr, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); + + // needs to be 8 bit, use xmm for unpacking + u16* dst = (u16*)lock.pBits; + u16* src = (u16*)(ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + assert( ((u32)dst)%16 == 0 ); + +#if defined(ZEROGS_SSE2) + int iters = targ->height*GPU_TEXWIDTH/16; + +#if defined(__x86_64__) + UnswizzleZ16Target(dst, src, iters); +#else + __asm { + mov edx, iters + pxor xmm7, xmm7 + mov eax, dst + mov ecx, src + +Z16Loop: + // unpack 64 bytes at a time + movdqa xmm0, [ecx] + movdqa xmm2, [ecx+16] + movdqa xmm4, [ecx+32] + movdqa xmm6, [ecx+48] + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm5, xmm4 + + punpcklwd xmm0, xmm7 + punpckhwd xmm1, xmm7 + punpcklwd xmm2, xmm7 + punpckhwd xmm3, xmm7 + + // start saving + movdqa [eax], xmm0 + movdqa [eax+16], xmm1 + + punpcklwd xmm4, xmm7 + punpckhwd xmm5, xmm7 + + movdqa [eax+32], xmm2 + movdqa [eax+48], xmm3 + + movdqa xmm0, xmm6 + punpcklwd xmm6, xmm7 + + movdqa [eax+64], xmm4 + movdqa [eax+80], xmm5 + + punpckhwd xmm0, xmm7 + + movdqa [eax+96], xmm6 + movdqa [eax+112], xmm0 + + add ecx, 64 + add eax, 128 + sub edx, 1 + jne Z16Loop + } +#endif // __x86_64__ +#else + for(int i = 0; i < targ->height; ++i) { + for(int j = 0; j < GPU_TEXWIDTH; ++j) { + dst[0] = src[0]; dst[1] = 0; + dst[2] = src[1]; dst[3] = 0; + dst += 4; + src += 2; + } + } +#endif + } + else { + if( targ->memory != NULL ) { + // release + if( targ->memory->ref > 0 && --targ->memory->ref <= 0 ) { + SAFE_DELETE(targ->memory); + } + targ->memory = NULL; + } + + memcpy_amd(lock.pBits, ZeroGS::g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height ); + } + } + + targ->ptexsys->UnlockRect(0); + + V(pd3dDevice->UpdateTexture(targ->ptexsys, targ->ptex)); + + assert( tex0.psm != 0xd ); + if( PSMT_ISCLUT(tex0.psm) ) + assert( targ->clut.size() > 0 ); + + return targ; +} + +void ZeroGS::CMemoryTargetMngr::ClearRange(int nbStartY, int nbEndY) +{ + int starty = nbStartY / (4*GPU_TEXWIDTH); + int endy = (nbEndY+4*GPU_TEXWIDTH-1) / (4*GPU_TEXWIDTH); + //int endy = (nbEndY+4096-1) / 4096; + + //if( listTargets.size() < TARGET_THRESH ) { + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + + if( it->starty < endy && (it->starty+it->height) > starty ) { + + // intersects, reduce valid texture mem (or totally delete texture) + // there are 4 cases + int miny = max(it->starty, starty); + int maxy = min(it->starty+it->height, endy); + assert(miny < maxy); + + if( it->clearmaxy == 0 ) { + it->clearminy = miny; + it->clearmaxy = maxy; + } + else { + if( it->clearminy > miny ) it->clearminy = miny; + if( it->clearmaxy < maxy ) it->clearmaxy = maxy; + } + } + + ++it; + } +// } +// else { +// for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { +// +// if( it->starty < endy && (it->starty+it->height) > starty ) { +// int newstarty = 0; +// if( starty <= it->starty ) { +// if( endy < it->starty + it->height) { +// // preserve end +// it->height = it->starty+it->height-endy; +// it->starty = endy; +// assert(it->height > 0); +// } +// else { +// // destroy +// it->height = 0; +// } +// } +// else { +// // beginning can be preserved +// it->height = starty-it->starty; +// } +// +// assert( it->starty >= it->realy && it->starty+it->height<=it->realy+it->realheight ); +// if( it->height <= 0 ) { +// list::iterator itprev = it; ++it; +// listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); +// continue; +// } +// } +// +// ++it; +// } +// } +} + +void ZeroGS::CMemoryTargetMngr::DestroyCleared() +{ + for(list::iterator it = listClearedTargets.begin(); it != listClearedTargets.end(); ) { + if( it->usedstamp < curstamp - 2 ) { + it = listClearedTargets.erase(it); + continue; + } + + ++it; + } + + if( (curstamp % 3) == 0 ) { + // purge old targets every 3 frames + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + if( it->usedstamp < curstamp - 3 ) { + it = listTargets.erase(it); + continue; + } + + ++it; + } + } + + ++curstamp; +} + +void ZeroGS::CMemoryTargetMngr::DestroyOldest() +{ + if( listTargets.size() == 0 ) + return; + + list::iterator it, itbest; + it = itbest = listTargets.begin(); + + while(it != listTargets.end()) { + if( it->usedstamp < itbest->usedstamp ) + itbest = it; + ++it; + } + + listTargets.erase(itbest); +} + +////////////////////////////////////// +// Texture Mngr For Bitwise AND Ops // +////////////////////////////////////// +void ZeroGS::CBitwiseTextureMngr::Destroy() +{ + for(map::iterator it = mapTextures.begin(); it != mapTextures.end(); ++it) + it->second->Release(); + mapTextures.clear(); +} + +LPD3DTEX ZeroGS::CBitwiseTextureMngr::GetTexInt(u32 bitvalue, LPD3DTEX ptexDoNotDelete) +{ + if( mapTextures.size() > 32 ) { + // randomly delete 8 + for(map::iterator it = mapTextures.begin(); it != mapTextures.end();) { + if( !(rand()&3) && it->second != ptexDoNotDelete) { + it->second->Release(); + it = mapTextures.erase(it); + } + else ++it; + } + } + + // create a new tex + LPD3DTEX ptex; + HRESULT hr = S_OK; + V(pd3dDevice->CreateTexture(GPU_TEXMASKWIDTH, 1, 1, 0, D3DFMT_L16, D3DPOOL_MANAGED, &ptex, NULL)); + + D3DLOCKED_RECT lock; + ptex->LockRect(0, &lock, NULL, 0); + for(u32 i = 0; i < GPU_TEXMASKWIDTH; ++i) ((u16*)lock.pBits)[i] = ((i&bitvalue)<<6)|0x1f; // add the 1/2 offset so that + ptex->UnlockRect(0); + + mapTextures[bitvalue] = ptex; + return ptex; +} + +void ZeroGS::CRangeManager::Insert(int start, int end) +{ + int imin = 0, imax = (int)ranges.size(), imid; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + switch( ranges.size() ) { + case 0: + ranges.push_back(RANGE(start, end)); + return; + + case 1: + if( end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + } + else if( start > ranges.front().end ) { + ranges.push_back(RANGE(start, end)); + } + else { + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + } + + return; + } + + // find where start is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end >= start && (imid == 0 || ranges[imid-1].end < start) ) { + imin = imid; + break; + } + else if( ranges[imid].start > start ) imax = imid; + else imin = imid+1; + } + + int startindex = imin; + + if( startindex >= (int)ranges.size() ) { + // non intersecting + assert( start > ranges.back().end ); + ranges.push_back(RANGE(start, end)); + return; + } + if( startindex == 0 && end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + imin = 0; imax = (int)ranges.size(); + + // find where end is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end <= end && (imid == ranges.size()-1 || ranges[imid+1].start > end ) ) { + imin = imid; + break; + } + else if( ranges[imid].start >= end ) imax = imid; + else imin = imid+1; + } + + int endindex = imin; + + if( startindex > endindex ) { + // create a new range + ranges.insert(ranges.begin()+startindex, RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + if( endindex >= (int)ranges.size()-1 ) { + // pop until startindex is reached + int lastend = ranges.back().end; + int numpop = (int)ranges.size() - startindex - 1; + while(numpop-- > 0 ) ranges.pop_back(); + + assert( start <= ranges.back().end ); + if( start < ranges.back().start ) ranges.back().start = start; + if( lastend > ranges.back().end ) ranges.back().end = lastend; + if( end > ranges.back().end ) ranges.back().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + return; + } + + if( endindex == 0 ) { + assert( end >= ranges.front().start ); + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + } + + // somewhere in the middle + if( ranges[startindex].start < start ) start = ranges[startindex].start; + + if( startindex < endindex ) { + ranges.erase(ranges.begin() + startindex, ranges.begin() + endindex ); + } + + if( start < ranges[startindex].start ) ranges[startindex].start = start; + if( end > ranges[startindex].end ) ranges[startindex].end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif +} + +namespace ZeroGS { + +CRangeManager s_RangeMngr; // manages overwritten memory +static int gs_imageEnd = 0; + +void ResolveInRange(int start, int end) +{ + list listTargs; + s_DepthRTs.GetTargs(start, end, listTargs); + s_RTs.GetTargs(start, end, listTargs); + + if( listTargs.size() > 0 ) { + // flushes can delete targets! + Flush(0); + Flush(1); + + listTargs.clear(); + s_DepthRTs.GetTargs(start, end, listTargs); + s_RTs.GetTargs(start, end, listTargs); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + // only resolve if not completely covered + (*it)->Resolve(); + } + } +} + +////////////////// +// Transferring // +////////////////// +void FlushTransferRanges(const tex0Info* ptex) +{ + assert( s_RangeMngr.ranges.size() > 0 ); + bool bHasFlushed = false; + list listTransmissionUpdateTargs; + + int texstart = -1, texend = -1; + if( ptex != NULL ) { + GetRectMemAddress(texstart, texend, ptex->psm, 0, 0, ptex->tw, ptex->th, ptex->tbp0, ptex->tbw); + } + + for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { + + int start = itrange->start; + int end = itrange->end; + + listTransmissionUpdateTargs.clear(); + s_DepthRTs.GetTargs(start, end, listTransmissionUpdateTargs); + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + +// if( !bHasFlushed && listTransmissionUpdateTargs.size() > 0 ) { +// Flush(0); +// Flush(1); +// +//#ifdef _DEBUG +// // make sure targets are still the same +// list::iterator it; +// FORIT(it, listTransmissionUpdateTargs) { +// CRenderTargetMngr::MAPTARGETS::iterator itmap; +// for(itmap = s_RTs.mapTargets.begin(); itmap != s_RTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// if( itmap == s_RTs.mapTargets.end() ) { +// +// for(itmap = s_DepthRTs.mapTargets.begin(); itmap != s_DepthRTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// assert( itmap != s_DepthRTs.mapTargets.end() ); +// } +// } +//#endif +// } + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) || ptarg->targoffx != 0 || ptarg->targoffy != 0) + continue; + + if( !(ptarg->start < texend && ptarg->end > texstart) ) { + // chekc if target is currently being used + + if( !(g_GameSettings & GAME_NOQUICKRESOLVE) ) { + if( ptarg->fbp != vb[0].gsfb.fbp ) {//&& (vb[0].prndr == NULL || ptarg->fbp != vb[0].prndr->fbp) ) { + + if( ptarg->fbp != vb[1].gsfb.fbp ) { //&& (vb[1].prndr == NULL || ptarg->fbp != vb[1].prndr->fbp) ) { + // this render target currently isn't used and is not in the texture's way, so can safely ignore + // resolving it. Also the range has to be big enough compared to the target to really call it resolved + // (ffx changing screens, shadowhearts) + // start == ptarg->start, used for kh to transfer text + if( ptarg->IsDepth() || end-start > 0x50000 || ((g_GameSettings&GAME_QUICKRESOLVE1)&&start == ptarg->start) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate|CRenderTarget::TS_Resolved; + + continue; + } + } + } + } + else { +// if( start <= texstart && end >= texend ) { +// // texture taken care of so can skip!? +// continue; +// } + } + + // the first range check was very rough; some games (dragonball z) have the zbuf in the same page as textures (but not overlapping) + // so detect that condition + if( ptarg->fbh % m_Blocks[ptarg->psm].height ) { + + // get start of left-most boundry page + int targstart, targend; + ZeroGS::GetRectMemAddress(targstart, targend, ptarg->psm, 0, 0, ptarg->fbw, ptarg->fbh & ~(m_Blocks[ptarg->psm].height-1), ptarg->fbp, ptarg->fbw); + + if( start >= targend ) { + + // don't bother + if( (ptarg->fbh % m_Blocks[ptarg->psm].height) <= 2 ) + continue; + + // calc how many bytes of the block that the page spans + } + } + + if( !(ptarg->status & CRenderTarget::TS_Virtual) ) { + + if( start < ptarg->end && end > ptarg->start ) { + + // suikoden5 is faster with check, but too big of a value and kh screens mess up + if( end - start > 0x8000 ) { + // intersects, do only one sided resolves + if( end-start > 4*ptarg->fbw ) { // at least it be greater than one scanline (spiro is faster) + if( start > ptarg->start ) { + ptarg->Resolve(ptarg->start, start); + } + else if( end < ptarg->end ) { + ptarg->Resolve(end, ptarg->end); + } + } + } + + ptarg->status |= CRenderTarget::TS_Resolved; + if( !ptarg->IsDepth() || (!(g_GameSettings & GAME_NODEPTHUPDATE) || end-start > 0x1000) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate; + } + } + } + + ZeroGS::g_MemTargs.ClearRange(start, end); + } + + s_RangeMngr.Clear(); +} + +// need to take into account left over data of 24bit transfers (always <= 5) +static vector s_vTempBuffer, s_vTransferCache; + +void InitTransferHostLocal() +{ + if( g_bIsLost ) + return; + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + bool bHasFlushed = false; + + gs.imageX = gs.trxpos.dx; + gs.imageY = gs.trxpos.dy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + s_vTransferCache.resize(0); + + assert( gs.imageEndX < 2048 && gs.imageEndY < 2048 ); + + // hack! viewful joe + if( gs.dstbuf.psm == 63 ) + gs.dstbuf.psm = 0; + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + if( end > 0x00400000 ) { + WARN_LOG("host local out of bounds!\n"); + //gs.imageTransfer = -1; + end = 0x00400000; + } + + gs_imageEnd = end; + + if( vb[0].dwCount > 0 ) + Flush(0); + if( vb[1].dwCount > 0 ) + Flush(1); + + //PRIM_LOG("trans: bp:%x x:%x y:%x w:%x h:%x\n", gs.dstbuf.bp, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew); + +// if( !bHasFlushed && (vb[0].bNeedFrameCheck || vb[0].bNeedZCheck || vb[1].bNeedFrameCheck || vb[1].bNeedZCheck)) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// +// // for all ranges, flush the targets +// // check if new rect intersects with current rendering texture, if so, flush +// if( vb[0].dwCount > 0 && vb[0].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[0].tex0.psm, 0, 0, vb[0].tex0.tw, vb[0].tex0.th, vb[0].tex0.tbp0, vb[0].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } +// +// if( !bHasFlushed && vb[1].dwCount > 0 && vb[1].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[1].tex0.psm, 0, 0, vb[1].tex0.tw, vb[1].tex0.th, vb[1].tex0.tbp0, vb[1].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } + + //ZeroGS::g_MemTargs.ClearRange(start, end); + //s_RangeMngr.Insert(start, end); +} + +void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +{ + if( g_bIsLost ) + return; + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.imageX, gs.imageY, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + assert( start < gs_imageEnd ); + + end = gs_imageEnd; + + // sometimes games can decompress to alpha channel of render target only, in this case + // do a resolve right away. wolverine x2 + if( gs.dstbuf.psm == PSMT8H || gs.dstbuf.psm == PSMT4HL || gs.dstbuf.psm == PSMT4HH ) { + list listTransmissionUpdateTargs; + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) ) + continue; + + //DEBUG_LOG("zerogs: resolving to alpha channel\n"); + ptarg->Resolve(); + } + } + + s_RangeMngr.Insert(start, min(end, start+(int)nQWordSize*16)); + + const u8* porgend = (const u8*)pbyMem + 4 * nQWordSize; + + if( s_vTransferCache.size() > 0 ) { + + int imagecache = s_vTransferCache.size(); + s_vTempBuffer.resize(imagecache + nQWordSize*4); + memcpy(&s_vTempBuffer[0], &s_vTransferCache[0], imagecache); + memcpy(&s_vTempBuffer[imagecache], pbyMem, nQWordSize*4); + + pbyMem = (const void*)&s_vTempBuffer[0]; + porgend = &s_vTempBuffer[0]+s_vTempBuffer.size(); + + int wordinc = imagecache / 4; + if( (nQWordSize * 4 + imagecache)/3 == ((nQWordSize+wordinc) * 4) / 3 ) { + // can use the data + nQWordSize += wordinc; + } + } + + int leftover = m_Blocks[gs.dstbuf.psm].TransferHostLocal(pbyMem, nQWordSize); + + if( leftover > 0 ) { + // copy the last gs.image24bitOffset to the cache + s_vTransferCache.resize(leftover); + memcpy(&s_vTransferCache[0], porgend - leftover, leftover); + } + else s_vTransferCache.resize(0); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +// left/right, top/down +//void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +//{ +// assert( gs.imageTransfer == 0 ); +// u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; +// +// const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; +// int i = gs.imageY, j = gs.imageX; +// +//#define DSTPSM gs.dstbuf.psm +// +//#define TRANSFERHOSTLOCAL(psm, T, widthlimit) { \ +// const T* pbuf = (const T*)pbyMem; \ +// u32 nSize = nQWordSize*(4/sizeof(T)); \ +// assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ +// if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) DEBUG_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM); \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 1 ) { \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 2 ) { \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 3 ) { \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ +// } \ +// } \ +// } \ +// } \ +// \ +// if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +//#define TRANSFERHOSTLOCAL_4(psm) { \ +// const u8* pbuf = (const u8*)pbyMem; \ +// u32 nSize = nQWordSize*8; \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += 8, nSize -= 8) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// } \ +// \ +// if( j >= gs.imageEndX ) { /*assert(j == gs.imageEndX);*/ j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +// switch (gs.dstbuf.psm) { +// case 0x0: TRANSFERHOSTLOCAL(32, u32, 2); break; +// case 0x1: TRANSFERHOSTLOCAL(24, u32, 4); break; +// case 0x2: TRANSFERHOSTLOCAL(16, u16, 4); break; +// case 0xA: TRANSFERHOSTLOCAL(16S, u16, 4); break; +// case 0x13: +// if( ((gs.imageEndX-gs.trxpos.dx)%4) ) { +// TRANSFERHOSTLOCAL(8, u8, 1); +// } +// else { +// TRANSFERHOSTLOCAL(8, u8, 4); +// } +// break; +// +// case 0x14: +//// if( (gs.imageEndX-gs.trxpos.dx)%8 ) { +//// // hack +//// if( abs((int)nQWordSize*8 - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= 8 ) { +//// // don't transfer +//// DEBUG_LOG("bad texture 4: %d %d %d\n", gs.trxpos.dx, gs.imageEndX, nQWordSize); +//// gs.imageEndX = gs.trxpos.dx + (gs.imageEndX-gs.trxpos.dx)&~7; +//// //i = gs.imageEndY; +//// //goto End; +//// gs.imageTransfer = -1; +//// } +//// } +// TRANSFERHOSTLOCAL_4(4); +// break; +// case 0x1B: TRANSFERHOSTLOCAL(8H, u8, 4); break; +// case 0x24: TRANSFERHOSTLOCAL_4(4HL); break; +// case 0x2C: TRANSFERHOSTLOCAL_4(4HH); break; +// case 0x30: TRANSFERHOSTLOCAL(32Z, u32, 2); break; +// case 0x31: TRANSFERHOSTLOCAL(24Z, u32, 4); break; +// case 0x32: TRANSFERHOSTLOCAL(16Z, u16, 4); break; +// case 0x3A: TRANSFERHOSTLOCAL(16SZ, u16, 4); break; +// } +// +//End: +// if( i >= gs.imageEndY ) { +// assert( i == gs.imageEndY ); +// gs.imageTransfer = -1; +// +// if( g_bSaveTrans ) { +// tex0Info t; +// t.tbp0 = gs.dstbuf.bp; +// t.tw = gs.imageWnew; +// t.th = gs.imageHnew; +// t.tbw = gs.dstbuf.bw; +// t.psm = gs.dstbuf.psm; +// SaveTex(&t, 0); +// } +// } +// else { +// /* update new params */ +// gs.imageY = i; +// gs.imageX = j; +// } +//} + +void InitTransferLocalHost() +{ + assert( gs.trxpos.sx+gs.imageWnew <= 2048 && gs.trxpos.sy+gs.imageHnew <= 2048 ); + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + gs.imageX = gs.trxpos.sx; + gs.imageY = gs.trxpos.sy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + + int start, end; + GetRectMemAddress(start, end, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + ResolveInRange(start, end); +} + +// left/right, top/down +void TransferLocalHost(void* pbyMem, u32 nQWordSize) +{ + assert( gs.imageTransfer == 1 ); + + u8* pstart = g_pbyGSMemory + 256*gs.srcbuf.bp; + int i = gs.imageY, j = gs.imageX; + +#define TRANSFERLOCALHOST(psm, T) { \ + T* pbuf = (T*)pbyMem; \ + u32 nSize = nQWordSize*16/sizeof(T); \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + *pbuf++ = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + +#define TRANSFERLOCALHOST_24(psm) { \ + u8* pbuf = (u8*)pbyMem; \ + u32 nSize = nQWordSize*16/3; \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + u32 p = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + pbuf[0] = (u8)p; \ + pbuf[1] = (u8)(p>>8); \ + pbuf[2] = (u8)(p>>16); \ + pbuf += 3; \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case 0x0: TRANSFERLOCALHOST(32, u32); break; + case 0x1: TRANSFERLOCALHOST_24(24); break; + case 0x2: TRANSFERLOCALHOST(16, u16); break; + case 0xA: TRANSFERLOCALHOST(16S, u16); break; + case 0x13: TRANSFERLOCALHOST(8, u8); break; + case 0x1B: TRANSFERLOCALHOST(8H, u8); break; + case 0x30: TRANSFERLOCALHOST(32Z, u32); break; + case 0x31: TRANSFERLOCALHOST_24(24Z); break; + case 0x32: TRANSFERLOCALHOST(16Z, u16); break; + case 0x3A: TRANSFERLOCALHOST(16SZ, u16); break; + default: assert(0); + } + + gs.imageY = i; + gs.imageX = j; + + if( gs.imageY >= gs.imageEndY ) { + assert( gs.imageY == gs.imageEndY ); + gs.imageTransfer = -1; + } +} + +// dir depends on trxpos.dir +void TransferLocalLocal() +{ + assert( gs.imageTransfer == 2 ); + assert( gs.trxpos.sx+gs.imageWnew < 2048 && gs.trxpos.sy+gs.imageHnew < 2048 ); + assert( gs.trxpos.dx+gs.imageWnew < 2048 && gs.trxpos.dy+gs.imageHnew < 2048 ); + assert( (gs.srcbuf.psm&0x7) == (gs.dstbuf.psm&0x7) ); + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, src width exceeds\n"); + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, dst width exceeds\n"); + + int srcstart, srcend, dststart, dstend; + + GetRectMemAddress(srcstart, srcend, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + GetRectMemAddress(dststart, dstend, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + // resolve the targs + ResolveInRange(srcstart, srcend); + + list listTargs; + s_RTs.GetTargs(dststart, dstend, listTargs); + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + if( !((*it)->status & CRenderTarget::TS_Virtual) ) { + (*it)->Resolve(); + (*it)->status |= CRenderTarget::TS_NeedUpdate; + } + } + + u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp*256; + u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp*256; + +#define TRANSFERLOCALLOCAL(srcpsm, dstpsm, widthlimit) { \ + if( (gs.imageWnew&widthlimit)!=0 ) break; \ + assert( (gs.imageWnew&widthlimit)==0 && widthlimit <= 4); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; i++, i2++) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=widthlimit, j2+=widthlimit) { \ + \ + writePixel##dstpsm##_0(pDstBuf, j2%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, j%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+1)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+1)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+2)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+2)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+3)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+3)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + } \ +} \ + +#define TRANSFERLOCALLOCAL_4(srcpsm, dstpsm) { \ + assert( (gs.imageWnew%8) == 0 ); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; ++i, ++i2) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=8, j2+=8) { \ + /* NOTE: the 2 conseq 4bit values are in NOT in the same byte */ \ + u32 read = getPixelAddress##srcpsm##_0(j%2048, i%2048, gs.srcbuf.bw); \ + u32 write = getPixelAddress##dstpsm##_0(j2%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+1)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+1)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case PSMCT32: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32, 32Z, 2); + } + break; + + case PSMCT24: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24, 24Z, 4); + } + break; + + case PSMCT16: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16, 16SZ, 4); break; + } + break; + + case PSMCT16S: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16S, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16S, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16S, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16S, 16SZ, 4); break; + } + break; + + case PSMT8: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8, 8H, 4); + } + break; + + case PSMT4: + + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4, 4HH); break; + } + break; + + case PSMT8H: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8H, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8H, 8H, 4); + } + break; + + case PSMT4HL: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HL, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HL, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HL, 4HH); break; + } + break; + case PSMT4HH: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HH, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HH, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HH, 4HH); break; + } + break; + + case PSMT32Z: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32Z, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32Z, 32Z, 2); + } + break; + + case PSMT24Z: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24Z, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24Z, 24Z, 4); + } + break; + + case PSMT16Z: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16Z, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16Z, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16Z, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16Z, 16SZ, 4); break; + } + break; + + case PSMT16SZ: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16SZ, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16SZ, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16SZ, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16SZ, 16SZ, 4); break; + } + break; + } + + g_MemTargs.ClearRange(dststart, dstend); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + + t.tbp0 = gs.srcbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.srcbuf.bw; + t.psm = gs.srcbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw) +{ + if( m_Blocks[psm].bpp == 0 ) { + ERROR_LOG("ZeroGS: Bad psm 0x%x\n", psm); + start = 0; + end = 0x00400000; + return; + } + + if( (psm&0x30) == 0x30 || psm == 0xa ) { + + const BLOCK& b = m_Blocks[psm]; + + bw = (bw + b.width -1)/b.width; + start = bp*256 + ((y/b.height) * bw + (x/b.width) )*0x2000; + end = bp*256 + (((y+h-1)/b.height) * bw + (x + w + b.width - 1)/b.width)*0x2000; + } + else { + // just take the addresses + switch(psm) { + case 0x00: + case 0x01: + case 0x1b: + case 0x24: + case 0x2c: + start = 4*getPixelAddress32(x, y, bp, bw); + end = 4*getPixelAddress32(x+w-1, y+h-1, bp, bw) + 4; + break; + case 0x02: + start = 2*getPixelAddress16(x, y, bp, bw); + end = 2*getPixelAddress16(x+w-1, y+h-1, bp, bw)+2; + break; + case 0x13: + start = getPixelAddress8(x, y, bp, bw); + end = getPixelAddress8(x+w-1, y+h-1, bp, bw)+1; + break; + case 0x14: + { + start = getPixelAddress4(x, y, bp, bw)/2; + int newx = ((x+w-1+31)&~31)-1; + int newy = ((y+h-1+15)&~15)-1; + end = (getPixelAddress4(max(newx,x), max(newy,y), bp, bw)+2)/2; + break; + } + } + } +} + +void _Resolve(const D3DLOCKED_RECT& locksrc, int fbp, int fbw, int fbh, int psm, u32 fbm) +{ + s_nResolved += 2; + + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + int start, end; + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + PRIM_LOG("resolve: %x %x %x (%x-%x)\n", fbp, fbw, fbh, start, end); + + int i, j; + short smask1 = gs.smask&1; + short smask2 = gs.smask&2; + u32 mask, imask; + + if( psm&2 ) { // 16 bit + // mask is shifted + imask = RGBA32to16(fbm); + mask = (~imask)&0xffff; + } + else { + mask = ~fbm; + imask = fbm; + + if( (psm&0xf)>0 ) { + // preserve the alpha? + mask &= 0x00ffffff; + imask |= 0xff000000; + } + } + +#define RESOLVE_32BIT(psm, T, Tsrc, blockbits, blockwidth, blockheight, convfn, frame, aax, aay) \ + { \ + Tsrc* src = (Tsrc*)locksrc.pBits; \ + T* pPageOffset = (T*)g_pbyGSMemory + fbp*(256/sizeof(T)), *dst; \ + int srcpitch = locksrc.Pitch * blockheight/sizeof(Tsrc); \ + int maxfbh = (0x00400000-fbp*256) / (sizeof(T) * fbw); \ + if( maxfbh > fbh ) maxfbh = fbh; \ + for(i = 0; i < (maxfbh&~(blockheight-1)); i += blockheight) { \ + /*if( smask2 && (i&1) == smask1 ) continue; */ \ + for(j = 0; j < fbw; j += blockwidth) { \ + /* have to write in the tiled format*/ \ + ##frame##SwizzleBlock##blockbits##(pPageOffset + getPixelAddress##psm##_0(j, i, fbw), \ + src+(j< psm + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + } + } + else { + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A4, 8, 8, Float16ToARGB, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A2, 8, 8, Float16ToARGB, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, Vector_16F, 32, 8, 8, Float16ToARGB, Frame16, 0, 0); + } + + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA4, 8, 8, Float16ToARGB_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA2, 8, 8, Float16ToARGB_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32Z, 8, 8, Float16ToARGB_Z, Frame16, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + } + } + + g_MemTargs.ClearRange(start, end); + INC_RESOLVE(); +} + +//////////// +// Saving // +//////////// +void SaveTex(tex0Info* ptex, int usevid) +{ + LPD3DTEX pTexture; + pd3dDevice->CreateTexture(ptex->tw, ptex->th, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pTexture, NULL); + + D3DLOCKED_RECT lockdst; + pTexture->LockRect(0, &lockdst, NULL, 0); + + DWORD* dst = (DWORD*)lockdst.pBits; + u8* psrc = g_pbyGSMemory; + + CMemoryTarget* pmemtarg = NULL; + + if( usevid ) { + pmemtarg = g_MemTargs.GetMemoryTarget(*ptex, 1); + assert( pmemtarg != NULL ); + D3DLOCKED_RECT lock; + HRESULT hr = pmemtarg->ptexsys->LockRect(0, &lock, NULL, D3DLOCK_READONLY); + if( FAILED(hr) ) + return; + u32 offset = pmemtarg->realy * 4 * GPU_TEXWIDTH; + if( ptex->psm == PSMT8 ) offset *= ptex->cpsm <= 1 ? 4 : 2; + else if( ptex->psm == PSMT4 ) offset *= ptex->cpsm <= 1 ? 8 : 4; + + psrc = (u8*)lock.pBits - offset; + } + + for(int i = 0; i < ptex->th; ++i) { + for(int j = 0; j < ptex->tw; ++j) { + u32 u, addr; + switch(ptex->psm) { + case PSMCT32: + addr = getPixelAddress32(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel32(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT24: + addr = getPixelAddress24(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel24(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT16: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + + break; + case PSMCT16S: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16S(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + break; + + case PSMT8: + addr = getPixelAddress8(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4: + addr = getPixelAddress4(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 2*0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT8H: + addr = getPixelAddress8H(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8H(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + + break; + + case PSMT4HL: + addr = getPixelAddress4HL(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HL(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4HH: + addr = getPixelAddress4HH(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HH(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT32Z: + addr = getPixelAddress32Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel32Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT24Z: + addr = getPixelAddress24Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel24Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16Z: + addr = getPixelAddress16Z(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16SZ: + addr = getPixelAddress16SZ(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16SZ(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + default: + assert(0); + } + + *dst++ = u; + } + + dst += lockdst.Pitch/4 - ptex->tw; + } + + pTexture->UnlockRect(0); + + if( usevid ) { + pmemtarg->ptexsys->UnlockRect(0); + } + + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, pTexture, NULL); + + SAFE_RELEASE(pTexture); + +} + +} diff --git a/plugins/zerogs/dx/targets.h b/plugins/zerogs/dx/targets.h new file mode 100644 index 0000000000..d104bbf68c --- /dev/null +++ b/plugins/zerogs/dx/targets.h @@ -0,0 +1,232 @@ +#define TARGET_VIRTUAL_KEY 0x80000000 + +namespace ZeroGS +{ + // manages render targets + class CRenderTargetMngr + { + public: + typedef map MAPTARGETS; + + enum TargetOptions + { + TO_DepthBuffer = 1, + TO_StrictHeight = 2, // height returned has to be the same as requested + TO_Virtual = 4 + }; + + ~CRenderTargetMngr() { Destroy(); } + + void Destroy(); + static MAPTARGETS::iterator GetOldestTarg(MAPTARGETS& m); + + CRenderTarget* GetTarg(const frameInfo& frame, DWORD Options, int maxposheight); + inline CRenderTarget* GetTarg(int fbp, int fbw) { + MAPTARGETS::iterator it = mapTargets.find(fbp|(fbw<<16)); + return it != mapTargets.end() ? it->second : NULL; + } + + // gets all targets with a range + void GetTargs(int start, int end, list& listTargets) const; + + virtual void DestroyChildren(CRenderTarget* ptarg); + + // resolves all targets within a range + __forceinline void Resolve(int start, int end); + __forceinline void ResolveAll() { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it ) + it->second->Resolve(); + } + + void DestroyTarg(CRenderTarget* ptarg) { + for(int i = 0; i < 2; ++i) { + if( ptarg == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( ptarg == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + DestroyChildren(ptarg); + delete ptarg; + } + + inline void DestroyAll(int start, int end, int fbw) { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second->start < end && start < it->second->end ) { + // if is depth, only resolve if fbw is the same + if( !it->second->IsDepth() ) { + // only resolve if the widths are the same or it->second has bit outside the range + // shadow of colossus swaps between fbw=256,fbh=256 and fbw=512,fbh=448. This kills the game if doing || it->second->end > end + + // kh hack, sometimes kh movies do this to clear the target, so have a static count that periodically checks end + static int count = 0; + + if( it->second->fbw == fbw || (it->second->fbw != fbw && (it->second->start < start || ((count++&0xf)?0:it->second->end > end) )) ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + else { + if( it->second->fbw == fbw ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( it->second->pmimicparent != NULL && mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + DestroyChildren(it->second); + mapDummyTargs[dummykey] = it->second; + } + else { + DestroyChildren(it->second); + delete it->second; + } + it = mapTargets.erase(it); + } + else ++it; + } + } + + inline void DestroyIntersecting(CRenderTarget* prndr) + { + assert( prndr != NULL ); + + int start, end; + GetRectMemAddress(start, end, prndr->psm, 0, 0, prndr->fbw, prndr->fbh, prndr->fbp, prndr->fbw); + + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second != prndr && it->second->start < end && start < it->second->end ) { + it->second->Resolve(); + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( it->second->pmimicparent != NULL && mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + DestroyChildren(it->second); + mapDummyTargs[dummykey] = it->second; + } + else { + DestroyChildren(it->second); + delete it->second; + } + + it = mapTargets.erase(it); + } + else ++it; + } + } + + // promotes a target from virtual to real + inline CRenderTarget* Promote(u32 key) { + assert( !(key & TARGET_VIRTUAL_KEY) ); + + // promote to regular targ + CRenderTargetMngr::MAPTARGETS::iterator it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + assert( it != mapTargets.end() ); + + CRenderTarget* ptarg = it->second; + mapTargets.erase(it); + + DestroyIntersecting(ptarg); + + it = mapTargets.find(key); + if( it != mapTargets.end() ) { + DestroyTarg(it->second); + it->second = ptarg; + } + else + mapTargets[key] = ptarg; + + if( g_GameSettings & GAME_RESOLVEPROMOTED ) + ptarg->status = CRenderTarget::TS_Resolved; + else + ptarg->status = CRenderTarget::TS_NeedUpdate; + return ptarg; + } + + MAPTARGETS mapTargets, mapDummyTargs; + }; + + class CMemoryTargetMngr + { + public: + CMemoryTargetMngr() : curstamp(0) {} + CMemoryTarget* GetMemoryTarget(const tex0Info& tex0, int forcevalidate); // pcbp is pointer to start of clut + + void Destroy(); // destroy all targs + + void ClearRange(int starty, int endy); // set all targets to cleared + void DestroyCleared(); // flush all cleared targes + void DestroyOldest(); + + list listTargets, listClearedTargets; + u32 curstamp; + + private: + list::iterator DestroyTargetIter(list::iterator& it); + }; + + class CBitwiseTextureMngr + { + public: + ~CBitwiseTextureMngr() { Destroy(); } + + void Destroy(); + + // since GetTex can delete textures to free up mem, it is dangerous if using that texture, so specify at least one other tex to save + __forceinline LPD3DTEX GetTex(u32 bitvalue, LPD3DTEX ptexDoNotDelete) { + map::iterator it = mapTextures.find(bitvalue); + if( it != mapTextures.end() ) + return it->second; + return GetTexInt(bitvalue, ptexDoNotDelete); + } + + private: + LPD3DTEX GetTexInt(u32 bitvalue, LPD3DTEX ptexDoNotDelete); + + map mapTextures; + }; + + // manages + class CRangeManager + { + public: + CRangeManager() + { + ranges.reserve(16); + } + + // [start, end) + struct RANGE + { + RANGE() {} + inline RANGE(int start, int end) : start(start), end(end) {} + int start, end; + }; + + // works in semi logN + void Insert(int start, int end); + inline void Clear() { ranges.resize(0); } + + vector ranges; // organized in ascending order, non-intersecting + }; + + extern CRenderTargetMngr s_RTs, s_DepthRTs; + extern CBitwiseTextureMngr s_BitwiseTextures; + extern CMemoryTargetMngr g_MemTargs; +} diff --git a/plugins/zerogs/dx/x86-32.asm b/plugins/zerogs/dx/x86-32.asm new file mode 100644 index 0000000000..1c55682057 --- /dev/null +++ b/plugins/zerogs/dx/x86-32.asm @@ -0,0 +1,1353 @@ +; Copyright (C) 2003-2005 Gabest +; http://www.gabest.org +; +; 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, 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 GNU Make; see the file COPYING. If not, write to +; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +; http://www.gnu.org/copyleft/gpl.html +; +; + .686 + .model flat + .mmx + .xmm + + .const + + __uvmin DD 0d01502f9r ; -1e+010 + __uvmax DD 0501502f9r ; +1e+010 + + .code + +; +; memsetd +; + +@memsetd@12 proc public + + push edi + + mov edi, ecx + mov eax, edx + mov ecx, [esp+4+4] + cld + rep stosd + + pop edi + + ret 4 + +@memsetd@12 endp + +; +; SaturateColor +; + +@SaturateColor_sse2@4 proc public + + pxor xmm0, xmm0 + movdqa xmm1, [ecx] + packssdw xmm1, xmm0 + packuswb xmm1, xmm0 + punpcklbw xmm1, xmm0 + punpcklwd xmm1, xmm0 + movdqa [ecx], xmm1 + + ret + +@SaturateColor_sse2@4 endp + +@SaturateColor_asm@4 proc public + + push esi + + mov esi, ecx + + xor eax, eax + mov edx, 000000ffh + + mov ecx, [esi] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi], ecx + + mov ecx, [esi+4] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi+4], ecx + + mov ecx, [esi+8] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi+8], ecx + + mov ecx, [esi+12] + cmp ecx, eax + cmovl ecx, eax + cmp ecx, edx + cmovg ecx, edx + mov [esi+12], ecx + + pop esi + + ret + +@SaturateColor_asm@4 endp + +; +; swizzling +; + +punpck macro op, sd0, sd2, s1, s3, d1, d3 + + movdqa @CatStr(xmm, %d1), @CatStr(xmm, %sd0) + pshufd @CatStr(xmm, %d3), @CatStr(xmm, %sd2), 0e4h + + @CatStr(punpckl, op) @CatStr(xmm, %sd0), @CatStr(xmm, %s1) + @CatStr(punpckh, op) @CatStr(xmm, %d1), @CatStr(xmm, %s1) + @CatStr(punpckl, op) @CatStr(xmm, %sd2), @CatStr(xmm, %s3) + @CatStr(punpckh, op) @CatStr(xmm, %d3), @CatStr(xmm, %s3) + + endm + +punpcknb macro + + movdqa xmm4, xmm0 + pshufd xmm5, xmm1, 0e4h + + psllq xmm1, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm0, xmm7 + pandn xmm6, xmm1 + por xmm0, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm1, xmm4 + + movdqa xmm4, xmm2 + pshufd xmm5, xmm3, 0e4h + + psllq xmm3, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm2, xmm7 + pandn xmm6, xmm3 + por xmm2, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm3, xmm4 + + punpck bw, 0, 2, 1, 3, 4, 6 + + endm + +; +; unSwizzleBlock32 +; + +@unSwizzleBlock32_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + lea eax, [ebx*2] + add eax, ebx + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+ebx], xmm4 + movdqa [edx+ebx+16], xmm6 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm2, [ecx+16*6] + movdqa xmm3, [ecx+16*7] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx+ebx*2], xmm0 + movdqa [edx+ebx*2+16], xmm2 + movdqa [edx+eax], xmm4 + movdqa [edx+eax+16], xmm6 + + lea edx, [edx+ebx*4] + + movdqa xmm0, [ecx+16*8] + movdqa xmm1, [ecx+16*9] + movdqa xmm2, [ecx+16*10] + movdqa xmm3, [ecx+16*11] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+ebx], xmm4 + movdqa [edx+ebx+16], xmm6 + + movdqa xmm0, [ecx+16*12] + movdqa xmm1, [ecx+16*13] + movdqa xmm2, [ecx+16*14] + movdqa xmm3, [ecx+16*15] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + movdqa [edx+ebx*2], xmm0 + movdqa [edx+ebx*2+16], xmm2 + movdqa [edx+eax], xmm4 + movdqa [edx+eax+16], xmm6 + + pop ebx + + ret 4 + +@unSwizzleBlock32_sse2@12 endp + +; +; unSwizzleBlock16 +; + +@unSwizzleBlock16_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck dq, 0, 4, 2, 6, 1, 3 + punpck wd, 0, 4, 1, 3, 2, 6 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+ebx], xmm4 + movdqa [edx+ebx+16], xmm6 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock16_sse2@12 endp + +; +; unSwizzleBlock8 +; + +@unSwizzleBlock8_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm4, [ecx+16*2] + movdqa xmm5, [ecx+16*3] + + punpck bw, 0, 4, 1, 5, 2, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshufd xmm1, xmm1, 0b1h + pshufd xmm3, xmm3, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + ; col 1, 3 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm4, [ecx+16*6] + movdqa xmm5, [ecx+16*7] + + punpck bw, 0, 4, 1, 5, 2, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock8_sse2@12 endp + +; +; unSwizzleBlock4 +; + +@unSwizzleBlock4_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm4, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck dq, 0, 4, 1, 3, 2, 6 + punpck dq, 0, 2, 4, 6, 1, 3 + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck wd, 0, 2, 1, 3, 4, 6 + + pshufd xmm0, xmm0, 0d8h + pshufd xmm2, xmm2, 0d8h + pshufd xmm4, xmm4, 0d8h + pshufd xmm6, xmm6, 0d8h + + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + ; col 1, 3 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm4, [ecx+16*6] + movdqa xmm3, [ecx+16*7] + + punpck dq, 0, 4, 1, 3, 2, 6 + punpck dq, 0, 2, 4, 6, 1, 3 + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck wd, 0, 2, 1, 3, 4, 6 + + pshufd xmm0, xmm0, 0d8h + pshufd xmm2, xmm2, 0d8h + pshufd xmm4, xmm4, 0d8h + pshufd xmm6, xmm6, 0d8h + + punpck qdq, 0, 2, 4, 6, 1, 3 + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + movdqa [edx], xmm0 + movdqa [edx+ebx], xmm2 + lea edx, [edx+ebx*2] + + movdqa [edx], xmm1 + movdqa [edx+ebx], xmm3 + lea edx, [edx+ebx*2] + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock4_sse2@12 endp + +; +; unSwizzleBlock8HP +; + +@unSwizzleBlock8HP_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 24 + psrld xmm2, 24 + psrld xmm4, 24 + psrld xmm6, 24 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + movlps qword ptr [edx], xmm0 + movhps qword ptr [edx+ebx], xmm0 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock8HP_sse2@12 endp + +; +; unSwizzleBlock4HLP +; + +@unSwizzleBlock4HLP_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 24 + psrld xmm2, 24 + psrld xmm4, 24 + psrld xmm6, 24 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + pand xmm0, xmm7 + + movlps qword ptr [edx], xmm0 + movhps qword ptr [edx+ebx], xmm0 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock4HLP_sse2@12 endp + +; +; unSwizzleBlock4HHP +; + +@unSwizzleBlock4HHP_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck qdq, 0, 2, 1, 3, 4, 6 + + psrld xmm0, 28 + psrld xmm2, 28 + psrld xmm4, 28 + psrld xmm6, 28 + + packssdw xmm0, xmm2 + packssdw xmm4, xmm6 + packuswb xmm0, xmm4 + + movlps qword ptr [edx], xmm0 + movhps qword ptr [edx+ebx], xmm0 + + add ecx, 64 + lea edx, [edx+ebx*2] + + dec eax + jnz @B + + pop ebx + + ret 4 + +@unSwizzleBlock4HHP_sse2@12 endp + +; +; unSwizzleBlock4P +; + +@unSwizzleBlock4P_sse2@12 proc public + + push esi + push edi + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov esi, [esp+4+8] + lea edi, [esi*2] + add edi, esi + + ; col 0 + + movdqa xmm0, [ecx+16*0] + movdqa xmm1, [ecx+16*1] + movdqa xmm2, [ecx+16*2] + movdqa xmm3, [ecx+16*3] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + lea edx, [edx+esi*4] + + ; col 1 + + movdqa xmm0, [ecx+16*4] + movdqa xmm1, [ecx+16*5] + movdqa xmm2, [ecx+16*6] + movdqa xmm3, [ecx+16*7] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm0, xmm0, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm2, xmm2, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm4, xmm4, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm6, xmm6, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + lea edx, [edx+esi*4] + + ; col 2 + + movdqa xmm0, [ecx+16*8] + movdqa xmm1, [ecx+16*9] + movdqa xmm2, [ecx+16*10] + movdqa xmm3, [ecx+16*11] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm1, xmm1, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm3, xmm3, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + lea edx, [edx+esi*4] + + ; col 3 + + movdqa xmm0, [ecx+16*12] + movdqa xmm1, [ecx+16*13] + movdqa xmm2, [ecx+16*14] + movdqa xmm3, [ecx+16*15] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 4, 2, 6, 1, 3 + punpck bw, 0, 4, 1, 3, 2, 6 + + movdqa xmm1, xmm7 + pandn xmm1, xmm0 + pand xmm0, xmm7 + pshufd xmm0, xmm0, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm2 + pand xmm2, xmm7 + pshufd xmm2, xmm2, 0b1h + psrlq xmm3, 4 + + movdqa [edx], xmm0 + movdqa [edx+16], xmm2 + movdqa [edx+esi*2], xmm1 + movdqa [edx+esi*2+16], xmm3 + + movdqa xmm1, xmm7 + pandn xmm1, xmm4 + pand xmm4, xmm7 + pshufd xmm4, xmm4, 0b1h + psrlq xmm1, 4 + + movdqa xmm3, xmm7 + pandn xmm3, xmm6 + pand xmm6, xmm7 + pshufd xmm6, xmm6, 0b1h + psrlq xmm3, 4 + + movdqa [edx+esi], xmm4 + movdqa [edx+esi+16], xmm6 + movdqa [edx+edi], xmm1 + movdqa [edx+edi+16], xmm3 + + ; lea edx, [edx+esi*4] + + pop edi + pop esi + + ret 4 + +@unSwizzleBlock4P_sse2@12 endp + +; +; swizzling +; + +; +; SwizzleBlock32 +; + +@SwizzleBlock32_sse2@16 proc public + + + push esi + push edi + + mov edi, ecx + mov esi, edx + mov edx, [esp+4+8] + mov ecx, 4 + + mov eax, [esp+8+8] + cmp eax, 0ffffffffh + jnz SwizzleBlock32_sse2@WM + + align 16 +@@: + movdqa xmm0, [esi] + movdqa xmm4, [esi+16] + movdqa xmm1, [esi+edx] + movdqa xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movntps [edi+16*0], xmm0 + movntps [edi+16*1], xmm2 + movntps [edi+16*2], xmm4 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +SwizzleBlock32_sse2@WM: + + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqa xmm0, [esi] + movdqa xmm4, [esi+16] + movdqa xmm1, [esi+edx] + movdqa xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movntps [edi+16*0], xmm0 + + pandn xmm5, [edi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movntps [edi+16*1], xmm2 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*2] + pand xmm4, xmm7 + por xmm4, xmm3 + movntps [edi+16*2], xmm4 + + pandn xmm5, [edi+16*3] + pand xmm6, xmm7 + por xmm6, xmm5 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +@SwizzleBlock32_sse2@16 endp + +; +; SwizzleBlock16 +; + +@SwizzleBlock16_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [edx] + movdqa xmm1, [edx+16] + movdqa xmm2, [edx+ebx] + movdqa xmm3, [edx+ebx+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm5 + + lea edx, [edx+ebx*2] + add ecx, 64 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock16_sse2@12 endp + +; +; SwizzleBlock8 +; + +@SwizzleBlock8_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + pshufd xmm1, [edx], 0b1h + pshufd xmm3, [edx+ebx], 0b1h + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm4 + movntps [ecx+16*2], xmm1 + movntps [ecx+16*3], xmm5 + + ; col 1, 3 + + pshufd xmm0, [edx], 0b1h + pshufd xmm2, [edx+ebx], 0b1h + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm4 + movntps [ecx+16*6], xmm1 + movntps [ecx+16*7], xmm5 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock8_sse2@12 endp + +; +; SwizzleBlock4 +; + +@SwizzleBlock4_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm3 + + ; col 1, 3 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm1 + movntps [ecx+16*6], xmm4 + movntps [ecx+16*7], xmm3 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock4_sse2@12 endp + +; +; swizzling with unaligned reads +; + +; +; SwizzleBlock32u +; + +@SwizzleBlock32u_sse2@16 proc public + + push esi + push edi + + mov edi, ecx + mov esi, edx + mov edx, [esp+4+8] + mov ecx, 4 + + mov eax, [esp+8+8] + cmp eax, 0ffffffffh + jnz SwizzleBlock32u_sse2@WM + + align 16 +@@: + movdqu xmm0, [esi] + movdqu xmm4, [esi+16] + movdqu xmm1, [esi+edx] + movdqu xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movntps [edi+16*0], xmm0 + movntps [edi+16*1], xmm2 + movntps [edi+16*2], xmm4 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +SwizzleBlock32u_sse2@WM: + + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqu xmm0, [esi] + movdqu xmm4, [esi+16] + movdqu xmm1, [esi+edx] + movdqu xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [edi+16*0], xmm0 + + pandn xmm5, [edi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [edi+16*1], xmm2 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*2] + pand xmm4, xmm7 + por xmm4, xmm3 + movdqa [edi+16*2], xmm4 + + pandn xmm5, [edi+16*3] + pand xmm6, xmm7 + por xmm6, xmm5 + movdqa [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +@SwizzleBlock32u_sse2@16 endp + +; +; SwizzleBlock16u +; + +@SwizzleBlock16u_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqu xmm0, [edx] + movdqu xmm1, [edx+16] + movdqu xmm2, [edx+ebx] + movdqu xmm3, [edx+ebx+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm5 + + lea edx, [edx+ebx*2] + add ecx, 64 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock16u_sse2@12 endp + +; +; SwizzleBlock8u +; + +@SwizzleBlock8u_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + pshufd xmm1, xmm1, 0b1h + pshufd xmm3, xmm3, 0b1h + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm4 + movntps [ecx+16*2], xmm1 + movntps [ecx+16*3], xmm5 + + ; col 1, 3 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm4 + movntps [ecx+16*6], xmm1 + movntps [ecx+16*7], xmm5 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock8u_sse2@12 endp + +; +; SwizzleBlock4u +; + +@SwizzleBlock4u_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm3 + + ; col 1, 3 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm1 + movntps [ecx+16*6], xmm4 + movntps [ecx+16*7], xmm3 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock4u_sse2@12 endp + + end \ No newline at end of file diff --git a/plugins/zerogs/dx/x86-64.asm b/plugins/zerogs/dx/x86-64.asm new file mode 100644 index 0000000000..430960809f --- /dev/null +++ b/plugins/zerogs/dx/x86-64.asm @@ -0,0 +1,1090 @@ +; Copyright (C) 2003-2005 Gabest/zerofrog +; http:;;www.gabest.org +; +; 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, 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 GNU Make; see the file COPYING. If not, write to +; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +; http:;;www.gnu.org/copyleft/gpl.html +; +; +extern s_clut16mask:ptr + + .code + +; mmx memcpy implementation, size has to be a multiple of 8 +; returns 0 is equal, nonzero value if not equal +; ~10 times faster than standard memcmp +; (zerofrog) +; u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +; rcx - src1 +; rdx - src2 +; r8d - cmpsize +memcmp_mmx proc public + cmp r8d, 32 + jl Done4 + + ; custom test first 8 to make sure things are ok + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pand mm0, mm1 + movq mm2, [rdx+16] + pmovmskb eax, mm0 + movq mm3, [rdx+24] + + ; check if eq + cmp eax, 0ffh + je NextComp + mov eax, 1 + jmp Finish + +NextComp: + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub r8d, 32 + add rdx, 32 + add rcx, 32 + + ; check if eq + cmp eax, 0ffh + je ContinueTest + mov eax, 1 + jmp Finish + + cmp r8d, 64 + jl Done8 + +Cmp8: + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + movq mm4, [rdx+32] + movq mm5, [rdx+40] + movq mm6, [rdx+48] + movq mm7, [rdx+56] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm0, mm1 + pcmpeqd mm4, [rcx+32] + pand mm0, mm2 + pcmpeqd mm5, [rcx+40] + pand mm0, mm3 + pcmpeqd mm6, [rcx+48] + pand mm0, mm4 + pcmpeqd mm7, [rcx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Continue + mov eax, 1 + jmp Finish + +Continue: + sub r8d, 64 + add rdx, 64 + add rcx, 64 +ContinueTest: + cmp r8d, 64 + jge Cmp8 + +Done8: + test r8d, 020h + jz Done4 + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub r8d, 32 + add rdx, 32 + add rcx, 32 + + ; check if eq + cmp eax, 0ffh + je Done4 + mov eax, 1 + jmp Finish + +Done4: + cmp r8d, 24 + jne Done2 + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Done + mov eax, 1 + jmp Finish + +Done2: + cmp r8d, 16 + jne Done1 + + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Done + mov eax, 1 + jmp Finish + +Done1: + cmp r8d, 8 + jne Done + + mov eax, [rdx] + mov rdx, [rdx+4] + cmp eax, [rcx] + je Next + mov eax, 1 + jmp Finish + +Next: + cmp rdx, [rcx+4] + je Done + mov eax, 1 + jmp Finish + +Done: + xor eax, eax + +Finish: + emms + ret + +memcmp_mmx endp + +; TestClutChangeMMX +; mov rdx, dst +; mov rcx, src +; mov r8d, entries +TestClutChangeMMX proc public + +Start: + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+16] + + movq mm2, [rdx+16] + movq mm3, [rdx+24] + pcmpeqd mm2, [rcx+32] + pcmpeqd mm3, [rcx+48] + + pand mm0, mm1 + pand mm2, mm3 + movq mm4, [rdx+32] + movq mm5, [rdx+40] + pcmpeqd mm4, [rcx+8] + pcmpeqd mm5, [rcx+24] + + pand mm0, mm2 + pand mm4, mm5 + movq mm6, [rdx+48] + movq mm7, [rdx+56] + pcmpeqd mm6, [rcx+40] + pcmpeqd mm7, [rcx+56] + + pand mm0, mm4 + pand mm6, mm7 + pand mm0, mm6 + + pmovmskb eax, mm0 + cmp eax, 0ffh + je Continue + mov byte ptr [r9], 1 + jmp Return + +Continue: + cmp r8d, 16 + jle Return + + test r8d, 010h + jz AddRcx + sub rcx, 448 ; go back and down one column, +AddRcx: + add rcx, 256 ; go to the right block + + + jne Continue1 + add rcx, 256 ; skip whole block +Continue1: + add rdx, 64 + sub r8d, 16 + jmp Start + +Return: + emms + ret + +TestClutChangeMMX endp + +UnswizzleZ16Target proc public + pxor xmm7, xmm7 + +Z16Loop: + ;; unpack 64 bytes at a time + movdqa xmm0, [rdx] + movdqa xmm2, [rdx+16] + movdqa xmm4, [rdx+32] + movdqa xmm6, [rdx+48] + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm5, xmm4 + + punpcklwd xmm0, xmm7 + punpckhwd xmm1, xmm7 + punpcklwd xmm2, xmm7 + punpckhwd xmm3, xmm7 + + ;; start saving + movdqa [rcx], xmm0 + movdqa [rcx+16], xmm1 + + punpcklwd xmm4, xmm7 + punpckhwd xmm5, xmm7 + + movdqa [rcx+32], xmm2 + movdqa [rcx+48], xmm3 + + movdqa xmm0, xmm6 + punpcklwd xmm6, xmm7 + + movdqa [rcx+64], xmm4 + movdqa [rcx+80], xmm5 + + punpckhwd xmm0, xmm7 + + movdqa [rcx+96], xmm6 + movdqa [rcx+112], xmm0 + + add rdx, 64 + add rcx, 128 + sub r9d, 1 + jne Z16Loop + + ret +UnswizzleZ16Target endp + +; +; swizzling +; + +punpck macro op, sd0, sd2, s1, s3, d1, d3 + + movdqa @CatStr(xmm, %d1), @CatStr(xmm, %sd0) + pshufd @CatStr(xmm, %d3), @CatStr(xmm, %sd2), 0e4h + + @CatStr(punpckl, op) @CatStr(xmm, %sd0), @CatStr(xmm, %s1) + @CatStr(punpckh, op) @CatStr(xmm, %d1), @CatStr(xmm, %s1) + @CatStr(punpckl, op) @CatStr(xmm, %sd2), @CatStr(xmm, %s3) + @CatStr(punpckh, op) @CatStr(xmm, %d3), @CatStr(xmm, %s3) + + endm + +punpcknbl macro + + movdqa xmm4, xmm0 + pshufd xmm5, xmm1, 0e4h + + psllq xmm1, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm0, xmm7 + pandn xmm6, xmm1 + por xmm0, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm1, xmm4 + + movdqa xmm4, xmm2 + pshufd xmm5, xmm3, 0e4h + + psllq xmm3, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm2, xmm7 + pandn xmm6, xmm3 + por xmm2, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm3, xmm4 + + punpck bw, 0, 2, 1, 3, 4, 6 + + endm + +punpcknbh macro + + movdqa xmm12, xmm8 + pshufd xmm13, xmm9, 0e4h + + psllq xmm9, 4 + psrlq xmm12, 4 + + movdqa xmm14, xmm15 + pand xmm8, xmm15 + pandn xmm14, xmm9 + por xmm8, xmm14 + + movdqa xmm14, xmm15 + pand xmm12, xmm15 + pandn xmm14, xmm13 + por xmm12, xmm14 + + movdqa xmm9, xmm12 + + movdqa xmm12, xmm10 + pshufd xmm13, xmm11, 0e4h + + psllq xmm11, 4 + psrlq xmm12, 4 + + movdqa xmm14, xmm15 + pand xmm10, xmm15 + pandn xmm14, xmm11 + por xmm10, xmm14 + + movdqa xmm14, xmm15 + pand xmm12, xmm15 + pandn xmm14, xmm13 + por xmm12, xmm14 + + movdqa xmm11, xmm12 + + punpck bw, 8, 10, 9, 11, 12, 14 + + endm + +; +; SwizzleBlock32_sse2 +; + +SwizzleBlock32_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + cmp r9d, 0ffffffffh + jne SwizzleBlock32_sse2@WM + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm4, [rsi+16] + movdqa xmm1, [rsi+r8] + movdqa xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm2 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32_sse2@WM: + + movd xmm7, r9d + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm4, [rsi+16] + movdqa xmm1, [rsi+r8] + movdqa xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + movdqa xmm9, xmm7 + pshufd xmm11, xmm7, 0e4h + + pandn xmm3, [rdi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [rdi+16*0], xmm0 + + pandn xmm5, [rdi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [rdi+16*1], xmm2 + + pandn xmm9, [rdi+16*2] + pand xmm4, xmm7 + por xmm4, xmm9 + movdqa [rdi+16*2], xmm4 + + pandn xmm11, [rdi+16*3] + pand xmm6, xmm7 + por xmm6, xmm11 + movdqa [edi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32_sse2 endp + +; +; SwizzleBlock16_sse2 +; + +SwizzleBlock16_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm1, [rsi+16] + movdqa xmm2, [rsi+r8] + movdqa xmm3, [rsi+r8+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm5 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock16_sse2 endp + +; +; SwizzleBlock8 +; + +SwizzleBlock8_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov ecx, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshufd xmm1, [rsi], 0b1h + pshufd xmm3, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm4 + movdqa [rdi+16*2], xmm1 + movdqa [rdi+16*3], xmm5 + + ; col 1, 3 + + pshufd xmm0, [rsi], 0b1h + pshufd xmm2, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm4 + movdqa [rdi+16*6], xmm1 + movdqa [rdi+16*7], xmm5 + + add edi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock8_sse2 endp + +; +; SwizzleBlock4 +; + +SwizzleBlock4_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 2 + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm3 + + ; col 1, 3 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea esi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm1 + movdqa [rdi+16*6], xmm4 + movdqa [rdi+16*7], xmm3 + + add rdi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock4_sse2 endp + +; +; swizzling with unaligned reads +; + +; +; SwizzleBlock32u_sse2 +; + +SwizzleBlock32u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + cmp r9d, 0ffffffffh + jne SwizzleBlock32u_sse2@WM + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm4, [rsi+16] + movdqu xmm1, [rsi+r8] + movdqu xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm2 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32u_sse2@WM: + + movd xmm7, r9d + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm4, [rsi+16] + movdqu xmm1, [rsi+r8] + movdqu xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + movdqa xmm9, xmm7 + pshufd xmm11, xmm7, 0e4h + + pandn xmm3, [rdi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [rdi+16*0], xmm0 + + pandn xmm5, [rdi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [rdi+16*1], xmm2 + + pandn xmm9, [rdi+16*2] + pand xmm4, xmm7 + por xmm4, xmm9 + movdqa [rdi+16*2], xmm4 + + pandn xmm11, [rdi+16*3] + pand xmm6, xmm7 + por xmm6, xmm11 + movdqa [edi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32u_sse2 endp + +; +; SwizzleBlock16u_sse2 +; + +SwizzleBlock16u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm1, [rsi+16] + movdqu xmm2, [rsi+r8] + movdqu xmm3, [rsi+r8+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm5 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock16u_sse2 endp + +; +; SwizzleBlock8u +; + +SwizzleBlock8u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov ecx, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshufd xmm1, xmm0, 0b1h + pshufd xmm3, xmm2, 0b1h + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm4 + movdqa [rdi+16*2], xmm1 + movdqa [rdi+16*3], xmm5 + + ; col 1, 3 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + lea rsi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm4 + movdqa [rdi+16*6], xmm1 + movdqa [rdi+16*7], xmm5 + + add edi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock8u_sse2 endp + +; +; SwizzleBlock4u +; + +SwizzleBlock4u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 2 + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm3 + + ; col 1, 3 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea esi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm1 + movdqa [rdi+16*6], xmm4 + movdqa [rdi+16*7], xmm3 + + add rdi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock4u_sse2 endp + +WriteCLUT_T16_I4_CSM1_sse2 proc public + movdqa xmm0, XMMWORD PTR [rcx] + movdqa xmm1, XMMWORD PTR [rcx+16] + movdqa xmm2, XMMWORD PTR [rcx+32] + movdqa xmm3, XMMWORD PTR [rcx+48] + + ;; rearrange + pshuflw xmm0, xmm0, 088h + pshufhw xmm0, xmm0, 088h + pshuflw xmm1, xmm1, 088h + pshufhw xmm1, xmm1, 088h + pshuflw xmm2, xmm2, 088h + pshufhw xmm2, xmm2, 088h + pshuflw xmm3, xmm3, 088h + pshufhw xmm3, xmm3, 088h + + shufps xmm0, xmm1, 088h + shufps xmm2, xmm3, 088h + + pshufd xmm0, xmm0, 0d8h + pshufd xmm2, xmm2, 0d8h + + pxor xmm6, xmm6 + mov rax, offset s_clut16mask + + test rdx, 15 + jnz WriteUnaligned + + movdqa xmm7, XMMWORD PTR [rax] ;; saves upper 16 bits + + ;; have to save interlaced with the old data + movdqa xmm4, [rdx] + movdqa xmm5, [rdx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 ;; lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0e4h ;; upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + + movdqa [rdx], xmm0 + movdqa [rdx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [rdx+16] + pand xmm5, [rdx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [rdx+16], xmm2 + movdqa [rdx+48], xmm3 + jmp WriteCLUT_T16_I4_CSM1_End + +WriteUnaligned: + ;; rdx is offset by 2 + sub rdx, 2 + + movdqa xmm7, XMMWORD PTR [rax+16] ;; saves lower 16 bits + + ;; have to save interlaced with the old data + movdqa xmm4, [rdx] + movdqa xmm5, [rdx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 ;; lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0e4h ;; upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + pslld xmm0, 16 + pslld xmm1, 16 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + pslld xmm2, 16 + pslld xmm3, 16 + + movdqa [rdx], xmm0 + movdqa [rdx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [rdx+16] + pand xmm5, [rdx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [rdx+16], xmm2 + movdqa [rdx+48], xmm3 +WriteCLUT_T16_I4_CSM1_End: + ret + +WriteCLUT_T16_I4_CSM1_sse2 endp + +end \ No newline at end of file diff --git a/plugins/zerogs/dx/x86.cpp b/plugins/zerogs/dx/x86.cpp new file mode 100644 index 0000000000..6b3a2d9b42 --- /dev/null +++ b/plugins/zerogs/dx/x86.cpp @@ -0,0 +1,573 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include + +#include "GS.h" +#include "Mem.h" +#include "x86.h" + +#if defined(ZEROGS_SSE2) && (defined(_WIN32)||defined(__x86_64__)) +#include +#include +#endif + +// swizzling + +void FASTCALL(SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask)) +{ + u32* d = &g_columnTable32[0][0]; + + if(WriteMask == 0xffffffff) + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = ((u32*)src)[i]; + } + else + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = (((u32*)dst)[d[i]] & ~WriteMask) | (((u32*)src)[i] & WriteMask); + } +} + +void FASTCALL(SwizzleBlock16_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable16[0][0]; + + for(int j = 0; j < 8; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + ((u16*)dst)[d[i]] = ((u16*)src)[i]; +} + +void FASTCALL(SwizzleBlock8_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable8[0][0]; + + for(int j = 0; j < 16; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + dst[d[i]] = src[i]; +} + +void FASTCALL(SwizzleBlock4_c(u8* dst, u8* src, int srcpitch)) +{ + u32* d = &g_columnTable4[0][0]; + + for(int j = 0; j < 16; j++, d += 32, src += srcpitch) + { + for(int i = 0; i < 32; i++) + { + u32 addr = d[i]; + u8 c = (src[i>>1] >> ((i&1) << 2)) & 0x0f; + u32 shift = (addr&1) << 2; + dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); + } + } +} + +#define _FrameSwizzleBlock(type, transfer, transfer16, incsrc) \ +/* FrameSwizzleBlock32 */ \ +void FASTCALL(FrameSwizzleBlock32##type##c(u32* dst, u32* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + \ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = (transfer); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = ((transfer)&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* FrameSwizzleBlock16 */ \ +void FASTCALL(FrameSwizzleBlock16##type##c(u16* dst, u32* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( WriteMask == 0xffff ) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + dst[d[j]] = RGBA32to16(temp); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + u32 dsrc = RGBA32to16(temp); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* Frame16SwizzleBlock32 */ \ +void FASTCALL(Frame16SwizzleBlock32##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ +\ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ +\ +/* Frame16SwizzleBlock32Z */ \ +void FASTCALL(Frame16SwizzleBlock32Z##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + if( WriteMask == 0xffffffff ) { /* breaks KH text if not checked */ \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB_Z(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16 */ \ +void FASTCALL(Frame16SwizzleBlock16##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( (WriteMask&0xfff8f8f8) == 0xfff8f8f8) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB16(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16Z */ \ +void FASTCALL(Frame16SwizzleBlock16Z##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ +} \ + +_FrameSwizzleBlock(_, src[j], src[j], 0); +_FrameSwizzleBlock(A2_, (src[2*j]+src[2*j+1])>>1, src[2*j], 0); +_FrameSwizzleBlock(A4_, (src[2*j]+src[2*j+1]+src[2*j+srcpitch]+src[2*j+srcpitch+1])>>2, src[2*j], 1); + +#ifdef ZEROGS_SSE2 + +//void FASTCALL(WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut) +//{ +// __asm { +// mov eax, vm +// mov ecx, clut +// mov edx, 8 +// } +// +//Extract32x2: +// __asm { +// movdqa xmm0, qword ptr [eax] +// movdqa xmm1, qword ptr [eax+16] +// movdqa xmm2, qword ptr [eax+32] +// movdqa xmm3, qword ptr [eax+48] +// +// // rearrange +// pshuflw xmm0, xmm0, 0xd8 +// pshufhw xmm0, xmm0, 0xd8 +// pshuflw xmm1, xmm1, 0xd8 +// pshufhw xmm1, xmm1, 0xd8 +// pshuflw xmm2, xmm2, 0xd8 +// pshufhw xmm2, xmm2, 0xd8 +// pshuflw xmm3, xmm3, 0xd8 +// pshufhw xmm3, xmm3, 0xd8 +// +// movdqa xmm4, xmm0 +// movdqa xmm6, xmm2 +// +// shufps xmm0, xmm1, 0x88 +// shufps xmm2, xmm3, 0x88 +// +// shufps xmm4, xmm1, 0xdd +// shufps xmm6, xmm3, 0xdd +// +// pshufd xmm0, xmm0, 0xd8 +// pshufd xmm2, xmm2, 0xd8 +// pshufd xmm4, xmm4, 0xd8 +// pshufd xmm6, xmm6, 0xd8 +// +// // left column +// movhlps xmm1, xmm0 +// movlhps xmm0, xmm2 +// //movdqa xmm7, [ecx] +// +// movdqa [ecx], xmm0 +// shufps xmm1, xmm2, 0xe4 +// movdqa [ecx+16], xmm1 +// +// // right column +// movhlps xmm3, xmm4 +// movlhps xmm4, xmm6 +// movdqa [ecx+32], xmm4 +// shufps xmm3, xmm6, 0xe4 +// movdqa [ecx+48], xmm3 +// +// add eax, 16*4 +// add ecx, 16*8 +// sub edx, 1 +// cmp edx, 0 +// jne Extract32x2 +// } +//} + +#if (defined(_WIN32)||defined(__x86_64__)) + +extern "C" void FASTCALL(WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut)) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + for(int j = 0; j < 64; j += 32, src += 32, dst += 32) + { + for(int i = 0; i < 16; i += 4) + { + __m128i r0 = _mm_load_si128(&src[i+0]); + __m128i r1 = _mm_load_si128(&src[i+1]); + __m128i r2 = _mm_load_si128(&src[i+2]); + __m128i r3 = _mm_load_si128(&src[i+3]); + + _mm_store_si128(&dst[i*2+0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[i*2+2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+3], _mm_unpackhi_epi64(r2, r3)); + + __m128i r4 = _mm_load_si128(&src[i+0+16]); + __m128i r5 = _mm_load_si128(&src[i+1+16]); + __m128i r6 = _mm_load_si128(&src[i+2+16]); + __m128i r7 = _mm_load_si128(&src[i+3+16]); + + _mm_store_si128(&dst[i*2+4], _mm_unpacklo_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+5], _mm_unpacklo_epi64(r6, r7)); + _mm_store_si128(&dst[i*2+6], _mm_unpackhi_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+7], _mm_unpackhi_epi64(r6, r7)); + } + } +} + +extern "C" void FASTCALL(WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut)) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + __m128i r0 = _mm_load_si128(&src[0]); + __m128i r1 = _mm_load_si128(&src[1]); + __m128i r2 = _mm_load_si128(&src[2]); + __m128i r3 = _mm_load_si128(&src[3]); + + _mm_store_si128(&dst[0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[3], _mm_unpackhi_epi64(r2, r3)); +} +#endif + +#if defined(_MSC_VER) + +extern "C" { +PCSX2_ALIGNED16(int s_clut16mask2[4]) = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; +PCSX2_ALIGNED16(int s_clut16mask[8]) = { 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, + 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}; +} + +#if !defined(__x86_64__) + +extern "C" void FASTCALL(WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut)) +{ + __asm { + mov eax, vm + mov ecx, clut + movdqa xmm0, qword ptr [eax] + movdqa xmm1, qword ptr [eax+16] + movdqa xmm2, qword ptr [eax+32] + movdqa xmm3, qword ptr [eax+48] + + // rearrange + pshuflw xmm0, xmm0, 0x88 + pshufhw xmm0, xmm0, 0x88 + pshuflw xmm1, xmm1, 0x88 + pshufhw xmm1, xmm1, 0x88 + pshuflw xmm2, xmm2, 0x88 + pshufhw xmm2, xmm2, 0x88 + pshuflw xmm3, xmm3, 0x88 + pshufhw xmm3, xmm3, 0x88 + + shufps xmm0, xmm1, 0x88 + shufps xmm2, xmm3, 0x88 + + pshufd xmm0, xmm0, 0xd8 + pshufd xmm2, xmm2, 0xd8 + + pxor xmm6, xmm6 + + test ecx, 15 + jnz WriteUnaligned + + movdqa xmm7, s_clut16mask // saves upper 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 + jmp End + +WriteUnaligned: + // ecx is offset by 2 + sub ecx, 2 + + movdqa xmm7, s_clut16mask2 // saves lower 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + pslld xmm0, 16 + pslld xmm1, 16 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + pslld xmm2, 16 + pslld xmm3, 16 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 +End: + } +} +#endif // __x86_64__ +#endif // _MSC_VER + +#endif // ZEROGS_SSE2 + +void FASTCALL(WriteCLUT_T16_I8_CSM1_c(u32* _vm, u32* _clut)) +{ + const static u32 map[] = + { + 0, 2, 8, 10, 16, 18, 24, 26, + 4, 6, 12, 14, 20, 22, 28, 30, + 1, 3, 9, 11, 17, 19, 25, 27, + 5, 7, 13, 15, 21, 23, 29, 31 + }; + + u16* vm = (u16*)_vm; + u16* clut = (u16*)_clut; + + int left = ((u32)(uptr)clut&2) ? 512 : 512-(((u32)(uptr)clut)&0x3ff)/2; + + for(int j = 0; j < 8; j++, vm += 32, clut += 64, left -= 32) + { + if(left == 32) { + assert( left == 32 ); + for(int i = 0; i < 16; i++) + clut[2*i] = vm[map[i]]; + + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + + for(int i = 16; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + else { + if( left == 0 ) { + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + left = -1; + } + + for(int i = 0; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + } +} + +void FASTCALL(WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut)) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + for(int j = 0; j < 2; j++, src += 32) { + for(int i = 0; i < 4; i++, dst+=16, src+=8) + { + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; + + dst[8] = src[32]; + dst[9] = src[32+2]; + dst[10] = src[32+4]; + dst[11] = src[32+6]; + dst[12] = src[32+1]; + dst[13] = src[32+3]; + dst[14] = src[32+5]; + dst[15] = src[32+7]; + } + } +} + +void FASTCALL(WriteCLUT_T16_I4_CSM1_c(u32* _vm, u32* _clut)) +{ + u16* dst = (u16*)_clut; + u16* src = (u16*)_vm; + + dst[0] = src[0]; dst[2] = src[2]; + dst[4] = src[8]; dst[6] = src[10]; + dst[8] = src[16]; dst[10] = src[18]; + dst[12] = src[24]; dst[14] = src[26]; + dst[16] = src[4]; dst[18] = src[6]; + dst[20] = src[12]; dst[22] = src[14]; + dst[24] = src[20]; dst[26] = src[22]; + dst[28] = src[28]; dst[30] = src[30]; +} + +void FASTCALL(WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut)) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; +} diff --git a/plugins/zerogs/dx/x86.h b/plugins/zerogs/dx/x86.h new file mode 100644 index 0000000000..6859c1a313 --- /dev/null +++ b/plugins/zerogs/dx/x86.h @@ -0,0 +1,184 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef ZEROGS_X86 +#define ZEROGS_X86 + +#include +#include +#include "GS.h" + +extern "C" void FASTCALL(SwizzleBlock32_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern "C" void FASTCALL(SwizzleBlock16_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock8_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock4_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock32u_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern "C" void FASTCALL(SwizzleBlock16u_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock8u_sse2(u8* dst, u8* src, int srcpitch)); +extern "C" void FASTCALL(SwizzleBlock4u_sse2(u8* dst, u8* src, int srcpitch)); + +// frame swizzling + +// no AA +extern "C" void FASTCALL(FrameSwizzleBlock32_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32Z_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16Z_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 2x +extern "C" void FASTCALL(FrameSwizzleBlock32A2_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16A2_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32A2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32ZA2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16A2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16ZA2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 4x +extern "C" void FASTCALL(FrameSwizzleBlock32A4_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(FrameSwizzleBlock16A4_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32A4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock32ZA4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16A4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern "C" void FASTCALL(Frame16SwizzleBlock16ZA4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +extern void FASTCALL(SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern void FASTCALL(SwizzleBlock16_c(u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleBlock8_c(u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleBlock4_c(u8* dst, u8* src, int srcpitch)); + +// no AA +extern void FASTCALL(FrameSwizzleBlock32_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32Z_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16Z_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 2x +extern void FASTCALL(FrameSwizzleBlock32A2_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16A2_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32A2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32ZA2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16A2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16ZA2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +// AA 4x +extern void FASTCALL(FrameSwizzleBlock32A4_c(u32* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(FrameSwizzleBlock16A4_c(u16* dst, u32* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32A4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock32ZA4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16A4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); +extern void FASTCALL(Frame16SwizzleBlock16ZA4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask)); + +extern void FASTCALL(SwizzleColumn32_c(int y, u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff)); +extern void FASTCALL(SwizzleColumn16_c(int y, u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleColumn8_c(int y, u8* dst, u8* src, int srcpitch)); +extern void FASTCALL(SwizzleColumn4_c(int y, u8* dst, u8* src, int srcpitch)); + +extern "C" void FASTCALL(WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut)); +extern "C" void FASTCALL(WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T16_I8_CSM1_c(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut)); + +extern void FASTCALL(WriteCLUT_T16_I4_CSM1_c(u32* vm, u32* clut)); +extern void FASTCALL(WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut)); + +#ifdef ZEROGS_SSE2 + +#define SwizzleBlock32 SwizzleBlock32_sse2 +#define SwizzleBlock16 SwizzleBlock16_sse2 +#define SwizzleBlock8 SwizzleBlock8_sse2 +#define SwizzleBlock4 SwizzleBlock4_sse2 +#define SwizzleBlock32u SwizzleBlock32u_sse2 +#define SwizzleBlock16u SwizzleBlock16u_sse2 +#define SwizzleBlock8u SwizzleBlock8u_sse2 +#define SwizzleBlock4u SwizzleBlock4u_sse2 + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_sse2 +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_sse2 +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_sse2 +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_sse2 + +#else + +#define SwizzleBlock32 SwizzleBlock32_c +#define SwizzleBlock16 SwizzleBlock16_c +#define SwizzleBlock8 SwizzleBlock8_c +#define SwizzleBlock4 SwizzleBlock4_c +#define SwizzleBlock32u SwizzleBlock32_c +#define SwizzleBlock16u SwizzleBlock16_c +#define SwizzleBlock8u SwizzleBlock8_c +#define SwizzleBlock4u SwizzleBlock4_c + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_c +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_c +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_c +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_c + +#endif + +#endif diff --git a/plugins/zerogs/dx/zerogs.cpp b/plugins/zerogs/dx/zerogs.cpp new file mode 100644 index 0000000000..22bb7c51e1 --- /dev/null +++ b/plugins/zerogs/dx/zerogs.cpp @@ -0,0 +1,5106 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) || defined(__WIN32__) +#include +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "x86.h" +#include "Regs.h" +#include "zerogs.h" +#include "resource.h" + +#include "zerogsshaders/zerogsshaders.h" +#include "targets.h" + +#define DEBUG_PS2 0 + +#define POINT_BUFFERFLUSH 512 +#define POINT_BUFFERSIZE (1<<18) + +#define MINMAX_SHIFT 3 +#define MAX_ACTIVECLUTS 16 + +#define ZEROGS_SAVEVER 0xaa000005 + +#define STENCIL_ALPHABIT 1 // if set, dest alpha >= 0x80 +#define STENCIL_PIXELWRITE 2 // if set, pixel just written (reset after every Flush) +#define STENCIL_FBA 4 // if set, just written pixel's alpha >= 0 (reset after every Flush) +#define STENCIL_SPECIAL 8 // if set, indicates that pixel passed its alpha test (reset after every Flush) +//#define STENCIL_PBE 16 +#define STENCIL_CLEAR (2|4|8|16) + +#define VBSAVELIMIT ((u32)((u8*)&vb[0].nNextFrameHeight-(u8*)&vb[0])) + +using namespace ZeroGS; + +static LPDIRECT3D9 pD3D = NULL; // Used to create the D3DDevice +LPDIRECT3DDEVICE9 pd3dDevice = NULL; +static DXVEC4 s_vznorm; +extern u32 g_nGenVars, g_nTexVars, g_nAlphaVars, g_nResolve; +extern char *libraryName; +extern int g_nFrame, g_nRealFrame; +extern float fFPS; +extern unsigned char revision, build, minor; + +BOOL g_bDisplayMsg = 1; + +extern HINSTANCE hInst; + +BOOL g_bSaveFlushedFrame = 1; +BOOL g_bIsLost = 0; +int g_nFrameRender = 10; +int g_nFramesSkipped = 0; +int g_MaxRenderedHeight = 0; + +#ifdef RELEASE_TO_PUBLIC + +#define INC_GENVARS() +#define INC_TEXVARS() +#define INC_ALPHAVARS() +#define INC_RESOLVE() + +#define g_bUpdateEffect 0 +#define g_bWriteProfile 0 +#define g_bSaveTex 0 +#define g_bSaveTrans 0 +#define g_bSaveFrame 0 +#define g_bSaveFinalFrame 0 +#define g_bUpdateStencil 1 +#define g_bSaveResolved 0 + +#else + +#define INC_GENVARS() ++g_nGenVars +#define INC_TEXVARS() ++g_nTexVars +#define INC_ALPHAVARS() ++g_nAlphaVars +#define INC_RESOLVE() ++g_nResolve + +BOOL g_bSaveTrans = 0; +BOOL g_bUpdateEffect = 0; +BOOL g_bWriteProfile = 0; +BOOL g_bSaveTex = 0; // saves the curent texture +BOOL g_bSaveFrame = 0; // saves the current psurfTarget +BOOL g_bSaveFinalFrame = 0; // saves the input to the CRTC +BOOL g_bUpdateStencil = 1; // only needed for dest alpha test (unfortunately, it has to be on all the time) +BOOL g_bSaveResolved = 0; + +#endif + +#define DRAW() pd3dDevice->DrawPrimitive(primtype[curvb.curprim.prim], 0, curvb.dwCount) + +extern int s_frameskipping; + +//inline void SetRenderTarget_(int index, LPD3DSURF psurf, int counter, const char* pname) +//{ +// static LPD3DSURF ptargs[4] = {NULL}; +// static int counters[4] = {0}; +// static const char* pnames[4] = {NULL}; +// +// if( ptargs[index] == psurf && psurf != NULL ) +// DEBUG_LOG("duplicate targets\n"); +// pd3dDevice->SetRenderTarget(index, psurf); +// ptargs[index] = psurf; +// counters[index] = counter; +// pnames[index] = pname; +//} +// +//#define SetRenderTarget(index, psurf) SetRenderTarget_(index, psurf, __COUNTER__, __FUNCTION__) + +static u32 g_SaveFrameNum = 0; +BOOL g_bMakeSnapshot = 0; +string strSnapshot; + +int GPU_TEXWIDTH = 512; +float g_fiGPU_TEXWIDTH = 1/512.0f; + +int g_MaxTexWidth = 4096, g_MaxTexHeight = 4096; + +// AVI Capture +static int s_aviinit = 0; +static int s_avicapturing = 0; +static LPD3DSURF s_ptexAVICapture = NULL; // system memory texture + +const u32 g_primmult[8] = { 1, 2, 2, 3, 3, 3, 2, 0xff }; +const u32 g_primsub[8] = { 1, 2, 1, 3, 1, 1, 2, 0 }; + +inline DWORD FtoDW(float f) { return (*((DWORD*)&f)); } + +float g_fBlockMult = 1; +static int s_nFullscreen = 0; +int g_nDepthUpdateCount = 0; +int g_nDepthBias = 0; + +// Consts +static const D3DPRIMITIVETYPE primtype[8] = { D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_LINELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLELIST, D3DPT_FORCE_DWORD }; +static const DWORD blendalpha[3] = { D3DBLEND_SRCALPHA, D3DBLEND_DESTALPHA, D3DBLEND_BLENDFACTOR }; +static const DWORD blendinvalpha[3] = { D3DBLEND_INVSRCALPHA, D3DBLEND_INVDESTALPHA, D3DBLEND_INVBLENDFACTOR }; + +static const int PRIMMASK = 0x0e; // for now ignore 0x10 (AA) + +static const DWORD g_dwAlphaCmp[] = { D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_LESS, D3DCMP_LESSEQUAL, + D3DCMP_EQUAL, D3DCMP_GREATEREQUAL, D3DCMP_GREATER, D3DCMP_NOTEQUAL }; + +// used for afail case +static const DWORD g_dwReverseAlphaCmp[] = { D3DCMP_ALWAYS, D3DCMP_NEVER, D3DCMP_GREATEREQUAL, D3DCMP_GREATER, + D3DCMP_NOTEQUAL, D3DCMP_LESS, D3DCMP_LESSEQUAL, D3DCMP_EQUAL }; + +static const DWORD g_dwZCmp[] = { D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_GREATEREQUAL, D3DCMP_GREATER }; + +///////////////////// +// graphics resources +static LPD3DDECL pdecl = NULL; +static LPD3DVS pvs[16] = {NULL}; +static LPD3DPS ppsRegular[4] = {NULL}, ppsTexture[NUM_SHADERS] = {NULL}; +static LPD3DPS ppsCRTC[2] = {NULL}, ppsCRTC24[2] = {NULL}, ppsCRTCTarg[2] = {NULL}; + +int g_nPixelShaderVer = SHADER_30; // default + +static BYTE* s_lpShaderResources = NULL; +static map mapShaderResources; + +LPD3DTEX s_ptexCurSet[2] = {NULL}; + +#define s_bForceTexFlush 1 +static LPD3DTEX s_ptexNextSet[2] = {NULL}; + +static ID3DXFont* pFont = NULL; +static ID3DXSprite* pSprite = NULL; + +static LPD3DSURF psurfOrgTarg = NULL, psurfOrgDepth = NULL; + +LPD3DTEX ptexBlocks = NULL, ptexConv16to32 = NULL; // holds information on block tiling +LPD3DTEX ptexBilinearBlocks = NULL; +IDirect3DVolumeTexture9* ptexConv32to16 = NULL; +static LPD3DTEX s_ptexInterlace = NULL; // holds interlace fields +static int s_nInterlaceTexWidth = 0; // width of texture +static list s_vecTempTextures; // temporary textures, released at the end of every frame + +static BOOL s_bTexFlush = FALSE; +static LPD3DTEX ptexLogo = NULL; +static BOOL s_bWriteDepth = FALSE; +static BOOL s_bDestAlphaTest = FALSE; +static int s_nLastResolveReset = 0; +static int s_nResolveCounts[30] = {0}; // resolve counts for last 30 frames +static int s_nCurResolveIndex = 0; +int s_nResolved = 0; // number of targets resolved this frame +int g_nDepthUsed = 0; // ffx2 pal movies +static int s_nWriteDepthCount = 0; +static int s_nWireframeCount = 0; +static int s_nWriteDestAlphaTest = 0; + +//////////////////// +// State parameters +static float fiRendWidth, fiRendHeight; + +static DWORD dwStencilRef, dwStencilMask; + +static DXVEC4 vAlphaBlendColor; // used for GPU_COLOR + +static BYTE bNeedBlendFactorInAlpha; // set if the output source alpha is different from the real source alpha (only when blend factor > 0x80) +static DWORD s_dwColorWrite = 0xf; // the color write mask of the current target + +BOOL g_bDisplayFPS = FALSE; + +union { + struct { + BYTE _bNeedAlphaColor; // set if vAlphaBlendColor needs to be set + BYTE _b2XAlphaTest; // Only valid when bNeedAlphaColor is set. if 1st bit set set, double all alpha testing values + // otherwise alpha testing needs to be done separately. + BYTE _bDestAlphaColor; // set to 1 if blending with dest color (process only one tri at a time). If 2, dest alpha is always 1. + BYTE _bAlphaClamping; // if first bit is set, do min; if second bit, do max + }; + u32 _bAlphaState; +} g_vars; + +#define bNeedAlphaColor g_vars._bNeedAlphaColor +#define b2XAlphaTest g_vars._b2XAlphaTest +#define bDestAlphaColor g_vars._bDestAlphaColor +#define bAlphaClamping g_vars._bAlphaClamping + +int g_PrevBitwiseTexX = -1, g_PrevBitwiseTexY = -1; // textures stored in SAMP_BITWISEANDX and SAMP_BITWISEANDY + +// stores the buffers for the last RenderCRTC +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +static BOOL s_bAlphaSet = FALSE; +static alphaInfo s_alphaInfo; + +namespace ZeroGS +{ + VB vb[2]; + float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + LONG width, height; + u8* g_pbyGSMemory = NULL; // 4Mb GS system mem + u8* g_pbyGSClut = NULL; + + D3DPRESENT_PARAMETERS d3dpp; + + BYTE s_AAx = 0, s_AAy = 0; // if AAy is set, then AAx has to be set + BYTE bIndepWriteMasks = 1; + BOOL s_bBeginScene = FALSE; + D3DFORMAT g_RenderFormat = D3DFMT_A16B16G16R16F; + int icurctx = -1; + + LPD3DVB pvbRect = NULL; + + DXVEC4 g_vdepth = DXVEC4(65536.0f, 256.0f, 1.0f, 65536.0f*256.0f); + + LPD3DVS pvsBitBlt = NULL, pvsBitBlt30 = NULL; + LPD3DPS ppsBitBlt[2] = {NULL}, ppsBitBltDepth[2] = {NULL}, ppsBitBltDepthTex[2] = {NULL}, ppsOne = NULL; + LPD3DPS ppsBaseTexture = NULL, ppsConvert16to32 = NULL, ppsConvert32to16 = NULL; + + extern CRangeManager s_RangeMngr; // manages overwritten memory + void FlushTransferRanges(const tex0Info* ptex); + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + HRESULT LoadEffects(); + HRESULT LoadExtraEffects(); + LPD3DPS LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context); + + static int s_nNewWidth = -1, s_nNewHeight = -1; + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + + void ProcessMessages(); + void RenderCustom(float fAlpha); // intro anim + + struct MESSAGE + { + MESSAGE() {} + MESSAGE(const char* p, DWORD dw) { strcpy(str, p); dwTimeStamp = dw; } + char str[255]; + DWORD dwTimeStamp; + }; + + static list listMsgs; + + /////////////////////// + // Method Prototypes // + /////////////////////// + + void AdjustTransToAspect(DXVEC4& v, int dispwidth, int dispheight); + + void KickPoint(); + void KickLine(); + void KickTriangle(); + void KickTriangleFan(); + void KickSprite(); + void KickDummy(); + + inline void SetContextTarget(int context); + + // use to update the d3d state + void SetTexVariables(int context); + void SetAlphaVariables(const alphaInfo& ainfo); + void ResetAlphaVariables(); + + __forceinline void SetAlphaTestInt(pixTest curtest); + + __forceinline void RenderAlphaTest(const VB& curvb); + __forceinline void RenderStencil(const VB& curvb, DWORD dwUsingSpecialTesting); + __forceinline void ProcessStencil(const VB& curvb); + __forceinline void RenderFBA(const VB& curvb); + __forceinline void ProcessFBA(const VB& curvb); + + void ResolveInRange(int start, int end); + + void ExtWrite(); + + inline LPD3DTEX CreateInterlaceTex(int width) { + if( width == s_nInterlaceTexWidth && s_ptexInterlace != NULL ) return s_ptexInterlace; + + SAFE_RELEASE(s_ptexInterlace); + s_nInterlaceTexWidth = width; + + HRESULT hr; + V(pd3dDevice->CreateTexture(width, 1, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &s_ptexInterlace, NULL)); + + D3DLOCKED_RECT lock; + s_ptexInterlace->LockRect(0, &lock, NULL, 0); + for(int i = 0; i < width; ++i) ((u32*)lock.pBits)[i] = (i&1) ? 0xffffffff : 0; + s_ptexInterlace->UnlockRect(0); + + return s_ptexInterlace; + } + + DrawFn drawfn[8] = { KickDummy, KickDummy, KickDummy, KickDummy, + KickDummy, KickDummy, KickDummy, KickDummy }; + +}; // end namespace + +/////////////////// +// Context State // +/////////////////// +ZeroGS::VB::VB() +{ + memset(this, 0, sizeof(VB)); + tex0.tw = 1; + tex0.th = 1; +} + +ZeroGS::VB::~VB() +{ + Destroy(); +} + +void ZeroGS::VB::Destroy() +{ + Unlock(); + SAFE_RELEASE(pvb); + + prndr = NULL; + pdepth = NULL; +} + +void ZeroGS::VB::Lock() +{ + assert(pvb != NULL); + if( pbuf == NULL ) + { + if( dwCurOff+POINT_BUFFERFLUSH > POINT_BUFFERSIZE ) dwCurOff = 0; + + pvb->Lock(dwCurOff*sizeof(VertexGPU), sizeof(VertexGPU)*POINT_BUFFERFLUSH, (void**)&pbuf, dwCurOff ? D3DLOCK_NOOVERWRITE|D3DLOCK_NOSYSLOCK : D3DLOCK_DISCARD|D3DLOCK_NOSYSLOCK); + dwCount = 0; + assert( pbuf != NULL ); + } +} + +bool ZeroGS::VB::CheckPrim() +{ + Lock(); + + if( (PRIMMASK & prim->_val) != (PRIMMASK & curprim._val) || primtype[prim->prim] != primtype[curprim.prim] ) + return dwCount > 0; + + return false; +} + +// upper bound on max possible height +#define GET_MAXHEIGHT(fbp, fbw, psm) ((((0x00100000-64*(fbp))/(fbw))&~0x1f)<<((psm&2)?1:0)) + +#include +static int maxmin = 608; +//static set s_setFBP[2]; // previous frame/zbuf pointers for the last 2 frames +//static int s_nCurFBPSet = 0; +//static map s_mapFrameHeights[2]; +//static int s_nCurFrameMap = 0; + +// a lot of times, target is too big and overwrites the texture using, if tbp != 0, use it to bound +void ZeroGS::VB::CheckFrame(int tbp) +{ + static int bChanged; + + if( bNeedZCheck ) { + PRIM_LOG("zbuf_%d: zbp=0x%x psm=0x%x, zmsk=%d\n", ictx, zbuf.zbp, zbuf.psm, zbuf.zmsk); + //zbuf = *zb; + } + + // invalid bpp + if( m_Blocks[gsfb.psm].bpp == 0 ) { + ERROR_LOG("CheckFrame invalid bpp %d\n", gsfb.psm); + return; + } + + bChanged = 0; + + if( gsfb.fbw <= 0 ) { + return; + } + + if( bNeedFrameCheck ) { + + int maxpos = 0x00100000; + + // important to set before calling GetTarg + bNeedFrameCheck = 0; + bNeedZCheck = 0; + + // add constraints of other targets + if( gsfb.fbw > 0 ) { + maxpos = 0x00100000-64*gsfb.fbp; + + // make sure texture is far away from tbp + if( gsfb.fbp < tbp && gsfb.fbp + 0x2000 < tbp) { + maxpos = min(64*(tbp-gsfb.fbp), maxpos); + } + if( prndr != NULL ) { + // offroad uses 0x80 fbp which messes up targets + if( gsfb.fbp + 0x80 < frame.fbp ) { + // special case when double buffering (hamsterball) + maxpos = min(64*(frame.fbp-gsfb.fbp), maxpos); + } + } + if( zbuf.zbp < tbp && !zbuf.zmsk ) { + maxpos = min((tbp-zbuf.zbp)*((zbuf.psm&2)?128:64), maxpos); + } + + // old caching method + if( gsfb.fbp < zbuf.zbp && !zbuf.zmsk ) { // zmsk necessary for KH movie + int temp = 64*(zbuf.zbp-gsfb.fbp);//min( (0x00100000-64*zbuf.zbp) , 64*(zbuf.zbp-gsfb.fbp) ); + maxpos = min(temp, maxpos); + } + + maxpos /= gsfb.fbw; + if( gsfb.psm & 2 ) + maxpos *= 2; + + maxpos = min(gsfb.fbh, maxpos); + maxpos = min(maxmin, maxpos); + //? atelier iris crashes without it + if( maxpos > 256 ) + maxpos &= ~0x1f; + } + else { + ERROR_LOG("render target null, ignoring\n"); + //prndr = NULL; + //pdepth = NULL; + return; + } + + gsfb.psm &= 0xf; // shadow tower + + if( prndr != NULL ) { + + // render target + if( prndr->psm != gsfb.psm ) { + // behavior for dest alpha varies + ResetAlphaVariables(); + } + } + + int fbh = (scissor.y1>>MINMAX_SHIFT)+1; + if( fbh > 2 && (fbh&1) ) fbh -= 1; + + if( !(gsfb.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + fbh = min(fbh, maxpos); + } + + frame = gsfb; + if (frame.fbw > 1024) frame.fbw = 1024; + +// if( fbh > 256 && (fbh % m_Blocks[gsfb.psm].height) <= 2 ) { +// // dragon ball z +// fbh -= fbh%m_Blocks[gsfb.psm].height; +// } + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) + frame.fbh = fbh; + + if( !(frame.psm&2) ) {//|| !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbh >= 512 ) { + // neopets hack + maxmin = min(maxmin, frame.fbh); + frame.fbh = maxmin; + } + } + + // mgs3 hack to get proper resolution, targets after 0x2000 are usually feedback + if( g_MaxRenderedHeight >= 0xe0 && frame.fbp >= 0x2000 ) { + int considerheight = (g_MaxRenderedHeight/8+31)&~31; + if( frame.fbh > considerheight ) + frame.fbh = considerheight; + else if( frame.fbh <= 32 ) + frame.fbh = considerheight; + + if( frame.fbh == considerheight ) { + // stops bad resolves (mgs3) + if( !curprim.abe && (!test.ate || test.atst == 0) ) + s_nResolved |= 0x100; + } + } + + // ffxii hack to stop resolving + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbp >= 0x3000 && fbh >= 0x1a0 ) { + int endfbp = frame.fbp + frame.fbw*fbh/((gsfb.psm&2)?128:64); + + // see if there is a previous render target in the way, reduce + for(CRenderTargetMngr::MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) { + if( itnew->second->fbp > frame.fbp && endfbp > itnew->second->fbp ) { + endfbp = itnew->second->fbp; + } + } + + frame.fbh = (endfbp-frame.fbp)*((gsfb.psm&2)?128:64)/frame.fbw; + } + } + + CRenderTarget* pprevrndr = prndr; + CDepthTarget* pprevdepth = pdepth; + + // reset so that Resolve doesn't call Flush + prndr = NULL; + pdepth = NULL; + + CRenderTarget* pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + + // pnewtarg->fbh >= 0x1c0 needed for ffx + if( pnewtarg->fbh >= 0x1c0 && pnewtarg->fbh > frame.fbh && zbuf.zbp < tbp && !zbuf.zmsk ) { + // check if zbuf is in the way of the texture (suikoden5) + int maxallowedfbh = (tbp-zbuf.zbp)*((zbuf.psm&2)?128:64) / gsfb.fbw; + if( gsfb.psm & 2 ) + maxallowedfbh *= 2; + + if( pnewtarg->fbh > maxallowedfbh+32 ) { // +32 needed for ffx2 + // destroy and recreate + s_RTs.DestroyAll(0, 0x100, pnewtarg->fbw); + pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + } + } + + PRIM_LOG("frame_%d: fbp=0x%x fbw=%d fbh=%d(%d) psm=0x%x fbm=0x%x\n", ictx, gsfb.fbp, gsfb.fbw, gsfb.fbh, pnewtarg->fbh, gsfb.psm, gsfb.fbm); + + if( (pprevrndr != pnewtarg) || (prndr != NULL && (prndr->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 1; + + prndr = pnewtarg; + + // update z + frameInfo tempfb; + tempfb.fbw = prndr->fbw; + tempfb.fbp = zbuf.zbp; + tempfb.psm = zbuf.psm; + tempfb.fbh = prndr->targheight; + if( zbuf.psm == 0x31 ) tempfb.fbm = 0xff000000; + else tempfb.fbm = 0; + + // check if there is a target that exactly aligns with zbuf (zbuf can be cleared this way, gunbird 2) + //u32 key = zbuf.zbp|(frame.fbw<<16); + //CRenderTargetMngr::MAPTARGETS::iterator it = s_RTs.mapTargets.find(key); +// if( it != s_RTs.mapTargets.end() ) { +//#ifdef _DEBUG +// DEBUG_LOG("zbuf resolve\n"); +//#endif +// if( it->second->status & CRenderTarget::TS_Resolved ) +// it->second->Resolve(); +// } + + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(tempfb, CRenderTargetMngr::TO_DepthBuffer | + CRenderTargetMngr::TO_StrictHeight|(zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), + prndr->targheight);//GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->targheight ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged |= 2; + + pdepth = pnewdepth; + + if( prndr->status & CRenderTarget::TS_NeedConvert32) { + if( pdepth->pdepth != NULL ) + pd3dDevice->SetDepthStencilSurface(pdepth->pdepth); + prndr->fbh *= 2; + prndr->targheight *= 2; + prndr->ConvertTo32(); + prndr->status &= ~CRenderTarget::TS_NeedConvert32; + } + else if( prndr->status & CRenderTarget::TS_NeedConvert16 ) { + if( pdepth->pdepth != NULL ) + pd3dDevice->SetDepthStencilSurface(pdepth->pdepth); + prndr->fbh /= 2; + prndr->targheight /= 2; + prndr->ConvertTo16(); + prndr->status &= ~CRenderTarget::TS_NeedConvert16; + } + } + else if( bNeedZCheck ) { + + bNeedZCheck = 0; + CDepthTarget* pprevdepth = pdepth; + pdepth = NULL; + + if( prndr != NULL && gsfb.fbw > 0 ) { + // just z changed + frameInfo f; + f.fbp = zbuf.zbp; + f.fbw = prndr->fbw; + f.fbh = prndr->fbh; + f.psm = zbuf.psm; + + if( zbuf.psm == 0x31 ) f.fbm = 0xff000000; + else f.fbm = 0; + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), prndr->fbh);//GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->fbh ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 2; + + pdepth = pnewdepth; + } + } + + s_nResolved &= 0xff; // restore + + if( prndr != NULL ) + SetContextTarget(ictx); + + //if( prndr != NULL && ictx == icurctx) + //else bVarsSetTarg = 0; + +// if( prndr != NULL && bChanged ) { +// if( ictx == icurctx ) SetContextTarget(icurctx); +// else +// bVarsSetTarg = 0; +// } +} + +void ZeroGS::VB::FlushTexData() +{ + assert( bNeedTexCheck ); + + bNeedTexCheck = 0; + + u32 psm = (uNextTex0Data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + // don't update unless necessary + if( uCurTex0Data[0] == uNextTex0Data[0] && (uCurTex0Data[1]&0x1f) == (uNextTex0Data[1]&0x1f) ) { + + if( PSMT_ISCLUT(psm) ) { + + // have to write the CLUT again if changed + if( (uCurTex0Data[1]&0x1fffffe0) == (uNextTex0Data[1]&0x1fffffe0) ) { + + if( uNextTex0Data[1]&0xe0000000 ) { + //ZeroGS::Flush(ictx); + ZeroGS::texClutWrite(ictx); + // invalidate to make sure target didn't change! + bVarsTexSync = FALSE; + } + + return; + } + + if( (uNextTex0Data[1]&0xe0000000) == 0 ) { + + if( (uCurTex0Data[1]&0x1ff10000) != (uNextTex0Data[1]&0x1ff10000) ) + ZeroGS::Flush(ictx); + + // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! + uCurTex0Data[1] = (uCurTex0Data[1]&0xe087ffff)|(uNextTex0Data[1]&0x1f780000); + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + ZeroGS::texClutWrite(ictx); + + bVarsTexSync = FALSE; + return; + } + + // fall through + } + else { + //bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(ictx); + bVarsTexSync = FALSE; + bTexConstsSync = FALSE; + + uCurTex0Data[0] = uNextTex0Data[0]; + uCurTex0Data[1] = uNextTex0Data[1]; + + tex0.tbp0 = (uNextTex0Data[0] & 0x3fff); + tex0.tbw = ((uNextTex0Data[0] >> 14) & 0x3f) * 64; + tex0.psm = psm; + tex0.tw = (uNextTex0Data[0] >> 26) & 0xf; + if (tex0.tw > 10) tex0.tw = 10; + tex0.tw = 1<> 30) & 0x3) | ((uNextTex0Data[1] & 0x3) << 2); + if (tex0.th > 10) tex0.th = 10; + tex0.th = 1<> 2) & 0x1; + tex0.tfx = (uNextTex0Data[1] >> 3) & 0x3; + + ZeroGS::fiTexWidth[ictx] = (1/16.0f)/ tex0.tw; + ZeroGS::fiTexHeight[ictx] = (1/16.0f) / tex0.th; + + if (tex0.tbw == 0) tex0.tbw = 64; + + if( PSMT_ISCLUT(psm) ) { + tex0.cbp = ((uNextTex0Data[1] >> 5) & 0x3fff); + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + tex0.csm = (uNextTex0Data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cld = (uNextTex0Data[1] >> 29) & 0x7; + + ZeroGS::texClutWrite(ictx); + } +} + +// does one time only initializing/destruction +class ZeroGSInit +{ +public: + ZeroGSInit() { + // clear + g_pbyGSMemory = (u8*)_aligned_malloc(0x00410000, 1024); // leave some room for out of range accesses (saves on the checks) + memset(g_pbyGSMemory, 0, 0x00410000); + + g_pbyGSClut = (u8*)_aligned_malloc(256*8, 1024); // need 512 alignment! + memset(g_pbyGSClut, 0, 256*8); + } + ~ZeroGSInit() { + _aligned_free(g_pbyGSMemory); g_pbyGSMemory = NULL; + _aligned_free(g_pbyGSClut); g_pbyGSClut = NULL; + } +}; + +static ZeroGSInit s_ZeroGSInit; + +HRESULT ZeroGS::Create(LONG _width, LONG _height) +{ + Destroy(1); + GSStateReset(); + + width = _width; + height = _height; + fiRendWidth = 1.0f / width; + fiRendHeight = 1.0f / height; + + HRESULT hr; + + if( NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION)) ) { + ERROR_LOG(_T("Failed to create the direct3d interface.")); + return E_FAIL; + } + + D3DDISPLAYMODE d3ddm; + if( FAILED( hr = pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) ) { + ERROR_LOG(_T("Error geting default adapter.")); + return hr; + } + + if( conf.options & GSOPTION_FULLSCREEN ) { + // choose best mode +// RECT rcdesktop; +// GetWindowRect(GetDesktopWindow(), &rcdesktop); +// width = rcdesktop.right - rcdesktop.left; +// height = rcdesktop.bottom - rcdesktop.top; + +// width = height = 0; +// D3DDISPLAYMODE d3ddmtemp; +// +// int modes = pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT, d3ddm.Format); +// for(int i= 0; i < modes; ++i) { +// pD3D->EnumAdapterModes(D3DADAPTER_DEFAULT, d3ddm.Format, i, &d3ddmtemp); +// +// if( abs(1024-(int)d3ddmtemp.Width) <= abs(1280-width) && abs(768-(int)d3ddmtemp.Height) <= abs(1024-height) ) { +// width = d3ddmtemp.Width; +// height = d3ddmtemp.Height; +// } +// } + } + else { + // change to default resolution + ChangeDisplaySettings(NULL, 0); + } + + // Set up the structure used to create the D3DDevice. Since we are now + // using more complex geometry, we will create a device with a zbuffer. + ZeroMemory( &d3dpp, sizeof(d3dpp) ); + d3dpp.Windowed = !(conf.options & GSOPTION_FULLSCREEN); + d3dpp.hDeviceWindow = GShwnd; + d3dpp.SwapEffect = (conf.options & GSOPTION_FULLSCREEN) ? D3DSWAPEFFECT_FLIP : D3DSWAPEFFECT_DISCARD; + d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; + d3dpp.BackBufferWidth = width; + d3dpp.BackBufferHeight = height; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//(conf.options & GSOPTION_FULLSCREEN) ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Flags = DEBUG_PS2 ? D3DPRESENTFLAG_LOCKABLE_BACKBUFFER : 0; + + s_nFullscreen = (conf.options & GSOPTION_FULLSCREEN) ? 1 : 0; + + // Create the D3DDevice + UINT adapter = D3DADAPTER_DEFAULT; + D3DDEVTYPE devtype = !DEBUG_PS2 ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF; + +#ifndef _DEBUG + DWORD hwoptions = D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_PUREDEVICE; +#else + DWORD hwoptions = D3DCREATE_HARDWARE_VERTEXPROCESSING; +#endif + +#ifndef RELEASE_TO_PUBLIC + for(UINT i = 0; i < pD3D->GetAdapterCount(); ++i) { + D3DADAPTER_IDENTIFIER9 id; + HRESULT hr = pD3D->GetAdapterIdentifier(i, 0, &id); + if( strcmp(id.Description, "NVIDIA NVPerfHUD") == 0 ) { + DEBUG_LOG("Using %s adapter\n", id.Description); + adapter = i; + devtype = D3DDEVTYPE_REF; + break; + } + } +#endif + + if( FAILED( hr = pD3D->CreateDevice( adapter, devtype, GShwnd, + !DEBUG_PS2 ? hwoptions : D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice ) ) ) + { + ERROR_LOG(_T("Failed to create hardware device, creating software.\n")); + + if( FAILED( hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GShwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3dpp, &pd3dDevice ) ) ) + { + ERROR_LOG(_T("Failed to create software device, switching to reference rasterizer.\n")); + + if( FAILED( hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, GShwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3dpp, &pd3dDevice ) ) ) + return hr; + } + } + + // get caps and check if gfx card is ok + D3DCAPS9 caps; + pd3dDevice->GetDeviceCaps(&caps); + + if( caps.VertexShaderVersion < D3DVS_VERSION(2,0) ) { + ERROR_LOG("*********\nGS ERROR: Need at least vs2.0\n*********\n"); + Destroy(1); + return E_FAIL; + } + + conf.mrtdepth = 1; + + if( caps.NumSimultaneousRTs == 1 ) { + ERROR_LOG("*********\nGS WARNING: Need at least 2 simultaneous render targets. Some zbuffer effects will look wrong\n*********\n"); + conf.mrtdepth = 0; + } + if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) ) { + ERROR_LOG("*********\nGS ERROR: Need separate alpha blending! Some effects will look bad\n*********\n"); + } + if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_INDEPENDENTWRITEMASKS) ) { + ERROR_LOG("******\nGS WARNING: Need independent write masks! Some z buffer effects might look bad\n*********\n"); + bIndepWriteMasks = 0; + } + + if( !(caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING) ) { + ERROR_LOG("******\nGS WARNING: Need MRT Post Pixel Shader Blending for some effects\n*********\n"); + } + + hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, + D3DUSAGE_RENDERTARGET|D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, g_RenderFormat); + + if( g_GameSettings & GAME_32BITTARGS ) { + g_RenderFormat = D3DFMT_A8R8G8B8; + ERROR_LOG("Setting 32 bit render target\n"); + } + else if( FAILED(hr) ) { + ERROR_LOG("******\nGS ERROR: Device doesn't support alpha blending for 16bit floating point targets.\nQuality will reduce.\n*********\n"); + g_RenderFormat = D3DFMT_A8R8G8B8; + } + +// hr = pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_G32R32F); +// +// if( FAILED(hr) ) { +// ERROR_LOG("******\nGS ERROR: Device doesn't support G32R32F textures.\nTextures will look bad.\n*********\n"); +// } + + g_MaxTexWidth = caps.MaxTextureWidth; + g_MaxTexHeight = caps.MaxTextureHeight; + GPU_TEXWIDTH = caps.MaxTextureWidth/8; + g_fiGPU_TEXWIDTH = 1.0f / GPU_TEXWIDTH; + + //g_RenderFormat = D3DFMT_A8R8G8B8; + + pd3dDevice->GetRenderTarget(0, &psurfOrgTarg); + pd3dDevice->GetDepthStencilSurface(&psurfOrgDepth); + + SETRS(D3DRS_ZENABLE, TRUE); + SETRS(D3DRS_LIGHTING, FALSE); + SETRS(D3DRS_SPECULARENABLE, FALSE); + + V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, + "Arial", &pFont ) ); + + // create the vertex decl + const D3DVERTEXELEMENT9 Decl[] = { + { 0, 0, D3DDECLTYPE_SHORT4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + { 0, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, + { 0, 12, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, 16, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 }, + D3DDECL_END() }; + V_RETURN(pd3dDevice->CreateVertexDeclaration(Decl, &pdecl)); + +#ifdef RELEASE_TO_PUBLIC + HRSRC hShaderSrc = FindResource(hInst, MAKEINTRESOURCE(IDR_SHADERS), RT_RCDATA); + assert( hShaderSrc != NULL ); + HGLOBAL hShaderGlob = LoadResource(hInst, hShaderSrc); + assert( hShaderGlob != NULL ); + s_lpShaderResources = (BYTE*)LockResource(hShaderGlob); +#endif + + // load the effect + ERROR_LOG("Creating effects\n"); + V_RETURN(LoadEffects()); + + g_bDisplayMsg = 0; + if( caps.VertexShaderVersion >= D3DVS_VERSION(3,0) && caps.PixelShaderVersion >= D3DPS_VERSION(2,0) ) + g_nPixelShaderVer = SHADER_30; + else if( caps.PixelShaderVersion == D3DPS_VERSION(2,0) ) + g_nPixelShaderVer = SHADER_20; + else + g_nPixelShaderVer = SHADER_20a; + +#ifdef RELEASE_TO_PUBLIC + // create a sample shader + clampInfo temp; + memset(&temp, 0, sizeof(temp)); + temp.wms = 3; temp.wmt = 3; + + if( g_nPixelShaderVer != SHADER_30 ) { + // test more + if( LoadShadeEffect(0, 1, 1, 1, 1, temp, 0) == NULL ) { + g_nPixelShaderVer = SHADER_20b; + if( LoadShadeEffect(0, 1, 1, 1, 1, temp, 0) == NULL ) { + + g_nPixelShaderVer = SHADER_20; + if( LoadShadeEffect(0, 0, 1, 1, 0, temp, 0) == NULL ) { + + ERROR_LOG("*********\nGS ERROR: Need at least ps2.0 (ps2.0a+ recommended)\n*********\n"); + Destroy(1); + return E_FAIL; + } + } + } + } +#endif + + // set global shader constants + pd3dDevice->SetPixelShaderConstantF(27, DXVEC4(0.5f, (g_GameSettings&GAME_EXACTCOLOR)?0.9f/256.0f:0.5f/256.0f, 0,1/255.0f), 1); // g_fExactColor + pd3dDevice->SetPixelShaderConstantF(28, DXVEC4(-0.7f, -0.65f, 0.9f,0), 1); // g_fBilinear + pd3dDevice->SetPixelShaderConstantF(29, DXVEC4(1.0f/256.0f, 1.0004f, 1, 0.5f), 1); // g_fZBias + pd3dDevice->SetPixelShaderConstantF(30, DXVEC4(0,1, 0.001f, 0.5f), 1); // g_fc0 + pd3dDevice->SetPixelShaderConstantF(31, DXVEC4(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f), 1); // g_fMult + + pd3dDevice->SetVertexShaderConstantF(29, DXVEC4(1.0f/256.0f, 1.0004f, 1, 0.5f), 1); // g_fZBias + pd3dDevice->SetVertexShaderConstantF(30, DXVEC4(0,1, 0.001f, 0.5f), 1); // g_fc0 + pd3dDevice->SetVertexShaderConstantF(31, DXVEC4(0.5f, -0.5f, 0.5f, 0.5f + 0.4f/416.0f), 1); // g_fBitBltTrans + + g_bDisplayMsg = 1; + if( g_nPixelShaderVer == SHADER_20 ) + conf.bilinear = 0; + + ERROR_LOG("Creating extra effects\n"); + V_RETURN(LoadExtraEffects()); + + ERROR_LOG("GS Using pixel shaders %s\n", g_pShaders[g_nPixelShaderVer]); + + pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER, 0, 1, 0); + + // init draw fns + drawfn[0] = KickPoint; + drawfn[1] = KickLine; + drawfn[2] = KickLine; + drawfn[3] = KickTriangle; + drawfn[4] = KickTriangle; + drawfn[5] = KickTriangleFan; + drawfn[6] = KickSprite; + drawfn[7] = KickDummy; + + SetAA(conf.aa); + GSsetGameCRC(g_LastCRC, g_GameSettings); + + return S_OK; +} + +void ZeroGS::Destroy(BOOL bD3D) +{ + DeleteDeviceObjects(); + + vb[0].Destroy(); + vb[1].Destroy(); + + for(int i = 0; i < ARRAYSIZE(pvs); ++i) { + SAFE_RELEASE(pvs[i]); + } + for(int i = 0; i < ARRAYSIZE(ppsRegular); ++i) { + SAFE_RELEASE(ppsRegular[i]); + } + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + + SAFE_RELEASE(pvsBitBlt); + SAFE_RELEASE(pvsBitBlt30); + SAFE_RELEASE(ppsBitBlt[0]); SAFE_RELEASE(ppsBitBlt[1]); + SAFE_RELEASE(ppsBitBltDepth[0]); SAFE_RELEASE(ppsBitBltDepth[1]); + SAFE_RELEASE(ppsBitBltDepthTex[0]); SAFE_RELEASE(ppsBitBltDepthTex[1]); + SAFE_RELEASE(ppsCRTCTarg[0]); SAFE_RELEASE(ppsCRTCTarg[1]); + SAFE_RELEASE(ppsCRTC[0]); SAFE_RELEASE(ppsCRTC[1]); + SAFE_RELEASE(ppsCRTC24[0]); SAFE_RELEASE(ppsCRTC24[1]); + SAFE_RELEASE(ppsOne); + + SAFE_RELEASE(pdecl); + SAFE_RELEASE(pFont); + SAFE_RELEASE(psurfOrgTarg); + SAFE_RELEASE(psurfOrgDepth); + + if( bD3D ) { + SAFE_RELEASE(pd3dDevice); + SAFE_RELEASE(pD3D); + } +} + +void ZeroGS::GSStateReset() +{ + icurctx = -1; + + for(int i = 0; i < 2; ++i) { + LPD3DVB pvb = vb[i].pvb; + if( pvb != NULL ) pvb->AddRef(); + vb[i].Destroy(); + memset(&vb[i], 0, sizeof(VB)); + + vb[i].tex0.tw = 1; + vb[i].tex0.th = 1; + vb[i].pvb = pvb; + vb[i].scissor.x1 = 639; + vb[i].scissor.y1 = 479; + vb[i].tex0.tbw = 64; + } + + s_RangeMngr.Clear(); + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + vb[0].ictx = 0; + vb[1].ictx = 1; + s_bAlphaSet = FALSE; +} + +void ZeroGS::AddMessage(const char* pstr, DWORD ms) +{ + listMsgs.push_back(MESSAGE(pstr, timeGetTime()+ms)); +} + +void ZeroGS::ChangeWindowSize(int nNewWidth, int nNewHeight) +{ + width = nNewWidth > 16 ? nNewWidth : 16; + height = nNewHeight > 16 ? nNewHeight : 16; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::SetChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + s_nNewWidth = nNewWidth; + s_nNewHeight = nNewHeight; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::Reset() +{ + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + vb[0].Unlock(); + vb[1].Unlock(); + + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + icurctx = -1; + + GSStateReset(); + Destroy(0); + + drawfn[0] = KickDummy; + drawfn[1] = KickDummy; + drawfn[2] = KickDummy; + drawfn[3] = KickDummy; + drawfn[4] = KickDummy; + drawfn[5] = KickDummy; + drawfn[6] = KickDummy; + drawfn[7] = KickDummy; +} + +void ZeroGS::ChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + int oldscreen = s_nFullscreen; + + int oldwidth = width, oldheight = height; + if( FAILED(Create(nNewWidth&~7, nNewHeight&~7)) ) { + DEBUG_LOG("Failed to recreate, changing to old\n"); + if( FAILED(Create(oldwidth, oldheight)) ) { + MessageBox(NULL, "failed to create dev, exiting...\n", "Error", MB_OK); + exit(0); + } + } + + if( FAILED(InitDeviceObjects()) ) { + MessageBox(NULL, "failed to init dev objs, exiting...\n", "Error", MB_OK); + exit(0); + } + + for(int i = 0; i < 2; ++i) { + vb[i].bNeedFrameCheck = vb[i].bNeedZCheck = 1; + vb[i].CheckFrame(0); + } + + if( oldscreen && !(conf.options & GSOPTION_FULLSCREEN) ) { // if transitioning from full screen + RECT rc; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + AdjustWindowRect(&rc, conf.winstyle, FALSE); + + RECT rcdesktop; + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + SetWindowLong( GShwnd, GWL_STYLE, conf.winstyle ); + SetWindowPos(GShwnd, HWND_TOP, ((rcdesktop.right-rcdesktop.left)-(rc.right-rc.left))/2, + ((rcdesktop.bottom-rcdesktop.top)-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW); + UpdateWindow(GShwnd); + } + + vb[0].Lock(); + vb[1].Lock(); + + assert( vb[0].pbuf != NULL && vb[1].pbuf != NULL ); +} + +void ZeroGS::SetAA(int mode) +{ + float f; + + // need to flush all targets + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + s_AAx = s_AAy = 0; + if( mode > 0 ) + { + s_AAx = (mode+1) / 2; + s_AAy = mode / 2; + } + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + + f = mode > 0 ? 2.0f : 1.0f; + SETRS(D3DRS_POINTSIZE, FtoDW(f)); +} + +#ifdef RELEASE_TO_PUBLIC + +#define LOAD_VS(Index, ptr) { \ + assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ + header = mapShaderResources[Index]; \ + assert( (header) != NULL && (header)->index == (Index) ); \ + hr = pd3dDevice->CreateVertexShader((DWORD*)(s_lpShaderResources + (header)->offset), &(ptr)); \ + if( FAILED(hr) || ptr == NULL ) { \ + DEBUG_LOG("errors 0x%x for %d, failed.. try updating your drivers or dx\n", hr, Index); \ + return E_FAIL; \ + } \ +} \ + +#define LOAD_PS(index, ptr) { \ + assert( mapShaderResources.find(index) != mapShaderResources.end() ); \ + header = mapShaderResources[index]; \ + hr = pd3dDevice->CreatePixelShader((DWORD*)(s_lpShaderResources + (header)->offset), &(ptr)); \ + if( FAILED(hr) || ptr == NULL ) { \ + DEBUG_LOG("errors 0x%x for %s, failed.. try updating your drivers or dx\n", hr, index); \ + return E_FAIL; \ + } \ +} \ + +HRESULT ZeroGS::LoadEffects() +{ + assert( s_lpShaderResources != NULL ); + + // process the header + DWORD num = *(DWORD*)s_lpShaderResources; + SHADERHEADER* header = (SHADERHEADER*)((BYTE*)s_lpShaderResources + 4); + + mapShaderResources.clear(); + while(num-- > 0 ) { + mapShaderResources[header->index] = header; + ++header; + } + + // clear the textures + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + + return S_OK; +} + +// called +HRESULT ZeroGS::LoadExtraEffects() +{ + HRESULT hr; + + SHADERHEADER* header; + + DWORD mask = g_nPixelShaderVer == SHADER_30 ? SH_30 : 0; + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + for(int i = 0; i < 4; ++i) { + LOAD_VS(vsshaders[i]|mask, pvs[2*i]); + LOAD_VS(vsshaders[i]|mask|SH_CONTEXT1, pvs[2*i+1]); + LOAD_VS(vsshaders[i]|mask|SH_WRITEDEPTH, pvs[2*i+8]); + LOAD_VS(vsshaders[i]|mask|SH_WRITEDEPTH|SH_CONTEXT1, pvs[2*i+8+1]); + } + + LOAD_VS(SH_BITBLTVS, pvsBitBlt); + //LOAD_VS(SH_BITBLTVS|SH_30, pvsBitBlt30); + + LOAD_PS(SH_REGULARPS|mask, ppsRegular[0]); + LOAD_PS(SH_REGULARFOGPS|mask, ppsRegular[1]); + LOAD_PS(SH_REGULARPS|SH_WRITEDEPTH|mask, ppsRegular[2]); + LOAD_PS(SH_REGULARFOGPS|SH_WRITEDEPTH|mask, ppsRegular[3]); + + LOAD_PS(SH_BITBLTPS, ppsBitBlt[0]); LOAD_PS(SH_BITBLTAAPS, ppsBitBlt[0]); + LOAD_PS(SH_BITBLTDEPTHPS, ppsBitBltDepth[0]); LOAD_PS(SH_BITBLTDEPTHMRTPS, ppsBitBltDepth[1]); + LOAD_PS(SH_BITBLTDEPTHTEXPS, ppsBitBltDepthTex[0]); LOAD_PS(SH_BITBLTDEPTHTEXMRTPS, ppsBitBltDepthTex[1]); + LOAD_PS(SH_CRTCTARGPS, ppsCRTCTarg[0]); LOAD_PS(SH_CRTCTARGINTERPS, ppsCRTCTarg[1]); + LOAD_PS(SH_CRTCPS, ppsCRTC[0]); LOAD_PS(SH_CRTCINTERPS, ppsCRTC[1]); + LOAD_PS(SH_CRTC24PS, ppsCRTC24[0]); LOAD_PS(SH_CRTC24INTERPS, ppsCRTC24[1]); + LOAD_PS(SH_ZEROPS|mask, ppsOne); + LOAD_PS(SH_BASETEXTUREPS, ppsBaseTexture); + LOAD_PS(SH_CONVERT16TO32PS, ppsConvert16to32); + LOAD_PS(SH_CONVERT32TO16PS, ppsConvert32to16); + + return S_OK; +} + +LPD3DPS ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context) +{ + int texwrap; + assert( texfilter < NUM_FILTERS ); + + if(g_nPixelShaderVer == SHADER_20 ) + texfilter = 0; + if(g_nPixelShaderVer == SHADER_20 ) + exactcolor = 0; + + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + assert( index < ARRAYSIZE(ppsTexture) ); + LPD3DPS* pps = ppsTexture+index; + + if( *pps != NULL ) + return *pps; + + index += NUM_SHADERS*g_nPixelShaderVer; + assert( mapShaderResources.find(index) != mapShaderResources.end() ); + SHADERHEADER* header = mapShaderResources[index]; + if( header == NULL ) DEBUG_LOG("%d %d\n", index%NUM_SHADERS, g_nPixelShaderVer); + assert( header != NULL ); + HRESULT hr = pd3dDevice->CreatePixelShader((DWORD*)(s_lpShaderResources + header->offset), pps); + + if( SUCCEEDED(hr) ) + return *pps; + + if( g_bDisplayMsg ) + ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", 3, fog, texfilter, 4*clamp.wms+clamp.wmt); + + return NULL; +} + +#else // not RELEASE_TO_PUBLIC + +//#define EFFECT_NAME "f:\\ps2dev\\pcsx2\\zerogs\\dx\\" +#define EFFECT_NAME ".\\" +#define COMPILE_SHADER(name, type, flags) + +class ZeroGSShaderInclude : public ID3DXInclude +{ +public: + int context; + STDMETHOD(Open)(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) + { + const char* pfilename = pFileName; + char strfile[255]; + if( strstr(pFileName, "ps2hw_ctx") != NULL ) { + + _snprintf(strfile, 255, "%sps2hw_ctx%d.fx", EFFECT_NAME, context); + pfilename = strfile; + } + else if( strstr(pFileName, "\\") == NULL ) { + _snprintf(strfile, 255, "%s%s", EFFECT_NAME, pFileName); + pfilename = strfile; + } + + FILE* f = fopen(pfilename, "rb"); + + if( f == NULL ) + return E_FAIL; + + fseek(f, 0, SEEK_END); + DWORD size = ftell(f); + fseek(f, 0, SEEK_SET); + char* buffer = new char[size+1]; + fread(buffer, size, 1, f); + buffer[size] = 0; + + *ppData = buffer; + *pBytes = size; + fclose(f); + + return S_OK; + } + + STDMETHOD(Close)(LPCVOID pData) + { + delete[] (char*)pData; + return S_OK; + } +}; + +#define LOAD_VS(name, ptr, shaderver) { \ + LPD3DXBUFFER pShader, pError; \ + V(D3DXCompileShaderFromFile(EFFECT_NAME"ps2hw.fx", pmacros, pInclude, name, shaderver, ShaderFlagsVS, &pShader, &pError, NULL)); \ + if( FAILED(hr) ) \ + { \ + DEBUG_LOG("Failed to load vs %s: \n%s\n", name, pError->GetBufferPointer()); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ + return hr; \ + } \ + hr = pd3dDevice->CreateVertexShader((const DWORD*)pShader->GetBufferPointer(), &(ptr)); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ +} \ + +#define LOAD_PS(name, ptr, shmodel) { \ + LPD3DXBUFFER pShader, pError; \ + SAFE_RELEASE(ptr); \ + V(D3DXCompileShaderFromFile(EFFECT_NAME"ps2hw.fx", pmacros, pInclude, name, shmodel, ShaderFlagsPS, &pShader, &pError, NULL)); \ + if( FAILED(hr) ) \ + { \ + DEBUG_LOG("Failed to load ps %s: \n%s\n", name, pError->GetBufferPointer()); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ + return hr; \ + } \ + hr = pd3dDevice->CreatePixelShader((const DWORD*)pShader->GetBufferPointer(), &(ptr)); \ + SAFE_RELEASE(pShader); \ + SAFE_RELEASE(pError); \ + if( FAILED(hr) || ptr == NULL ) { \ + DEBUG_LOG("errors 0x%x for %s, failed.. try updating your drivers or dx\n", hr, name); \ + return E_FAIL; \ + } \ +} \ + +HRESULT ZeroGS::LoadEffects() +{ + // clear the textures + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + + return S_OK; +} + +#define VS_VER (g_nPixelShaderVer == SHADER_20?"vs_2_0":"vs_3_0") +#define PS_VER (g_nPixelShaderVer == SHADER_20?"ps_2_0":"ps_3_0") + +HRESULT ZeroGS::LoadExtraEffects() +{ + HRESULT hr; + DWORD ShaderFlagsPS = !DEBUG_PS2 ? 0 : (D3DXSHADER_DEBUG|D3DXSHADER_SKIPOPTIMIZATION); + DWORD ShaderFlagsVS = !DEBUG_PS2 ? 0 : (D3DXSHADER_DEBUG|D3DXSHADER_SKIPOPTIMIZATION); + + ZeroGSShaderInclude inc; + inc.context = 0; + ZeroGSShaderInclude* pInclude = &inc; + + //assert( g_nPixelShaderVer == SHADER_30) ; + const char* pstrps = g_nPixelShaderVer == SHADER_20 ? "ps_2_0" : "ps_2_a"; + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + D3DXMACRO macros[2] = {0}; + D3DXMACRO* pmacros = NULL; + + macros[0].Name = "WRITE_DEPTH"; + macros[0].Definition = "1"; + + for(int i = 0; i < 4; ++i) { + pmacros = NULL; + inc.context = 0; + LOAD_VS(pvsshaders[i], pvs[2*i], VS_VER); + inc.context = 1; + LOAD_VS(pvsshaders[i], pvs[2*i+1], VS_VER); + + pmacros = macros; + inc.context = 0; + LOAD_VS(pvsshaders[i], pvs[2*i+8], VS_VER); + inc.context = 1; + LOAD_VS(pvsshaders[i], pvs[2*i+8+1], VS_VER); + } + + inc.context = 0; + pmacros = NULL; + LOAD_PS("RegularPS", ppsRegular[0], PS_VER); + LOAD_PS("RegularFogPS", ppsRegular[1], PS_VER); + + pmacros = macros; + LOAD_PS("RegularPS", ppsRegular[2], PS_VER); + LOAD_PS("RegularFogPS", ppsRegular[3], PS_VER); + + pmacros = NULL; + LOAD_VS("BitBltVS", pvsBitBlt, "vs_2_0"); + LOAD_PS("BitBltPS", ppsBitBlt[0], pstrps); + LOAD_PS("BitBltAAPS", ppsBitBlt[1], pstrps); + LOAD_PS("BitBltDepthPS", ppsBitBltDepth[0], pstrps); + LOAD_PS("BitBltDepthMRTPS", ppsBitBltDepth[1], pstrps); + LOAD_PS("BitBltDepthTexPS", ppsBitBltDepthTex[0], pstrps); + LOAD_PS("BitBltDepthTexMRTPS", ppsBitBltDepthTex[1], pstrps); + LOAD_PS("CRTCTargPS", ppsCRTCTarg[0], pstrps); LOAD_PS("CRTCTargInterPS", ppsCRTCTarg[1], pstrps); + LOAD_PS("CRTCPS", ppsCRTC[0], pstrps); LOAD_PS("CRTCInterPS", ppsCRTC[1], pstrps); + LOAD_PS("CRTC24PS", ppsCRTC24[0], pstrps); LOAD_PS("CRTC24InterPS", ppsCRTC24[1], pstrps); + LOAD_PS("ZeroPS", ppsOne, PS_VER); + LOAD_PS("BaseTexturePS", ppsBaseTexture, pstrps); + LOAD_PS("Convert16to32PS", ppsConvert16to32, pstrps); + LOAD_PS("Convert32to16PS", ppsConvert32to16, pstrps); + + return S_OK; +} + +LPD3DPS ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context) +{ + int texwrap; + + assert( texfilter < NUM_FILTERS ); + //assert( g_nPixelShaderVer == SHADER_30 ); + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: + texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + LPD3DPS* pps = ppsTexture+index; + + if( *pps != NULL ) + return *pps; + + ZeroGSShaderInclude inc; + inc.context = context; + + HRESULT hr = LoadShaderFromType(EFFECT_NAME"ps2hw.fx", type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, g_nPixelShaderVer, 0, pd3dDevice, &inc, pps); + + if( SUCCEEDED(hr) ) + return *pps; + + DEBUG_LOG("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + + return NULL; +} + +#endif // RELEASE_TO_PUBLIC + +HRESULT ZeroGS::InitDeviceObjects() +{ + //g_GameSettings |= 0;//GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE|GAME_FASTUPDATE; + //s_bWriteDepth = TRUE; + DeleteDeviceObjects(); + + int i; + HRESULT hr; + SETRS(D3DRS_SRCBLEND, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLEND, D3DBLEND_ONE); + + if( pFont ) V_RETURN( pFont->OnResetDevice() ); + V_RETURN( D3DXCreateSprite( pd3dDevice, &pSprite ) ); + + V(D3DXCreateTextureFromResource(pd3dDevice, hInst, MAKEINTRESOURCE( IDB_ZEROGSLOGO ), &ptexLogo)); + + for(i = 0; i < 2; ++i) + { + V_RETURN(pd3dDevice->CreateVertexBuffer( sizeof(VertexGPU) * POINT_BUFFERSIZE, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &vb[i].pvb, NULL)); + } + + // create the blocks texture + D3DFORMAT blockfmt = D3DFMT_R32F; + g_fBlockMult = 1; + + if( FAILED(hr = pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, blockfmt, D3DPOOL_MANAGED, &ptexBlocks, NULL)) ) { + blockfmt = D3DFMT_G16R16; + g_fBlockMult = 65535.0f*(float)g_fiGPU_TEXWIDTH; + V_RETURN(pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, blockfmt, D3DPOOL_MANAGED, &ptexBlocks, NULL)); + } + + if( blockfmt == D3DFMT_R32F ) { + if( FAILED(hr = pd3dDevice->CreateTexture(BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 1, 0, D3DFMT_A32B32G32R32F, D3DPOOL_MANAGED, &ptexBilinearBlocks, NULL)) ) { + DEBUG_LOG("Failed to create bilinear block texture, fmt = D3DFMT_A32B32G32R32F\n"); + } + } + else ptexBilinearBlocks = NULL; + + // fill a simple rect + V_RETURN(pd3dDevice->CreateVertexBuffer( 4 * sizeof(VertexGPU), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &pvbRect, NULL)); + VertexGPU* pvert; + + pvbRect->Lock(0, 0, (void**)&pvert, 0); + pvert->x = -0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 0; pvert++; + pvert->x = 0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 0; pvert++; + pvert->x = -0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 1; pvert++; + pvert->x = 0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 1; pvert++; + pvbRect->Unlock(); + + D3DLOCKED_RECT lock, lockbilinear; + ptexBlocks->LockRect(0, &lock, NULL, 0); + + if( ptexBilinearBlocks != NULL ) + ptexBilinearBlocks->LockRect(0, &lockbilinear, NULL, 0); + + BLOCK::FillBlocks(&lock, ptexBilinearBlocks != NULL ? &lockbilinear : NULL, blockfmt); + + ptexBlocks->UnlockRect(0); + if( ptexBilinearBlocks != NULL ) + ptexBilinearBlocks->UnlockRect(0); + + // create the conversion textures + V_RETURN(pd3dDevice->CreateTexture(256, 256, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexConv16to32, NULL)); + ptexConv16to32->LockRect(0, &lock, NULL, 0); + assert(lock.Pitch == 256*4); + u32* dst = (u32*)lock.pBits; + for(i = 0; i < 256*256; ++i) { + DWORD tempcol = RGBA16to32(i); + // have to flip r and b + *dst++ = (tempcol&0xff00ff00)|((tempcol&0xff)<<16)|((tempcol&0xff0000)>>16); + } + ptexConv16to32->UnlockRect(0); + + V_RETURN(pd3dDevice->CreateVolumeTexture(32, 32, 32, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexConv32to16, NULL)); + D3DLOCKED_BOX lockbox; + ptexConv32to16->LockBox(0, &lockbox, NULL, 0); + dst = (u32*)lockbox.pBits; + for(i = 0; i < 32; ++i) { + for(int j = 0; j < 32; ++j) { + for(int k = 0; k < 32; ++k) { + u32 col = (i<<10)|(j<<5)|k; + *dst++ = ((col&0xff)<<16)|(col&0xff00); + } + } + } + ptexConv32to16->UnlockBox(0); + + // set samplers + for(i = 0; i < 8; ++i) { + pd3dDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pd3dDevice->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + } + + //pd3dDevice->SetSamplerState(SAMP_SRC, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + //pd3dDevice->SetSamplerState(SAMP_SRC, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP); // can be used as a 3d texture + pd3dDevice->SetSamplerState(SAMP_BITWISEANDX, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BITWISEANDX, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BITWISEANDY, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BITWISEANDY, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + pd3dDevice->SetTexture(SAMP_BLOCKS, ptexBlocks); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); + pd3dDevice->SetVertexDeclaration(pdecl); + + SETRS(D3DRS_STENCILENABLE, FALSE); + SETRS(D3DRS_SCISSORTESTENABLE, 1); + SETRS(D3DRS_SEPARATEALPHABLENDENABLE, USEALPHABLENDING); + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO); + SETRS(D3DRS_CULLMODE, D3DCULL_NONE); + SETRS(D3DRS_BLENDFACTOR, 0x80000000); + SETRS(D3DRS_COLORWRITEENABLE1, 0); + + // points + SETRS(D3DRS_POINTSCALEENABLE, FALSE); + SETRS(D3DRS_POINTSIZE, FtoDW(1.0f)); + + g_nDepthBias = 0; + SETRS(D3DRS_DEPTHBIAS, FtoDW(0.000015f)); + + SETCONSTF(GPU_Z, g_vdepth);//vb[icurctx].zbuf.psm&3]); + + s_vznorm = DXVEC4(g_filog32, 0, 0,0); + SETCONSTF(GPU_ZNORM, s_vznorm); + + return S_OK; +} + +void ZeroGS::DeleteDeviceObjects() +{ + if( s_aviinit ) { + StopCapture(); + STOP_AVI(); + DEBUG_LOG("zerogs.avi stopped"); + s_aviinit = 0; + } + + SAFE_RELEASE(s_ptexAVICapture); + + if( pFont ) pFont->OnLostDevice(); + SAFE_RELEASE(pSprite); + + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + SAFE_RELEASE(s_ptexInterlace); + SAFE_RELEASE(pvbRect); + SAFE_RELEASE(ptexBlocks); + SAFE_RELEASE(ptexBilinearBlocks); + SAFE_RELEASE(ptexConv16to32); + SAFE_RELEASE(ptexConv32to16); + s_bAlphaSet = FALSE; + + vb[0].Unlock(); + SAFE_RELEASE(vb[0].pvb); + + vb[1].Unlock(); + SAFE_RELEASE(vb[1].pvb); +} + +void ZeroGS::Prim() +{ + if( g_bIsLost ) + return; + + VB& curvb = vb[prim->ctxt]; + if( curvb.CheckPrim() ) + Flush(prim->ctxt); + curvb.curprim._val = prim->_val; + + // flush the other pipe if sharing the same buffer +// if( vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp && vb[!prim->ctxt].dwCount > 0 ) +// { +// assert( vb[prim->ctxt].dwCount == 0 ); +// Flush(!prim->ctxt); +// } + + curvb.curprim.prim = prim->prim; + vb[prim->ctxt].Lock(); +} + +int GetTexFilter(const tex1Info& tex1) +{ + // always force + if( conf.bilinear == 2 ) + return 1; + + int texfilter = 0; + if( conf.bilinear && ptexBilinearBlocks != NULL ) { + if( tex1.mmin <= 1 ) + texfilter = tex1.mmin|tex1.mmag; + else + texfilter = tex1.mmag ? ((tex1.mmin+2)&5) : tex1.mmin; + + texfilter = texfilter == 1 || texfilter == 4 || texfilter == 5; + } + return texfilter; +} + +void ZeroGS::ReloadEffects() +{ +#ifndef RELEASE_TO_PUBLIC + for(int i = 0; i < ARRAYSIZE(ppsTexture); ++i) { + SAFE_RELEASE(ppsTexture[i]); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + LoadExtraEffects(); +#endif +} + +static int s_ClutResolve = 0; +static int s_PSM8Resolve = 0; +void ZeroGS::Flush(int context) +{ + assert( context >= 0 && context <= 1 ); + +#ifndef RELEASE_TO_PUBLIC + if( g_bUpdateEffect ) { + ReloadEffects(); + g_bUpdateEffect = 0; + } +#endif + + VB& curvb = vb[context]; + const pixTest curtest = curvb.test; + if( curvb.dwCount == 0 || (curtest.zte && curtest.ztst == 0) || g_bIsLost ) { + curvb.dwCount = 0; + return; + } + + if( s_RangeMngr.ranges.size() > 0 ) { + + // don't want infinite loop + DWORD prevcount = curvb.dwCount; + curvb.dwCount = 0; + FlushTransferRanges(curvb.curprim.tme ? &curvb.tex0 : NULL); + + curvb.dwCount = prevcount; + //if( curvb.dwCount == 0 ) + // return; + } + + if( curvb.bNeedTexCheck ) { + curvb.FlushTexData(); + + if( curvb.dwCount == 0 ) + return; + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + curvb.Unlock(); + + LPD3DTEX ptexRenderTargetCached = NULL; + int cachedtbp0, cachedtbw, cachedtbh; + + //s_bWriteDepth = TRUE; + + //static int lasttime = 0; + //fprintf(gsLog, "%d: %d\n", g_SaveFrameNum, timeGetTime()-lasttime); + //lasttime = timeGetTime(); + + if( curvb.bNeedFrameCheck || curvb.bNeedZCheck ) { + + int tpsm = curvb.tex0.psm; + if( curvb.bNeedTexCheck ) + tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; + + if( tpsm == PSMT8H && (g_GameSettings&GAME_NOTARGETCLUT) ) { + curvb.dwCount = 0; + return; + } + + // check for the texture before checking the frame (since things could get destroyed) + if( (g_GameSettings&GAME_PARTIALPOINTERS) &&curvb.curprim.tme ) { + +// if( (curvb.gsfb.fbp&0xff) != 0 ) { +// curvb.dwCount = 0; +// return; +// } + + // if texture is part of a previous target, use that instead + int tbw = curvb.tex0.tbw; + int tbp0 = curvb.tex0.tbp0; + + if( curvb.bNeedTexCheck ) { + // not yet initied, but still need to get correct target! (xeno3 ingame) + tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); + tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; + } + + if( (tpsm&~1) == 0 ) { + CRenderTarget* ptemptarg = s_RTs.GetTarg(tbp0, tbw); + if( ptemptarg != NULL && (ptemptarg->psm&~1) == (tpsm&~1) ) { + ptexRenderTargetCached = ptemptarg->ptex; + ptexRenderTargetCached->AddRef(); + cachedtbp0 = ptemptarg->fbp; + cachedtbw = ptemptarg->fbw; + cachedtbh = ptemptarg->fbh; + } + } + } + curvb.CheckFrame(curvb.curprim.tme ? curvb.tex0.tbp0 : 0); + } + +// if( g_SaveFrameNum == 976 ) { +// curvb.prndr->ConvertTo32(); +// } + if( curvb.prndr == NULL || curvb.pdepth == NULL ) { + WARN_LOG("Current render target NULL (ctx: %d)", context); + curvb.dwCount = 0; + SAFE_RELEASE(ptexRenderTargetCached); + return; + } + +#if defined(PRIM_LOG) && defined(_DEBUG) + static const char* patst[8] = { "NEVER", "ALWAYS", "LESS", "LEQUAL", "EQUAL", "GEQUAL", "GREATER", "NOTEQUAL"}; + static const char* pztst[4] = { "NEVER", "ALWAYS", "GEQUAL", "GREATER" }; + static const char* pafail[4] = { "KEEP", "FB_ONLY", "ZB_ONLY", "RGB_ONLY" }; + PRIM_LOG("**Drawing ctx %d, num %d, fbp: 0x%x, zbp: 0x%x, fpsm: %d, zpsm: %d, fbw: %d\n", context, vb[context].dwCount, curvb.prndr->fbp, curvb.zbuf.zbp, curvb.prndr->psm, curvb.zbuf.psm, curvb.prndr->fbw); + PRIM_LOG("prim: prim=%x iip=%x tme=%x fge=%x abe=%x aa1=%x fst=%x ctxt=%x fix=%x\n", + curvb.curprim.prim, curvb.curprim.iip, curvb.curprim.tme, curvb.curprim.fge, curvb.curprim.abe, curvb.curprim.aa1, curvb.curprim.fst, curvb.curprim.ctxt, curvb.curprim.fix); + PRIM_LOG("test: ate:%d, atst: %s, aref: %d, afail: %s, date: %d, datm: %d, zte: %d, ztst: %s, fba: %d\n", + curvb.test.ate, patst[curvb.test.atst], curvb.test.aref, pafail[curvb.test.afail], curvb.test.date, curvb.test.datm, curvb.test.zte, pztst[curvb.test.ztst], curvb.fba.fba); + PRIM_LOG("alpha: A%d B%d C%d D%d FIX:%d pabe: %d; aem: %d, ta0: %d, ta1: %d\n", curvb.alpha.a, curvb.alpha.b, curvb.alpha.c, curvb.alpha.d, curvb.alpha.fix, gs.pabe, gs.texa.aem, gs.texa.ta[0], gs.texa.ta[1]); + PRIM_LOG("tex0: tbp0=0x%x, tbw=%d, psm=0x%x, tw=%d, th=%d, tcc=%d, tfx=%d, cbp=0x%x, cpsm=0x%x, csm=%d, csa=%d, cld=%d\n", + curvb.tex0.tbp0, curvb.tex0.tbw, curvb.tex0.psm, curvb.tex0.tw, + curvb.tex0.th, curvb.tex0.tcc, curvb.tex0.tfx, curvb.tex0.cbp, + curvb.tex0.cpsm, curvb.tex0.csm, curvb.tex0.csa, curvb.tex0.cld); + PRIM_LOG("frame: %d\n\n", g_SaveFrameNum); +#endif + + CMemoryTarget* pmemtarg = NULL; + CRenderTarget* ptextarg = NULL; + + // kh2 hack +// if( curvb.dwCount == 2 && curvb.curprim.tme == 0 && curvb.curprim.abe == 0 && (curvb.tex0.tbp0 == 0x2a00 || curvb.tex0.tbp0==0x1d00) ) { +// // skip +// DEBUG_LOG("skipping\n"); +// g_SaveFrameNum++; +// curvb.dwCount = 0; +// return; +// } + + if( curtest.date || gs.pabe ) + SetDestAlphaTest(); + + // set the correct pixel shaders + if( curvb.curprim.tme && ptexRenderTargetCached == NULL ) { + + // if texture is part of a previous target, use that instead + int tbw = curvb.tex0.tbw; + int tbp0 = curvb.tex0.tbp0; + int tpsm = curvb.tex0.psm; + + if( curvb.bNeedTexCheck ) { + // not yet initied, but still need to get correct target! (xeno3 ingame) + tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); + tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; + tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; + } + ptextarg = s_RTs.GetTarg(tbp0, tbw); + + if( ptextarg == NULL && tpsm == PSMT8 ) { + // check for targets with half the width + ptextarg = s_RTs.GetTarg(tbp0, tbw/2); + if( ptextarg == NULL ) { + tbp0 &= ~0x7ff; + ptextarg = s_RTs.GetTarg(tbp0, tbw/2); // mgs3 hack + + if( ptextarg == NULL ) { + // check the next level (mgs3) + tbp0 &= ~0xfff; + ptextarg = s_RTs.GetTarg(tbp0, tbw/2); // mgs3 hack + } + + if( ptextarg != NULL && ptextarg->start > tbp0*256 ) { + // target beyond range, so ignore + ptextarg = NULL; + } + } + +// if( ptextarg != NULL ) { +// // make sure target isn't invalidated by the ranges +// for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { +// +// int start = itrange->start; +// int end = itrange->end; +// +// // if start and end are in the range or there's a range that is between tbp0 and start, then remove +// if( (start <= tbp0*256 && end > tbp0*256) || (start >= ptextarg->fbp*256 && start <= tbp0*256) ) { +// ptextarg = NULL; +// break; +// } +// } +// } + + if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { + // find the equivalent memtarg + if( s_PSM8Resolve == 0 ) { //|| (s_PSM8Resolve > 0 && s_PSM8Resolve+128 < g_SaveFrameNum) ) { + DWORD prevcount = curvb.dwCount; + curvb.dwCount = 0; + if( ptextarg->pmimicparent != NULL ) + ptextarg->pmimicparent->Resolve(); + else + ptextarg->Resolve(); + curvb.dwCount = prevcount; + s_PSM8Resolve = g_SaveFrameNum; // stop from resolving again (once per frame) + } + + tex0Info mytex0 = curvb.tex0; + mytex0.tbp0 = tbp0; + if( ptextarg->pmimicparent != NULL ) { + mytex0.tbp0 = ptextarg->pmimicparent->fbp; + } + pmemtarg = g_MemTargs.GetMemoryTarget(mytex0, 1); + + // have to add an offset to all texture reads + mytex0.tbp0 = tbp0; // change so that SetTexVariablesInt can set the right offsets + + SetTexVariablesInt(context, GetTexFilter(curvb.tex1), mytex0, pmemtarg, s_bForceTexFlush); + curvb.bVarsTexSync = TRUE; + + ptextarg = NULL; // won't be needing this anymore + } + } + + if( (tpsm&0x30)==0x30 && ptextarg == NULL ) { + // try depth + ptextarg = s_DepthRTs.GetTarg(tbp0, tbw); + } + + if( ptextarg == NULL && (g_GameSettings&GAME_TEXTURETARGS) ) { + // check if any part of the texture intersects the current target + if( !PSMT_ISCLUT(tpsm) && curvb.tex0.tbp0 >= curvb.frame.fbp && (curvb.tex0.tbp0 << 8) < curvb.prndr->end) { + ptextarg = curvb.prndr; + } + } + + if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { + if( PSMT_ISCLUT(tpsm) && tpsm != PSMT8H && tpsm != PSMT8 ) { // handle 8h cluts + // don't support clut targets, read from mem + // 4hl - kh2 check + if( tpsm != PSMT4HL && tpsm != PSMT4HH && s_ClutResolve <= 1 ) { // xenosaga requires 2 resolves + DWORD prevcount = curvb.dwCount; + curvb.dwCount = 0; + ptextarg->Resolve(); + s_ClutResolve++; + curvb.dwCount = prevcount; + } + ptextarg = NULL; + } + else { + if( ptextarg == curvb.prndr ) { + // need feedback + if( ptextarg->pmimicparent != NULL ) { + // if the target is mimic, create the feedback of the parent + assert( ptextarg->pmimicparent->ptex == ptextarg->ptex || ptextarg->pmimicparent->ptexFeedback == ptextarg->ptex ); + SAFE_RELEASE(ptextarg->ptexFeedback); + SAFE_RELEASE(ptextarg->psurfFeedback); + ptextarg->pmimicparent->CreateFeedback(); + ptextarg->ptex = ptextarg->pmimicparent->ptex; + ptextarg->ptexFeedback = ptextarg->pmimicparent->ptexFeedback; ptextarg->ptexFeedback->AddRef(); + ptextarg->psurf = ptextarg->pmimicparent->psurf; + ptextarg->psurfFeedback = ptextarg->pmimicparent->psurfFeedback; ptextarg->psurfFeedback->AddRef(); + } + else + curvb.prndr->CreateFeedback(); + + pd3dDevice->SetRenderTarget(1, (s_bWriteDepth && curvb.pdepth != NULL) ? curvb.pdepth->psurf : NULL); + } + } + } + else ptextarg = NULL; + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0x80000000 ) { + char str[255]; + sprintf(str, "rndr.tga", g_SaveFrameNum); + D3DXSaveSurfaceToFile(str, D3DXIFF_TGA, curvb.prndr->psurf, NULL, NULL); + } +#endif + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + } + } + + if( !curvb.bVarsSetTarg ) + SetContextTarget(context); + else { + assert( curvb.pdepth != NULL ); + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + if( (curvb.pdepth->status & CRenderTarget::TS_NeedUpdate) || (curvb.prndr->status & CRenderTarget::TS_NeedUpdate) ) + SetContextTarget(context); + } + + SetTexVariables(context); + if( ptextarg == NULL && pmemtarg == NULL ) { + pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); + + if( vb[context].bVarsTexSync ) { + if( vb[context].pmemtarg != pmemtarg ) { + SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + } + } + else { + SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + + INC_TEXVARS(); + } + } + + icurctx = context; + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + curvb.prndr->status = 0; + + if( curvb.pdepth != NULL ) { + assert( !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); + if( !curvb.zbuf.zmsk ) { + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + curvb.pdepth->status = 0; + } + } + + s_dwColorWrite = (curvb.prndr->psm&0xf) == 1 ? (D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED) : 0xf; + + if( ((curvb.frame.fbm)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_RED; + if( ((curvb.frame.fbm>>8)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_GREEN; + if( ((curvb.frame.fbm>>16)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_BLUE; + if( ((curvb.frame.fbm>>24)&0xff) == 0xff) s_dwColorWrite &= ~D3DCOLORWRITEENABLE_ALPHA; + + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); // need to always set it since something in this code resets it + + // set the shaders + pd3dDevice->SetVertexShader(pvs[2*((curvb.curprim._val>>1)&3)+8*s_bWriteDepth+context]); + pd3dDevice->SetStreamSource(0, curvb.pvb, curvb.dwCurOff*sizeof(VertexGPU), sizeof(VertexGPU)); + + DWORD dwUsingSpecialTesting = 0; + DWORD dwFilterOpts = 0; + + IDirect3DPixelShader9* pps; + + // need exact if equal or notequal + int exactcolor = 0; + if( g_nPixelShaderVer != SHADER_20 ) + // ffx2 breaks when ==7 + exactcolor = (curtest.ate && curtest.aref <= 128) && (curtest.atst==4);//||curtest.atst==7); + + int shadertype = 0; + + // set the correct pixel shaders + if( curvb.curprim.tme ) { + + if( curvb.ptexClamp[0] != NULL ) pd3dDevice->SetTexture(SAMP_BITWISEANDX, curvb.ptexClamp[0]); + if( curvb.ptexClamp[1] != NULL ) pd3dDevice->SetTexture(SAMP_BITWISEANDY, curvb.ptexClamp[1]); + + if( ptexRenderTargetCached != NULL ) { + DXVEC4 vpageoffset; + vpageoffset.w = 0; + + int psm = curvb.tex0.psm; + assert( !PSMT_ISCLUT(curvb.tex0.psm)); + + pps = LoadShadeEffect(1, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context); + pd3dDevice->SetTexture(SAMP_MEMORY0+context, ptexRenderTargetCached); + s_ptexCurSet[context] = ptexRenderTargetCached; + + if( curvb.tex1.mmag ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 1; + } + + if( curvb.tex1.mmin ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 2; + } + + DXVEC4 vTexDims; + vTexDims.x = curvb.tex0.tw / (float)cachedtbw; + vTexDims.y = curvb.tex0.th / (float)cachedtbh; + +// u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page +// int blockheight = 32; +// int ycoord = ((curvb.tex0.tbp0-cachedtbp0)/(32*(cachedtbw>>6))) * blockheight; +// int xcoord = (((curvb.tex0.tbp0-cachedtbp0)%(32*(cachedtbw>>6)))) * 2; +//// xcoord += ptextarg->targoffx; +//// ycoord += ptextarg->targoffy; +// vTexDims.z = (float)xcoord / (float)cachedtbw; +// vTexDims.w = (float)ycoord / (float)cachedtbh; + vTexDims.z = vTexDims.w = 0; + SETCONSTF(GPU_TEXDIMS0+context, vTexDims); + + SETCONSTF(GPU_PAGEOFFSET0+context, vpageoffset); + + if( g_bSaveTex ) + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, ptexRenderTargetCached, NULL); + } + else if( ptextarg != NULL ) { + + if( ptextarg->IsDepth() ) + SetWriteDepth(); + + DXVEC4 vpageoffset; + vpageoffset.w = 0; + + shadertype = 1; + if( (curvb.tex0.psm == PSMT8 || curvb.tex0.psm == PSMT8H) && !(g_GameSettings&GAME_NOTARGETCLUT) ) { + // load the clut to memory + LPD3DTEX ptexclut = NULL; + pd3dDevice->CreateTexture(256, 1, 1, 0, (curvb.tex0.cpsm&2) ? D3DFMT_A1R5G5B5 : D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &ptexclut, NULL); + if( ptexclut != NULL ) { + + D3DLOCKED_RECT lock; + ptexclut->LockRect(0, &lock, NULL, D3DLOCK_NOSYSLOCK); + + // fill the buffer by decoding the clut + int nClutOffset = 0, clutsize; + int entries = (curvb.tex0.psm&3)==3 ? 256 : 16; + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * curvb.tex0.csa; + clutsize = min(entries, 256-curvb.tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (curvb.tex0.csa&15) + (curvb.tex0.csa>=16?2:0); + clutsize = min(entries, 512-curvb.tex0.csa*16)*2; + } + + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(lock.pBits, ZeroGS::g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)lock.pBits; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(ZeroGS::g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + + ptexclut->UnlockRect(0); + + s_vecTempTextures.push_back(ptexclut); + pd3dDevice->SetTexture(SAMP_FINAL, ptexclut); + + if( g_bSaveTex ) + D3DXSaveTextureToFile("clut.tga", D3DXIFF_TGA, ptexclut, NULL); + } + + if( g_nPixelShaderVer != SHADER_20 && (ptextarg->psm & 2) ) { + // 16 bit texture + shadertype = 4; + + DXVEC4 v; + v.x = 16.0f / (float)ptextarg->fbw; + v.y = 64.0f / (float)ptextarg->fbh; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0, v); + + v.x = 1; + v.y = -0.5f; + v.z = 0; + v.w = 0.0001f; + SETCONSTF(GPU_PAGEOFFSET0, v); + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv32to16); + } + else + shadertype = 2; + } + else { + if( PSMT_ISCLUT(curvb.tex0.psm) ) + WARN_LOG("Using render target with CLUTs %d!\n", curvb.tex0.psm); + else { + if( (curvb.tex0.psm&2) != (ptextarg->psm&2) && (g_nPixelShaderVer != SHADER_20 || !curvb.curprim.fge) ) { + if( curvb.tex0.psm & 2 ) { + // converting from 32->16 + shadertype = 3; + + DXVEC4 v; + v.x = 16.0f / (float)curvb.tex0.tw; + v.y = 64.0f / (float)curvb.tex0.th; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + SETCONSTF(GPU_TEXOFFSET0+context, v); + + vpageoffset.x = -0.1f / 256.0f; + vpageoffset.y = -0.001f / 256.0f; + vpageoffset.z = -0.1f / ptextarg->fbh; + vpageoffset.w = ((ptextarg->psm&0x30)==0x30)?-1.0f:0.0f; + + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexConv16to32); + } + else { + // converting from 16->32 + WARN_LOG("ZeroGS: converting from 16 to 32bit RTs\n"); + //shadetype = 4; + } + } + } + } + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + pps = LoadShadeEffect(shadertype, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context); + LPD3DTEX ptexset = ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex; + pd3dDevice->SetTexture(SAMP_MEMORY0+context, ptexset); + s_ptexCurSet[context] = ptexset; + + if( curvb.tex1.mmag ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 1; + } + + if( curvb.tex1.mmin ) { + pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + dwFilterOpts |= 2; + } + + DXVEC4 vTexDims; + vTexDims.x = curvb.tex0.tw / (float)ptextarg->fbw; + vTexDims.y = curvb.tex0.th / (float)ptextarg->targheight; + + // look at the offset of tbp0 from fbp + if( curvb.tex0.tbp0 <= ptextarg->fbp ) { + vTexDims.z = 0;//-0.5f/(float)ptextarg->fbw; + vTexDims.w = 0;//0.2f/(float)ptextarg->fbh; + } + else { + u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page + int blockheight = (ptextarg->psm&2) ? 64 : 32; + int ycoord = ((curvb.tex0.tbp0-ptextarg->fbp)/(32*(ptextarg->fbw>>6))) * blockheight; + int xcoord = (((curvb.tex0.tbp0-ptextarg->fbp)%(32*(ptextarg->fbw>>6)))) * 2; + xcoord += ptextarg->targoffx; + ycoord += ptextarg->targoffy; + vTexDims.z = (float)xcoord / (float)ptextarg->fbw; + vTexDims.w = (float)ycoord / (float)ptextarg->targheight; + } + + if( shadertype == 4 ) { + vTexDims.z += 8.0f / (float)ptextarg->fbw; + } + + SETCONSTF(GPU_TEXDIMS0+context, vTexDims); + + // zoe2 + if( (ptextarg->psm&0x30) == 0x30 ) {//&& (psm&2) == (ptextarg->psm&2) ) { + // target of zbuf has +1 added to it, don't do 16bit + vpageoffset.w = -1; +// DXVEC4 valpha2; +// valpha2.x = 1; valpha2.y = 0; +// valpha2.z = -1; valpha2.w = 0; +// SETCONSTF(GPU_TEXALPHA20+context, &valpha2); + } + SETCONSTF(GPU_PAGEOFFSET0+context, vpageoffset); + + if( g_bSaveTex ) + D3DXSaveTextureToFile("tex.tga", D3DXIFF_TGA, ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex, NULL); + } + else { + // save the texture +#ifdef _DEBUG +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 0); +// assert( curvb.pmemtarg == pmemtarg ); +// if( PSMT_ISCLUT(curvb.tex0.psm) ) +// assert( curvb.pmemtarg->ValidateClut(curvb.tex0) ); +#endif + +//#ifdef ZEROGS_CACHEDCLEAR +// if( !curvb.pmemtarg->ValidateTex(curvb.tex0, true) ) { +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); +// SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); +// vb[context].bVarsTexSync = TRUE; +// } +//#endif + + if( g_bSaveTex ) { + if( g_bSaveTex == 1 ) SaveTex(&curvb.tex0, 1); + else SaveTex(&curvb.tex0, 0); + } + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + pps = LoadShadeEffect(0, GetTexFilter(curvb.tex1), curvb.curprim.fge, + curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context); + } + } + else pps = ppsRegular[curvb.curprim.fge+2*s_bWriteDepth]; + + pd3dDevice->SetPixelShader(pps); + + BOOL bCanRenderStencil = g_bUpdateStencil && (curvb.prndr->psm&0xf) != 1 && !(curvb.frame.fbm&0x80000000); + if( g_GameSettings & GAME_NOSTENCIL ) + bCanRenderStencil = 0; + + if( s_bDestAlphaTest) { + SETRS(D3DRS_STENCILENABLE, bCanRenderStencil); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + } + else SETRS(D3DRS_STENCILENABLE, 0); + + SETRS(D3DRS_ZWRITEENABLE, !curvb.zbuf.zmsk); + SETRS(D3DRS_ZENABLE, curtest.zte); + if( curtest.zte ) { + if( curtest.ztst > 1 ) g_nDepthUsed = 2; + if( (curtest.ztst == 2) ^ (g_nDepthBias != 0) ) { + g_nDepthBias = curtest.ztst == 2; + if( g_GameSettings & GAME_RELAXEDDEPTH ) + SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.00003f):FtoDW(0.0001f)); + else + SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.0003f):FtoDW(0.000015f)); + } + + SETRS(D3DRS_ZFUNC, g_dwZCmp[curtest.ztst]); + +// if( curtest.ztst == 3 ) { +// // gequal +// if( s_vznorm.y == 0 ) { +// s_vznorm.y = 0.00001f; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } +// else { +// if( s_vznorm.y > 0 ) { +// s_vznorm.y = 0; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } + } + + SETRS(D3DRS_ALPHATESTENABLE, curtest.ate&&USEALPHATESTING); + if( curtest.ate ) { + + if( curtest.atst == 7 && curtest.aref == 255 ) { + // when it is at the very top, do a less than rather than not equal (gekibo2) + SETRS(D3DRS_ALPHAFUNC, D3DCMP_LESS); + SETRS(D3DRS_ALPHAREF, 255); + } + else { + SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curtest.atst]); + SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curtest.aref) : curtest.aref); + } + } + + if( s_bWriteDepth ) { + //pd3dDevice->SetRenderTarget(0, curvb.prndr->psurf); + //pd3dDevice->SetRenderTarget(1, !curvb.zbuf.zmsk?curvb.pdepth->psurf:NULL); + if( bIndepWriteMasks ) + SETRS(D3DRS_COLORWRITEENABLE1, !curvb.zbuf.zmsk?0xf:0); + else + pd3dDevice->SetRenderTarget(1, !curvb.zbuf.zmsk?curvb.pdepth->psurf:NULL); + } + + if( curvb.curprim.abe ) + SetAlphaVariables(curvb.alpha); + else + SETRS(D3DRS_ALPHABLENDENABLE, 0); + + // needs to be before RenderAlphaTest + if( curvb.fba.fba || s_bDestAlphaTest ) { + if( gs.pabe || (curvb.fba.fba || bCanRenderStencil) && !(curvb.frame.fbm&0x80000000) ) { + RenderFBA(curvb); + } + } + + u32 oldabe = curvb.curprim.abe; + if( gs.pabe ) { + //WARN_LOG("PBE!\n"); + curvb.curprim.abe = 1; + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + } + + if( curvb.curprim.abe && bNeedAlphaColor ) { + + if( //bCanRenderStencil && + (bNeedBlendFactorInAlpha || ((curtest.ate && curtest.atst>1) && (curtest.aref > 0x80))) ) { + // need special stencil processing for the alpha + RenderAlphaTest(curvb); + dwUsingSpecialTesting = 1; + } + + // harvest fishing + DXVEC4 v = vAlphaBlendColor;// + DXVEC4(0,0,0,(curvb.test.atst==4 && curvb.test.aref>=128)?-0.004f:0); + if( exactcolor ) { v.y *= 255; v.w *= 255; } + SETCONSTF(GPU_ONECOLOR, v); + } + else { + // not using blending so set to defaults + DXVEC4 v = exactcolor ? DXVEC4(1, 510*255.0f/256.0f, 0, 0) : DXVEC4(1,2*255.0f/256.0f,0,0); + SETCONSTF(GPU_ONECOLOR, v); + } + + if( s_bDestAlphaTest && bCanRenderStencil ) { + // if not 24bit and can write to high alpha bit + RenderStencil(curvb, dwUsingSpecialTesting); + } + else { + dwStencilRef = STENCIL_SPECIAL; + dwStencilMask = STENCIL_SPECIAL; + + // setup the stencil to only accept the test pixels + if( dwUsingSpecialTesting ) { + SETRS(D3DRS_STENCILENABLE, TRUE); + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_PIXELWRITE); + SETRS(D3DRS_STENCILMASK, STENCIL_SPECIAL); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + } + } + +#ifdef _DEBUG + if( bDestAlphaColor == 1 ) { + WARN_LOG("dest alpha blending! manipulate alpha here\n"); + } +#endif + + if( bCanRenderStencil && gs.pabe ) { + // only render the pixels with alpha values >= 0x80 + SETRS(D3DRS_STENCILREF, dwStencilRef|STENCIL_FBA); + SETRS(D3DRS_STENCILMASK, dwStencilMask|STENCIL_FBA); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + } + +// curvb.prndr->SetViewport(); +// pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); +// SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + if( !curvb.test.ate || curvb.test.atst > 0 ) { + DRAW(); + } + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_STENCILREF, dwStencilRef); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + SETCONSTF(GPU_ONECOLOR, v); + + DRAW(); + + // reset + SETRS(D3DRS_STENCILMASK, dwStencilMask); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + } + + // more work on alpha failure case + if( curtest.ate && curtest.atst != 1 && curtest.afail > 0 ) { + + // need to reverse the test and disable some targets + SETRS(D3DRS_ALPHAFUNC, g_dwReverseAlphaCmp[curtest.atst]); + + if( curtest.afail & 1 ) { // front buffer update only + + if( curtest.afail == 3 ) // disable alpha + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED); + + SETRS(D3DRS_ZWRITEENABLE, FALSE); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + } + else { + // zbuffer update only + SETRS(D3DRS_COLORWRITEENABLE, 0); + } + + if( gs.pabe && bCanRenderStencil ) { + // only render the pixels with alpha values >= 0x80 + DXVEC4 v = vAlphaBlendColor; + if( exactcolor ) { v.y *= 255; v.w *= 255; } + SETCONSTF(GPU_ONECOLOR, v); + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + SETRS(D3DRS_STENCILREF, dwStencilRef|STENCIL_FBA); + SETRS(D3DRS_STENCILMASK, dwStencilMask|STENCIL_FBA); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + } + + // setup the stencil to only accept the test pixels + if( dwUsingSpecialTesting ) { + + if( !s_bDestAlphaTest || !bCanRenderStencil ) { + SETRS(D3DRS_STENCILENABLE, FALSE); + } + } + +// IDirect3DQuery9* pOcclusionQuery; +// DWORD numberOfPixelsDrawn; +// +// pd3dDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery); +// +// // Add an end marker to the command buffer queue. +// pOcclusionQuery->Issue(D3DISSUE_BEGIN); + + DRAW(); + +// pOcclusionQuery->Issue(D3DISSUE_END); + // Force the driver to execute the commands from the command buffer. + // Empty the command buffer and wait until the GPU is idle. +// while(S_FALSE == pOcclusionQuery->GetData( &numberOfPixelsDrawn, sizeof(DWORD), D3DGETDATA_FLUSH )); +// SAFE_RELEASE(pOcclusionQuery); + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_STENCILREF, dwStencilRef); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + SETCONSTF(GPU_ONECOLOR, v); + + DRAW(); + + // reset + SETRS(D3DRS_STENCILMASK, dwStencilMask); + SETRS(D3DRS_ALPHABLENDENABLE, oldabe); + if( !dwStencilMask ) SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + } + + // restore + + if( (curtest.afail & 1) && !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL); + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1,curvb.pdepth->psurf); + } + } + + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + // not needed anymore since rest of ops concentrate on image processing + //SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curtest.atst]); + } + + if( dwUsingSpecialTesting ) { + // render the real alpha + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + + SETRS(D3DRS_ZWRITEENABLE, FALSE); + + SETRS(D3DRS_STENCILMASK, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + + DXVEC4 v = DXVEC4(0,exactcolor ? 510.0f : 2.0f,0,0); + SETCONSTF(GPU_ONECOLOR, v); + DRAW(); + + // don't need to restore + } + + if( s_bDestAlphaTest ) { + if( (s_dwColorWrite&D3DCOLORWRITEENABLE_ALPHA) ) { + if( curvb.fba.fba ) + ProcessFBA(curvb); + else if( bCanRenderStencil ) + // finally make sure all entries are 1 when the dest alpha >= 0x80 (if fba is 1, this is already the case) + ProcessStencil(curvb); + } + } + else if( (s_dwColorWrite&D3DCOLORWRITEENABLE_ALPHA) && curvb.fba.fba ) + ProcessFBA(curvb); + + if( bDestAlphaColor == 1 ) { + // need to reset the dest colors to their original counter parts + //WARN_LOG("Need to reset dest alpha color\n"); + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0xf ) { + char str[255]; + sprintf(str, "frames\\frame%.4d.jpg", g_SaveFrameNum++); + if( (g_bSaveFlushedFrame & 2) ) + D3DXSaveSurfaceToFile(str, D3DXIFF_JPG, curvb.prndr->psurf, NULL, NULL); + } +#endif + + // clamp the final colors, when enabled ffx2 credits mess up + if( curvb.curprim.abe && bAlphaClamping && g_RenderFormat != D3DFMT_A8R8G8B8 && !(g_GameSettings&GAME_NOCOLORCLAMP) ) { // if !colclamp, skip + + ResetAlphaVariables(); + + // if processing the clamping case, make sure can write to the front buffer + SETRS(D3DRS_STENCILENABLE, 0); + SETRS(D3DRS_ALPHABLENDENABLE, TRUE); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + + pd3dDevice->SetPixelShader(ppsOne); + + // (dest&0x7f)+0x80, blend factor for alpha is always 0x80 + SETRS(D3DRS_DESTBLEND, D3DBLEND_ONE); + SETRS(D3DRS_SRCBLEND, D3DBLEND_ONE); + + float f; + + if( bAlphaClamping & 1 ) { // min + f = 0; + SETCONSTF(GPU_ONECOLOR, &f); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_MAX); + DRAW(); + } + + // bios shows white screen + if( bAlphaClamping & 2 ) { // max + f = 1; + SETCONSTF(GPU_ONECOLOR, &f); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_MIN); + DRAW(); + } + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL ); + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1,curvb.pdepth->psurf); + } + } + + if( curvb.test.ate && USEALPHATESTING ) + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + + SETRS(D3DRS_ZENABLE, curtest.zte); + } + + if( dwFilterOpts ) { + // undo filter changes + if( dwFilterOpts & 1 ) pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + if( dwFilterOpts & 2 ) pd3dDevice->SetSamplerState(SAMP_MEMORY0+context, D3DSAMP_MINFILTER, D3DTEXF_POINT); + } + + // reset used textures + if( shadertype > 2 ) { + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + pd3dDevice->SetSamplerState(SAMP_BILINEARBLOCKS, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + pd3dDevice->SetTexture(SAMP_BILINEARBLOCKS, ptexBilinearBlocks); + } + + SETRS(D3DRS_CLIPPLANEENABLE, 0); +//#ifndef RELEASE_TO_PUBLIC + ppf += curvb.dwCount+0x100000; +//#endif + curvb.dwCurOff += POINT_BUFFERFLUSH; + SAFE_RELEASE(ptexRenderTargetCached); + + g_MaxRenderedHeight = 0; + curvb.dwCount = 0; + //curvb.Lock(); + curvb.curprim.abe = oldabe; + //if( oldabe ) SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + --s_nWireframeCount; + } + } +} + +void ZeroGS::ProcessMessages() +{ + if( listMsgs.size() > 0 ) { + pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); + + RECT rctext; + rctext.left = 25; rctext.top = 15; + list::iterator it = listMsgs.begin(); + + while( it != listMsgs.end() ) { + rctext.left += 1; + rctext.top += 1; + pFont->DrawText(pSprite, it->str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); + rctext.left -= 1; + rctext.top -= 1; + pFont->DrawText(pSprite, it->str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffffff30); + rctext.top += 15; + + if( (int)(it->dwTimeStamp - timeGetTime()) < 0 ) + it = listMsgs.erase(it); + else ++it; + } + + pSprite->End(); + } +} + +void ZeroGS::RenderCustom(float fAlpha) +{ + if( !s_bBeginScene ) + pd3dDevice->BeginScene(); + + pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); + + pd3dDevice->SetRenderTarget(0, psurfOrgTarg); + + if( s_bWriteDepth ) + pd3dDevice->SetRenderTarget(1, NULL); + + SETRS(D3DRS_STENCILENABLE, 0); + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_ALPHATESTENABLE, 0); + SETRS(D3DRS_SCISSORTESTENABLE, 0); + + // play custom animation + pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, 0, 1, 0); + + // tex coords + DXVEC4 v = DXVEC4(1, 1, 0, 0); + SETCONSTF(GPU_BITBLTTEX, v); + SETCONSTF(GPU_BITBLTPOS, v); + + v.x = v.y = v.z = v.w = fAlpha; + SETCONSTF(GPU_ONECOLOR, v); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + pd3dDevice->SetPixelShader(ppsBaseTexture); + + // inside vb[0]'s target area, so render that region only + pd3dDevice->SetTexture(SAMP_FINAL, ptexLogo); + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + // restore + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + //pd3dDevice->SetSamplerState(SAMP_FINAL, D3DSAMP_MINFILTER, D3DTEXF_POINT); + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + + ProcessMessages(); + + pd3dDevice->EndScene(); + s_bBeginScene = FALSE; + + pd3dDevice->Present(NULL, NULL, NULL, NULL); + + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + SETRS(D3DRS_STENCILENABLE, 1); + + if( icurctx >= 0 ) vb[icurctx].bSyncVars = 0; +} + +// adjusts trans to preserve aspect ratio +void ZeroGS::AdjustTransToAspect(DXVEC4& v, int dispwidth, int dispheight) +{ + float temp, f; + if( dispwidth * height > dispheight * width ) { + // limited by width + + // change in ratio + f = ((float)width / (float)dispwidth) / ((float)height / (float)dispheight); + v.y *= f; + v.w *= f; + + // scanlines mess up when not aligned right + v.y += (1-modf(v.y*height/2+0.05f, &temp))*2.0f/(float)height; + v.w += (1-modf(v.w*height/2+0.05f, &temp))*2.0f/(float)height; + } + else { + // limited by height + f = ((float)height / (float)dispheight) / ((float)width / (float)dispwidth); + f -= modf(f*width, &temp)/(float)width; + v.x *= f; + v.z *= f; + } +} + +void ZeroGS::Restore() +{ + if( !g_bIsLost ) + return; + + if( SUCCEEDED(pd3dDevice->Reset(&d3dpp)) ) { + g_bIsLost = 0; + // handle lost states + ZeroGS::ChangeDeviceSize(width, height); + } +} + +void ZeroGS::RenderCRTC(int interlace) +{ + if( pd3dDevice == NULL ) { + return; + } + + if( g_bIsLost ) return; + +#ifdef RELEASE_TO_PUBLIC + if( g_nRealFrame < 80 ) { + RenderCustom( min(1.0f, 2.0f - (float)g_nRealFrame / 40.0f) ); + + if( g_nRealFrame == 79 ) + SAFE_RELEASE(ptexLogo); + return; + } +#endif + + Flush(0); + Flush(1); + + // frame skipping + if( g_nFrameRender > 0 ) { + + if( g_nFrameRender < 8 ) { + g_nFrameRender++; + if( g_nFrameRender <= 3 ) { + g_nFramesSkipped++; + return; + } + } + } + else { + if( g_nFrameRender < -1 ) { + g_nFramesSkipped++; + return; + } + g_nFrameRender--; + } + + if( g_bSaveFrame ) { + if( vb[0].prndr != NULL ) D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, vb[0].prndr->psurf, NULL, NULL); + + if( vb[1].prndr != NULL && vb[0].prndr != vb[1].prndr ) D3DXSaveSurfaceToFile("frame2.tga", D3DXIFF_TGA, vb[1].prndr->psurf, NULL, NULL); + else DeleteFile("frame2.tga"); + } + + if( s_RangeMngr.ranges.size() > 0 ) + FlushTransferRanges(NULL); + + if( icurctx >= 0 && vb[icurctx].bVarsSetTarg ) { // check if anything rendered + pd3dDevice->SetRenderTarget(0, psurfOrgTarg); + pd3dDevice->SetRenderTarget(1, NULL); + + pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); + } + + D3DVIEWPORT9 view; + view.Width = width; + view.Height = height; + view.X = 0; + view.Y = 0; + view.MinZ = 0; + view.MaxZ = 1.0f; + pd3dDevice->SetViewport(&view); + + //g_GameSettings |= GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE; + //s_bWriteDepth = TRUE; + g_SaveFrameNum = 0; + g_bSaveFlushedFrame = 1; +// static int counter = 0; +// counter++; + // reset fba after every frame + //if( !(g_GameSettings&GAME_NOFBARESET) ) { + vb[0].fba.fba = 0; + vb[1].fba.fba = 0; + //} + u32 bInterlace = SMODE2->INT && SMODE2->FFMD && (conf.interlace<2); + + // if interlace, only clear every other vsync + if(!bInterlace ) { + u32 color = D3DCOLOR_ARGB(0, BGCOLOR->R, BGCOLOR->G, BGCOLOR->B); + pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_STENCIL, color, 1, 0); + } + + if( !s_bBeginScene ) { + pd3dDevice->BeginScene(); + s_bBeginScene = TRUE; + } + + pd3dDevice->SetVertexShader(pvsBitBlt); + pd3dDevice->SetStreamSource(0, pvbRect, 0, sizeof(VertexGPU)); + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_SOLID); + SETRS(D3DRS_ZENABLE, 0); + SETRS(D3DRS_ZWRITEENABLE, 0); + SETRS(D3DRS_COLORWRITEENABLE, 0xf); + SETRS(D3DRS_ALPHABLENDENABLE, 0); + SETRS(D3DRS_ALPHATESTENABLE, 0); + SETRS(D3DRS_SCISSORTESTENABLE, 0); + SETRS(D3DRS_STENCILENABLE, 0); + + BOOL bUsingStencil = 0; + + if( bInterlace ) g_PrevBitwiseTexX = -1; // reset since will be using + + tex0Info dispinfo[2]; + + for(int i = 0; i < 2; ++i) { + + if( !(*(u32*)(PMODE) & (1<MAGH+1; + int magv = pd->MAGV+1; + + dispinfo[i].tbp0 = pfb->FBP << 5; + dispinfo[i].tbw = pfb->FBW << 6; + dispinfo[i].tw = (pd->DW + 1) / magh; + dispinfo[i].th = (pd->DH + 1) / magv; + dispinfo[i].psm = pfb->PSM; + + // hack!! + // 2 * dispinfo[i].tw / dispinfo[i].th <= 1, metal slug 4 + if( bInterlace && 2 * dispinfo[i].tw / dispinfo[i].th <= 1 && !(g_GameSettings&GAME_INTERLACE2X) ) { + dispinfo[i].th >>= 1; + } + } + + //int dispwidth = max(dispinfo[0].tw, dispinfo[1].tw), dispheight = max(dispinfo[0].th, dispinfo[1].th); + + // hack!, CMOD != 3, gradius +// if( SMODE2->INT && SMODE2->FFMD && SMODE1->CMOD == 3 && dispwidth <= 320) +// dispwidth *= 2; + + // hack! makai + //if( !bInterlace && dispheight * 2 < dispwidth ) dispheight *= 2; + + // start from the last circuit + for(int i = !PMODE->SLBG; i >= 0; --i) { + + tex0Info& texframe = dispinfo[i]; + if( texframe.th <= 1 ) + continue; + + GSRegDISPFB* pfb = i ? DISPFB2 : DISPFB1; + GSRegDISPLAY* pd = i ? DISPLAY2 : DISPLAY1; + + DXVEC4 v, valpha; + + if( bInterlace ) { + + texframe.th >>= 1; + + // interlace mode + pd3dDevice->SetTexture(SAMP_INTERLACE, CreateInterlaceTex(2*texframe.th)); + + if( interlace == (conf.interlace&1) ) { + // pass if odd + valpha.z = 1.0f; + valpha.w = -0.4999f; + } + else { + // pass if even + valpha.z = -1.0f; + valpha.w = 0.5001f; + } + } + else { + + if( SMODE2->INT && SMODE2->FFMD ) { + texframe.th >>= 1; + } + + // always pass interlace test + valpha.z = 0; + valpha.w = 1; + } + + int bpp = 4; + if( texframe.psm == 0x12 ) bpp = 3; + else if( texframe.psm & 2 ) bpp = 2; + + // get the start and end addresses of the buffer + int start, end; + GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); + + if( i == 0 ) { + // setup right blending + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); + + if( PMODE->MMOD ) { + SETRS(D3DRS_BLENDFACTOR, D3DCOLOR_ARGB(0x80, PMODE->ALP, PMODE->ALP, PMODE->ALP)); + SETRS(D3DRS_SRCBLEND, D3DBLEND_BLENDFACTOR); + SETRS(D3DRS_DESTBLEND, D3DBLEND_INVBLENDFACTOR); + } + else { + SETRS(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + SETRS(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + } + + SETRS(D3DRS_SRCBLENDALPHA, PMODE->AMOD ? D3DBLEND_ZERO : D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, PMODE->AMOD? D3DBLEND_ONE : D3DBLEND_ZERO); + } + + if( bUsingStencil ) { + SETRS(D3DRS_STENCILWRITEMASK, 1<SetPixelShader(ppsCRTC24[bInterlace]); + valpha.x = 0; + valpha.y = 1; + SETCONSTF(GPU_ONECOLOR, valpha); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + continue; + } + + // first render the current render targets, then from ptexMem + if( texframe.psm == 1 ) { + valpha.x = 0; + valpha.y = 1; + } + else { + valpha.x = 1; + valpha.y = 0; + } + + SETCONSTF(GPU_ONECOLOR, valpha); + + BOOL bSkip = 0; + BOOL bResolveTargs = 1; + + //s_mapFrameHeights[s_nCurFrameMap][texframe.tbp0] = texframe.th; + list listTargs; + + s_RTs.GetTargs(start, end, listTargs); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ) { + + CRenderTarget* ptarg = *it; + + if( ptarg->fbw == texframe.tbw && !(ptarg->status&CRenderTarget::TS_NeedUpdate) && ((256/bpp)*(texframe.tbp0-ptarg->fbp))%texframe.tbw == 0 ) { + + if( ptarg->fbp != texframe.tbp0 ) { + // look for a better target (metal slug 5) + list::iterator itbetter; + for(itbetter = listTargs.begin(); itbetter != listTargs.end(); ++itbetter ) { + if( (*itbetter)->fbp == texframe.tbp0 ) + break; + } + + if( itbetter != listTargs.end() ) { + it = listTargs.erase(it); + continue; + } + } + + static int sindex = 0; + char strtemp[25]; + sprintf(strtemp, "frames/frame%d.jpg", sindex++); +// D3DXSaveSurfaceToFile(strtemp, D3DXIFF_JPG, ptarg->psurf, NULL, NULL); +// if( g_bSaveFinalFrame ) +// D3DXSaveSurfaceToFile("frame1.tga", D3DXIFF_TGA, ptarg->psurf, NULL, NULL); + + int dby = pfb->DBY; + int movy = 0; + + // determine the rectangle to render + if( ptarg->fbp < texframe.tbp0 ) { + dby += (256/bpp)*(texframe.tbp0-ptarg->fbp)/texframe.tbw; + } + else if( ptarg->fbp > texframe.tbp0 ) { + dby -= (256/bpp)*(ptarg->fbp-texframe.tbp0)/texframe.tbw; + + if( dby < 0 ) { + movy = -dby; + dby = 0; + } + } + + int dh = min(ptarg->fbh - dby, texframe.th-movy); + + if( dh >= 64 ) { + + if( ptarg->fbh - dby < texframe.th-movy && !bUsingStencil ) { + + if( !bUsingStencil ) { + pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1, 0); + } + bUsingStencil = 1; + SETRS(D3DRS_STENCILENABLE, TRUE); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL); + SETRS(D3DRS_STENCILREF, 3); + SETRS(D3DRS_STENCILWRITEMASK, 1<fbh; + + // tex coords + v = DXVEC4(fiw*(float)texframe.tw, fih*(float)(dh), fiw*(float)(pfb->DBX), fih*((float)dby-0.5f)); + SETCONSTF(GPU_BITBLTTEX, v); + + // dest rect + v.x = 1; + v.y = dh/(float)texframe.th; + v.z = 0; + v.w = 1-v.y; + + if( movy > 0 ) + v.w -= movy/(float)texframe.th; + + if (bInterlace && interlace == (conf.interlace&1) ) { + // move down by 1 pixel + v.w += 1.0f / (float)dh; + } + + AdjustTransToAspect(v, (conf.options&GSOPTION_WIDESCREEN)?960:640, (conf.options&GSOPTION_WIDESCREEN)?540:480); + SETCONSTF(GPU_BITBLTPOS, v); + + // use GPU_INVTEXDIMS to store inverse texture dims + v.x = fiw; + v.y = fih; + v.z = 0; + SETCONSTF(GPU_INVTEXDIMS, v); + + // inside vb[0]'s target area, so render that region only + pd3dDevice->SetTexture(SAMP_FINAL, ptarg->ptex); + pd3dDevice->SetPixelShader(ppsCRTCTarg[bInterlace]); + + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + + if( abs(dh - (int)texframe.th) <= 1 ) { + bSkip = 1; + break; + } + if( abs(dh - (int)ptarg->fbh) <= 1 ) { + it = listTargs.erase(it); + continue; + } + } + } + + ++it; + } + + if( !bSkip ) { + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) + (*it)->Resolve(); + + // context has to be 0 + SetTexVariablesInt(0, 2, texframe, g_MemTargs.GetMemoryTarget(texframe, 1), 1); + + if( g_bSaveFinalFrame ) + SaveTex(&texframe, g_bSaveFinalFrame-1>0); + + // finally render from the memory (note that the stencil buffer will keep previous regions) + v = DXVEC4(1,1,0,0); + + if (bInterlace && interlace == (conf.interlace)) { + // move down by 1 pixel + v.w += 1.0f / (float)texframe.th; + } + + AdjustTransToAspect(v, (conf.options&GSOPTION_WIDESCREEN)?960:640, (conf.options&GSOPTION_WIDESCREEN)?540:480); + SETCONSTF(GPU_BITBLTPOS, v); + + v = DXVEC4(texframe.tw,texframe.th,-0.5f,-0.5f); + SETCONSTF(GPU_BITBLTTEX, v); + + // use GPU_INVTEXDIMS to store inverse texture dims + v.x = 1.0f / (float)texframe.tw; + v.y = 1.0f / (float)texframe.th; + v.z = 0;//-0.5f * v.x; + v.w = -0.5f * v.y; + SETCONSTF(GPU_INVTEXDIMS, v); + + pd3dDevice->SetPixelShader(ppsCRTC[bInterlace]); + pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + } + } + + if(1) {// || !bInterlace) { + s_bBeginScene = FALSE; + + ProcessMessages(); + + if( g_bMakeSnapshot ) { + RECT rctext; + char str[64]; + rctext.left = 200; rctext.top = 15; + sprintf(str, "ZeroGS %d.%d.%d - %.1f fps %s", revision, build, minor, fFPS, s_frameskipping?" - frameskipping":""); + + pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); + rctext.left += 1; + rctext.top += 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); + rctext.left -= 1; + rctext.top -= 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffc0ffff); + pSprite->End(); + } + + if( g_bDisplayFPS ) { + RECT rctext; + char str[64]; + rctext.left = 10; rctext.top = 10; + sprintf(str, "%.1f fps", fFPS); + + pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_SORT_TEXTURE); + rctext.left += 1; + rctext.top += 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xff000000); + rctext.left -= 1; + rctext.top -= 1; + pFont->DrawText(pSprite, str, -1, &rctext, DT_LEFT|DT_NOCLIP, 0xffc0ffff); + pSprite->End(); + } + + pd3dDevice->EndScene(); + if( pd3dDevice->Present(NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST ) { + // device is lost, need to recreate + DEBUG_LOG("device lost\n"); + g_bIsLost = TRUE; + Reset(); + return; + } + + if( conf.options & GSOPTION_WIREFRAME ) { + // clear all targets + s_nWireframeCount = 1; + } + + if( g_bMakeSnapshot ) { + + if( SUCCEEDED(D3DXSaveSurfaceToFile(strSnapshot != ""?strSnapshot.c_str():"temp.jpg", (conf.options&GSOPTION_BMPSNAP)?D3DXIFF_BMP:D3DXIFF_JPG, psurfOrgTarg, NULL, NULL)) ) { + char str[255]; + sprintf(str, "saved %s\n", strSnapshot.c_str()); + AddMessage(str, 500); + } + g_bMakeSnapshot = 0; + } + + if( s_avicapturing ) { + CaptureFrame(); + } + + if( s_nNewWidth >= 0 && s_nNewHeight >= 0 && !g_bIsLost ) { + Reset(); + ChangeDeviceSize(s_nNewWidth, s_nNewHeight); + s_nNewWidth = s_nNewHeight = -1; + } + + // switch the fbp lists +// s_nCurFBPSet ^= 1; +// s_setFBP[s_nCurFBPSet].clear(); + //s_nCurFrameMap ^= 1; + //s_mapFrameHeights[s_nCurFrameMap].clear(); + } + + pd3dDevice->SetTexture(SAMP_FINAL, NULL); // d3d debug complains if not + g_MemTargs.DestroyCleared(); + + for(list::iterator it = s_vecTempTextures.begin(); it != s_vecTempTextures.end(); ++it) + (*it)->Release(); + s_vecTempTextures.clear(); + + if( EXTWRITE->WRITE&1 ) { + WARN_LOG("EXTWRITE\n"); + ExtWrite(); + EXTWRITE->WRITE = 0; + } + + if( conf.options & GSOPTION_WIREFRAME ) SETRS(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + SETRS(D3DRS_SCISSORTESTENABLE, TRUE); + + if( icurctx >= 0 ) { + vb[icurctx].bVarsSetTarg = FALSE; + vb[icurctx].bVarsTexSync = FALSE; + vb[0].bVarsTexSync = FALSE; + } + + // statistics + if( s_nWriteDepthCount > 0 ) { + assert( conf.mrtdepth ); + if( --s_nWriteDepthCount <= 0 ) { + s_bWriteDepth = FALSE; + } + } + + if( s_nWriteDestAlphaTest > 0 ) { + if( --s_nWriteDestAlphaTest <= 0 ) { + s_bDestAlphaTest = FALSE; + } + } + + if( g_GameSettings & GAME_AUTORESET ) { + s_nResolveCounts[s_nCurResolveIndex] = s_nResolved; + s_nCurResolveIndex = (s_nCurResolveIndex+1)%ARRAYSIZE(s_nResolveCounts); + + int total = 0; + for(int i = 0; i < ARRAYSIZE(s_nResolveCounts); ++i) total += s_nResolveCounts[i]; + + if( total / ARRAYSIZE(s_nResolveCounts) > 3 ) { + if( s_nLastResolveReset > (int)(fFPS * 8) ) { + // reset + DEBUG_LOG("ZeroGS: video mem reset\n"); + s_nLastResolveReset = 0; + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + } + } + + s_nLastResolveReset++; + } + + if( s_nResolved > 8 ) s_nResolved = 2; + else if( s_nResolved > 0 ) --s_nResolved; + + if( g_nDepthUsed > 0 ) --g_nDepthUsed; + + s_ClutResolve = 0; + s_PSM8Resolve = 0; + g_nDepthUpdateCount = 0; + + maxmin = 608; +} + +////////////////////////// +// Internal Definitions // +////////////////////////// + +__forceinline void MOVZ(VertexGPU *p, u32 gsz, const VB& curvb) +{ + p->z = curvb.zprimmask==0xffff?min((u32)0xffff, gsz):gsz; +} + +__forceinline void MOVFOG(VertexGPU *p, Vertex gsf) +{ + p->f = ((s16)(gsf).f<<7)|0x7f; +} + +__forceinline void SET_VERTEX(VertexGPU *p, int Index, const VB& curvb) +{ + int index = Index; + + p->x = (((int)gs.gsvertex[index].x - curvb.offset.x)>>1)&0xffff; + p->y = (((int)gs.gsvertex[index].y - curvb.offset.y)>>1)&0xffff; + + /*x = ((int)gs.gsvertex[index].x - curvb.offset.x); + y = ((int)gs.gsvertex[index].y - curvb.offset.y); + p.x = (x&0x7fff) | (x < 0 ? 0x8000 : 0); + p.y = (y&0x7fff) | (y < 0 ? 0x8000 : 0);*/ + + p->f = ((s16)gs.gsvertex[index].f<<7)|0x7f; + MOVZ(p, gs.gsvertex[index].z, curvb); + p->rgba = prim->iip ? gs.gsvertex[index].rgba : gs.rgba; + + if ((g_GameSettings & GAME_TEXAHACK) && !(p->rgba&0xffffff)) + p->rgba = 0; + if (prim->tme ) + { + if( prim->fst ) + { + p->s = (float)gs.gsvertex[index].u * fiTexWidth[prim->ctxt]; + p->t = (float)gs.gsvertex[index].v * fiTexHeight[prim->ctxt]; + p->q = 1; + } + else + { + p->s = gs.gsvertex[index].s; + p->t = gs.gsvertex[index].t; + p->q = gs.gsvertex[index].q; + } + } +} + +#define OUTPUT_VERT(fn, vert, id) { \ + fn("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)\n", id==0?'*':' ', id, prim->prim, vert.x/8, vert.y/8, vert.z, vert.f/128, \ + vert.rgba, Clamp(vert.s, -10, 10), Clamp(vert.t, -10, 10), Clamp(vert.q, -10, 10)); \ +} \ + + +void ZeroGS::KickPoint() +{ + assert( gs.primC >= 1 ); + + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH) + Flush(prim->ctxt); + + curvb.Lock(); + int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); + + VertexGPU* p = curvb.pbuf+curvb.dwCount; + SET_VERTEX(&p[0], last, curvb); + curvb.dwCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); +#endif +} + +void ZeroGS::KickLine() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH/2 ) + Flush(prim->ctxt); + + curvb.Lock(); + int next = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); + + VertexGPU* p = curvb.pbuf+curvb.dwCount*2; + SET_VERTEX(&p[0], next, curvb); + SET_VERTEX(&p[1], last, curvb); + + curvb.dwCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickTriangle() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH/3 ) + Flush(prim->ctxt); + + curvb.Lock(); + VertexGPU* p = curvb.pbuf+curvb.dwCount*3; + SET_VERTEX(&p[0], 0, curvb); + SET_VERTEX(&p[1], 1, curvb); + SET_VERTEX(&p[2], 2, curvb); + + curvb.dwCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +void ZeroGS::KickTriangleFan() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if( curvb.dwCount >= POINT_BUFFERFLUSH/3 ) + Flush(prim->ctxt); + + curvb.Lock(); + VertexGPU* p = curvb.pbuf+curvb.dwCount*3; + SET_VERTEX(&p[0], 0, curvb); + SET_VERTEX(&p[1], 1, curvb); + SET_VERTEX(&p[2], 2, curvb); + + curvb.dwCount++; + + // add 1 to skip the first vertex + if( gs.primIndex == gs.nTriFanVert ) + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +__forceinline void SetKickVertex(VertexGPU *p, Vertex v, int next, const VB& curvb) +{ + SET_VERTEX(p, next, curvb); + MOVZ(p, v.z, curvb); + MOVFOG(p, v); +} + +void ZeroGS::KickSprite() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( !(g_GameSettings&GAME_DOPARALLELCTX) && vb[!prim->ctxt].dwCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].dwCount == 0 ); + Flush(!prim->ctxt); + } + + if (curvb.dwCount >= POINT_BUFFERFLUSH/3) Flush(prim->ctxt); + + curvb.Lock(); + int next = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAYSIZE(gs.gsvertex); + + // sprite is too small and AA shows lines (tek4) + if( s_AAx ) + { + gs.gsvertex[last].x += 4; + if (s_AAy) gs.gsvertex[last].y += 4; + } + + // might be bad sprite (KH dialog text) + //if( gs.gsvertex[next].x == gs.gsvertex[last].x || gs.gsvertex[next].y == gs.gsvertex[last].y ) + // return; + + VertexGPU* p = curvb.pbuf+curvb.dwCount*3; + + SetKickVertex(&p[0], gs.gsvertex[last], next, curvb); + SetKickVertex(&p[3], gs.gsvertex[last], next, curvb); + SetKickVertex(&p[1], gs.gsvertex[last], last, curvb); + SetKickVertex(&p[4], gs.gsvertex[last], last, curvb); + + if (g_MaxRenderedHeight < p[0].y) g_MaxRenderedHeight = p[0].y; + if (g_MaxRenderedHeight < p[1].y) g_MaxRenderedHeight = p[1].y; + + SetKickVertex(&p[2], gs.gsvertex[last], next, curvb); + p[2].s = p[1].s; + p[2].x = p[1].x; + + SetKickVertex(&p[5], gs.gsvertex[last], last, curvb); + p[5].s = p[0].s; + p[5].x = p[0].x; + + curvb.dwCount += 2; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickDummy() +{ + //GREG_LOG("Kicking bad primitive: %.8x\n", *(u32*)prim); +} + +__forceinline void ZeroGS::RenderFBA(const VB& curvb) +{ + // add fba to all pixels + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_ZERO); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + SETRS(D3DRS_STENCILREF, STENCIL_FBA); + + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1, NULL); + } + + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + SETRS(D3DRS_ALPHAREF, 0xff); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + SETCONSTF(GPU_ONECOLOR, v); + + DRAW(); + + if( !curvb.test.ate ) + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + else { + SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curvb.test.atst]); + SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curvb.test.aref) : curvb.test.aref); + } + + // reset (not necessary) + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + assert( curvb.pdepth != NULL ); + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } + SETRS(D3DRS_ZENABLE, curvb.test.zte); +} + +__forceinline void ZeroGS::RenderAlphaTest(const VB& curvb) +{ + if( !g_bUpdateStencil ) return; + + if( curvb.test.ate ) { + if( curvb.test.afail == 1 ) SETRS(D3DRS_ALPHATESTENABLE, FALSE); + } + + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0); + + DXVEC4 v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + SETCONSTF(GPU_ONECOLOR, v); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1,NULL); + } + + // or a 1 to the stencil buffer wherever alpha passes + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + + SETRS(D3DRS_STENCILENABLE, TRUE); + + if( !s_bDestAlphaTest ) { + // clear everything + SETRS(D3DRS_STENCILREF, 0); + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + DRAW(); + + if( curvb.test.ate && curvb.test.afail != 1 && USEALPHATESTING) + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + } + + if( curvb.test.ate && curvb.test.atst>1 && curvb.test.aref > 0x80) { + v.x = 1; v.y = 1; v.z = 0; v.w = 0; + SETCONSTF(GPU_ONECOLOR, v); + SETRS(D3DRS_ALPHAREF, curvb.test.aref); + } + + SETRS(D3DRS_STENCILREF, STENCIL_SPECIAL); + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_SPECIAL); + SETRS(D3DRS_ZENABLE, FALSE); + + DRAW(); + + if( curvb.test.zte ) SETRS(D3DRS_ZENABLE, TRUE); + SETRS(D3DRS_ALPHATESTENABLE, 0); + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + // set rt next level + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } +} + +__forceinline void ZeroGS::RenderStencil(const VB& curvb, DWORD dwUsingSpecialTesting) +{ + //NOTE: This stencil hack for dest alpha testing ONLY works when + // the geometry in one DrawPrimitive call does not overlap + + // mark the stencil buffer for the new data's bits (mark 4 if alpha is >= 0xff) + // mark 4 if a pixel was written (so that the stencil buf can be changed with new values) + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_PIXELWRITE); + + dwStencilMask = (curvb.test.date?STENCIL_ALPHABIT:0)|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + SETRS(D3DRS_STENCILMASK, dwStencilMask); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, dwStencilMask ? D3DCMP_EQUAL : D3DCMP_ALWAYS); + + dwStencilRef = curvb.test.date*curvb.test.datm|STENCIL_PIXELWRITE|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + SETRS(D3DRS_STENCILREF, dwStencilRef); +} + +__forceinline void ZeroGS::ProcessStencil(const VB& curvb) +{ + assert( !curvb.fba.fba ); + + // set new alpha bit + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_ALPHABIT); + SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_PIXELWRITE); + + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, 0); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1, NULL); + } + + SETRS(D3DRS_ALPHATESTENABLE, 0); + + pd3dDevice->SetPixelShader(ppsOne); + DRAW(); + + // process when alpha >= 0xff + SETRS(D3DRS_STENCILREF, STENCIL_PIXELWRITE|STENCIL_FBA|STENCIL_ALPHABIT); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + DRAW(); + + // clear STENCIL_PIXELWRITE bit + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + SETRS(D3DRS_STENCILREF, 0); + + DRAW(); + + // restore state + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + if( curvb.test.ate && USEALPHATESTING) + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL ); + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } + + SETRS(D3DRS_ZENABLE, curvb.test.zte); + + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); +} + +__forceinline void ZeroGS::ProcessFBA(const VB& curvb) +{ + if( (curvb.frame.fbm&0x80000000) ) return; + + // add fba to all pixels that were written and alpha was less than 0xff + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_ALPHABIT); + SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + SETRS(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + SETRS(D3DRS_STENCILREF, STENCIL_FBA|STENCIL_PIXELWRITE|STENCIL_ALPHABIT); + + SETRS(D3DRS_ZENABLE, FALSE); + SETRS(D3DRS_ZWRITEENABLE, FALSE); + SETRS(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0); + else pd3dDevice->SetRenderTarget(1, NULL); + } + + // processes the pixels with ALPHA < 0x80*2 + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL); + SETRS(D3DRS_ALPHAREF, 0xff); + + // add 1 to dest + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); + + float f = 1; + SETCONSTF(GPU_ONECOLOR, &f); + pd3dDevice->SetPixelShader(ppsOne); + + DRAW(); + + SETRS(D3DRS_ALPHATESTENABLE, FALSE); + + // reset bits + SETRS(D3DRS_STENCILWRITEMASK, STENCIL_CLEAR); + SETRS(D3DRS_STENCILMASK, STENCIL_PIXELWRITE|STENCIL_FBA); + SETRS(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO); + SETRS(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + SETRS(D3DRS_STENCILFUNC, D3DCMP_GREATER); + SETRS(D3DRS_STENCILREF, 0); + + DRAW(); + + if( curvb.test.atst && USEALPHATESTING) { + SETRS(D3DRS_ALPHATESTENABLE, TRUE); + SETRS(D3DRS_ALPHAFUNC, g_dwAlphaCmp[curvb.test.atst]); + SETRS(D3DRS_ALPHAREF, b2XAlphaTest ? min(255,2 * curvb.test.aref) : curvb.test.aref); + } + + // restore (SetAlphaVariables) + if( !bNeedAlphaColor ) SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);//(bNeedBlendFactorInAlpha ? D3DBLEND_ZERO : D3DBLEND_ONE)); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO);//bNeedBlendFactorInAlpha ? D3DBLEND_ONE : D3DBLEND_ZERO); + if(bNeedAlphaColor && vAlphaBlendColor.y<0) SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_REVSUBTRACT); + + // reset (not necessary) + SETRS(D3DRS_COLORWRITEENABLE, s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) { + SETRS(D3DRS_ZWRITEENABLE, TRUE); + + if( s_bWriteDepth ) { + if( bIndepWriteMasks ) SETRS(D3DRS_COLORWRITEENABLE1, 0xf); + else pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + } + } + SETRS(D3DRS_ZENABLE, curvb.test.zte); +} + +inline void ZeroGS::SetContextTarget(int context) +{ + VB& curvb = vb[context]; + + if( curvb.prndr == NULL ) + curvb.prndr = s_RTs.GetTarg(curvb.frame, 0, GET_MAXHEIGHT(curvb.gsfb.fbp, curvb.gsfb.fbw, curvb.gsfb.psm)); + + // make sure targets are valid + if( curvb.pdepth == NULL ) { + frameInfo f; + f.fbp = curvb.zbuf.zbp; + f.fbw = curvb.frame.fbw; + f.fbh = curvb.prndr->fbh; + f.psm = curvb.zbuf.psm; + f.fbm = 0; + curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); + } + + assert( curvb.prndr != NULL && curvb.pdepth != NULL ); + assert( curvb.pdepth->fbh == curvb.prndr->targheight ); + +// if( curvb.pdepth->fbh != curvb.prndr->fbh ) { +// +// s_DepthRTs.DestroyTarg(curvb.pdepth); +// ERROR_LOG("ZeroGS: render and depth heights different: %x %x\n", curvb.prndr->fbh, curvb.pdepth->fbh); +// frameInfo f; +// f.fbp = curvb.zbuf.zbp; +// f.fbw = curvb.frame.fbw; +// f.fbh = curvb.prndr->fbh; +// f.psm = curvb.zbuf.psm; +// f.fbm = 0; +// curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| +// (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); +// } + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + BOOL bSetTarg = 1; + if( curvb.pdepth->status & CRenderTarget::TS_NeedUpdate ) { + + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + + // don't update if virtual + curvb.pdepth->Update(context, curvb.prndr); + bSetTarg = 0; + } + + if( curvb.prndr->status & CRenderTarget::TS_NeedUpdate ) { + + if( s_bWriteDepth ) { + if( bSetTarg ) { + pd3dDevice->SetRenderTarget(1, curvb.pdepth->psurf); + pd3dDevice->SetDepthStencilSurface(curvb.pdepth->pdepth); + } + } + else if( bSetTarg ) + pd3dDevice->SetDepthStencilSurface(curvb.pdepth->pdepth); + + curvb.prndr->Update(context, curvb.pdepth); + // note, targ already set + } + else { + + //if( (vb[0].prndr != vb[1].prndr && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg ) + pd3dDevice->SetRenderTarget(0, curvb.prndr->psurf); + //if( bSetTarg && ((vb[0].pdepth != vb[1].pdepth && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg) ) + curvb.pdepth->SetDepthTarget(); + + if( s_ptexCurSet[0] == curvb.prndr->ptex ) { + s_ptexCurSet[0] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY0, NULL); + } + if( s_ptexCurSet[1] == curvb.prndr->ptex ) { + s_ptexCurSet[1] = NULL; + pd3dDevice->SetTexture(SAMP_MEMORY1, NULL); + } + + curvb.prndr->SetViewport(); + } + + curvb.prndr->SetTarget(curvb.frame.fbp, curvb.scissor, context); + + if( (curvb.zbuf.zbp-curvb.pdepth->fbp) != (curvb.frame.fbp - curvb.prndr->fbp) && curvb.test.zte ) { + WARN_LOG("frame and zbuf not aligned\n"); + } + + curvb.bVarsSetTarg = TRUE; + if( vb[!context].prndr != curvb.prndr ) + vb[!context].bVarsSetTarg = FALSE; + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + assert( curvb.pdepth == NULL || !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); +} + +void ZeroGS::SetTexVariables(int context) +{ + if( !vb[context].curprim.tme ) { + return; + } + + assert( !vb[context].bNeedTexCheck ); + + DXVEC4 v, v2; + tex0Info& tex0 = vb[context].tex0; + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + if( !vb[context].bTexConstsSync ) { + // alpha and texture highlighting + DXVEC4 valpha, valpha2; + + // if clut, use the frame format + int psm = tex0.psm; + if( PSMT_ISCLUT(tex0.psm) ) psm = tex0.cpsm; + + int nNeedAlpha = (psm == 1 || psm == 2 || psm == 10); + + DXVEC4 vblack; + vblack.x = vblack.y = vblack.z = vblack.w = 10; + + switch(tex0.tfx) { + case 0: + valpha.z = 0; valpha.w = 0; + valpha2.x = 0; valpha2.y = 0; + valpha2.z = 2; valpha2.w = 1; + + break; + case 1: + valpha.z = 0; valpha.w = 1; + valpha2.x = 1; valpha2.y = 0; + valpha2.z = 0; valpha2.w = 0; + + break; + case 2: + valpha.z = 1; valpha.w = 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + + case 3: + valpha.z = 1; valpha.w = tex0.tcc ? 0.0f : 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + default: __assume(0); + } + + if( tex0.tcc ) { + + if( tex0.tfx == 1 ) { + //mode.x = 10; + valpha.z = 0; valpha.w = 0; + valpha2.x = 1; valpha2.y = 1; + valpha2.z = 0; valpha2.w = 0; + } + + if( nNeedAlpha ) { + + if( tex0.tfx == 0 ) { + // make sure alpha is mult by two when the output is Cv = Ct*Cf + valpha.x = 2*gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = 2*gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + else { + valpha.x = gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + + // need black detection + if( gs.texa.aem && psm == PSMCT24 ) + vblack.w = 0; + } + else { + if( tex0.tfx == 0 ) { + valpha.x = 0; + valpha.y = 2; + } + else { + valpha.x = 0; + valpha.y = 1; + } + } + } + else { + + // reset alpha to color + valpha.x = valpha.y = 0; + valpha.w = 1; + } + + SETCONSTF(GPU_TEXALPHA0+context, &valpha); + SETCONSTF(GPU_TEXALPHA20+context, &valpha2); + if( tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S) ) + SETCONSTF(GPU_TESTBLACK0+context, &vblack); + + // clamp relies on texture width + { + clampInfo* pclamp = &ZeroGS::vb[context].clamp; + DXVEC4 v, v2; + v.x = v.y = 0; + LPD3DTEX* ptex = ZeroGS::vb[context].ptexClamp; + ptex[0] = ptex[1] = NULL; + + float fw = ZeroGS::vb[context].tex0.tw; + float fh = ZeroGS::vb[context].tex0.th; + + switch(pclamp->wms) { + case 0: + v2.x = -1e10; v2.z = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.x = 0; v2.z = 1-0.5f/fw; + break; + case 2: // reg pclamp + v2.x = (pclamp->minu+0.5f)/fw; v2.z = (pclamp->maxu-0.5f)/fw; + break; + + case 3: // region rep x + v.x = 0.9999f; + v.z = fw / (float)GPU_TEXMASKWIDTH; + v2.x = (float)GPU_TEXMASKWIDTH / fw; + v2.z = pclamp->maxu / fw; + + if( pclamp->minu != g_PrevBitwiseTexX ) { + g_PrevBitwiseTexX = pclamp->minu; + ptex[0] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minu, NULL); + } + break; + + default: __assume(0); + } + + switch(pclamp->wmt) { + case 0: + v2.y = -1e10; v2.w = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.y = 0; v2.w = 1-0.5f/fh; + break; + case 2: // reg pclamp + v2.y = (pclamp->minv+0.5f)/fh; v2.w = (pclamp->maxv-0.5f)/fh; + break; + + case 3: // region rep y + v.y = 0.9999f; + v.w = fh / (float)GPU_TEXMASKWIDTH; + v2.y = (float)GPU_TEXMASKWIDTH / fh; + v2.w = pclamp->maxv / fh; + + if( pclamp->minv != g_PrevBitwiseTexY ) { + g_PrevBitwiseTexY = pclamp->minv; + ptex[1] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minv, ptex[0]); + } + break; + + default: __assume(0); + } + + SETCONSTF(GPU_TEXWRAPMODE0+context, v); + SETCONSTF(GPU_CLAMPEXTS0+context, v2); + } + + vb[context].bTexConstsSync = TRUE; + } + + if(s_bTexFlush ) { + if( PSMT_ISCLUT(tex0.psm) ) + texClutWrite(context); + else + s_bTexFlush = FALSE; + } +} + +void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, CMemoryTarget* pmemtarg, int force) +{ + DXVEC4 v; + assert( pmemtarg != NULL ); + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + if( bilinear > 1 || (bilinear && conf.bilinear)) { + v.x = (float)fw; + v.y = (float)fh; + v.z = 1.0f / (float)fw; + v.w = 1.0f / (float)fh; + SETCONSTF(GPU_REALTEXDIMS0+context, v); + } + + if( m_Blocks[tex0.psm].bpp == 0 ) { + ERROR_LOG("ZeroGS: Undefined tex psm 0x%x!\n", tex0.psm); + return; + } + + const BLOCK& b = m_Blocks[tex0.psm]; + + float fbw = (float)tex0.tbw; + + v.x = b.vTexDims.x * fw; + v.y = b.vTexDims.y * fh; + v.z = (float)BLOCK_TEXWIDTH*(0.002f / 64.0f + 0.01f/128.0f); + v.w = (float)BLOCK_TEXHEIGHT*0.2f/512.0f; + + if( bilinear > 1 || (conf.bilinear && bilinear) ) { + v.x *= 1/128.0f; + v.y *= 1/512.0f; + v.z *= 1/128.0f; + v.w *= 1/512.0f; + } + SETCONSTF(GPU_TEXDIMS0+context, v); + + float g_fitexwidth = g_fiGPU_TEXWIDTH/(float)pmemtarg->widthmult; + float g_texwidth = GPU_TEXWIDTH*(float)pmemtarg->widthmult; + + SETCONSTF(GPU_TEXBLOCK0+context, &b.vTexBlock.x); + + float fpage = tex0.tbp0*(64.0f*g_fitexwidth) + 0.05f * g_fitexwidth; + float fpageint = floorf(fpage); + int starttbp = (int)fpage; + + // 2048 is number of words to span one page + float fblockstride = (2048.0f /(float)(g_texwidth*BLOCK_TEXWIDTH)) * b.vTexDims.x * fbw; + assert( fblockstride >= 1.0f ); + + v.x = (float)(2048 * g_fitexwidth); + v.y = fblockstride; + v.z = g_fBlockMult/(float)pmemtarg->widthmult; + v.w = fpage-fpageint; + + if( g_fBlockMult > 1 ) { + // make sure to divide by mult (since the G16R16 texture loses info) + v.z *= b.bpp * (1/32.0f); + } + + SETCONSTF(GPU_TEXOFFSET0+context, v); + + v.y = (float)1.0f / (float)((pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult); + v.x = (fpageint-(float)pmemtarg->realy/(float)pmemtarg->widthmult+0.5f)*v.y; + + SETCONSTF(GPU_PAGEOFFSET0+context, v); + + if( force ) { + pd3dDevice->SetTexture(SAMP_MEMORY0+context, pmemtarg->ptex); + s_ptexCurSet[context] = pmemtarg->ptex; + } + else s_ptexNextSet[context] = pmemtarg->ptex; + vb[context].pmemtarg = pmemtarg; + + vb[context].bVarsTexSync = FALSE; +} + +// assumes texture factor is unused +#define SET_ALPHA_COLOR_FACTOR(sign) { \ + switch(a.c) { \ + case 0: \ + bNeedAlphaColor = 1; \ + vAlphaBlendColor.y = (sign) ? 2.0f*255.0f/256.0f : -2.0f*255.0f/256.0f; \ + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); \ + SETRS(D3DRS_BLENDOPALPHA, (sign) ? D3DBLENDOP_ADD : D3DBLENDOP_REVSUBTRACT); \ + break; \ + case 1: \ + /* if in 24 bit mode, dest alpha should be one */ \ + switch(vb[icurctx].prndr->psm&0xf) { \ + case 0: \ + bDestAlphaColor = (a.d!=2)&&((a.a==a.d)||(a.b==a.d)); \ + break; \ + case 1: \ + /* dest alpha should be one */ \ + bDestAlphaColor = 2; \ + break; \ + /* default: 16bit surface, so returned alpha is ok */ \ + } \ + break; \ + \ + case 2: \ + bNeedBlendFactorInAlpha = 1; /* should disable alpha channel writing */ \ + bNeedAlphaColor = 1; \ + vAlphaBlendColor.y = 0; \ + vAlphaBlendColor.w = (sign) ? (float)a.fix * (2.0f/255.0f) : (float)a.fix * (-2.0f/255.0f); \ + usec = 0; /* change so that alpha comes from source*/ \ + break; \ + } \ +} \ + +//if( a.fix <= 0x80 ) { \ +// dwTemp = (a.fix*2)>255?255:(a.fix*2); \ +// dwTemp = dwTemp|(dwTemp<<8)|(dwTemp<<16)|0x80000000; \ +// DEBUG_LOG("bfactor: %8.8x\n", dwTemp); \ +// SETRS(D3DRS_BLENDFACTOR, dwTemp); \ +// } \ +// else { \ + +void ZeroGS::ResetAlphaVariables() +{ + s_bAlphaSet = FALSE; +} + +void ZeroGS::SetAlphaVariables(const alphaInfo& a) +{ + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); // always set + + if( s_bAlphaSet && a.abcd == s_alphaInfo.abcd && a.fix == s_alphaInfo.fix ) { + return; + } + + // TODO: negative color when not clamping turns to positive??? + g_vars._bAlphaState = 0; // set all to zero + bNeedBlendFactorInAlpha = 0; + b2XAlphaTest = 1; + DWORD dwTemp = 0xffffffff; + + // default + SETRS(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + SETRS(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO); + SETRS(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); + + s_alphaInfo = a; + + vAlphaBlendColor = DXVEC4(1,2*255.0f/256.0f,0,0); + DWORD usec = a.c; + + if( a.a == a.b ) { // just d remains + SETRS(D3DRS_ALPHABLENDENABLE, USEALPHABLENDING); + + if( a.d == 0 ) { + SETRS(D3DRS_ALPHABLENDENABLE, 0); + } + else { + SETRS(D3DRS_DESTBLEND, a.d == 1 ? D3DBLEND_ONE : D3DBLEND_ZERO); + SETRS(D3DRS_SRCBLEND, D3DBLEND_ZERO); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + } + + goto EndSetAlpha; + } + else if( a.d == 2 ) { // zero + + if( a.a == 2 ) { + // zero all color + SETRS(D3DRS_SRCBLEND, D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, D3DBLEND_ZERO); + goto EndSetAlpha; + } + else if( a.b == 2 ) { + //b2XAlphaTest = 1; + + SET_ALPHA_COLOR_FACTOR(1); + + if( bDestAlphaColor == 2 ) { + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_ONE : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : D3DBLEND_ONE); + } + else { + if( bNeedAlphaColor ) bAlphaClamping = 2; + + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendalpha[usec] : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : blendalpha[usec]); + } + + goto EndSetAlpha; + } + + // nothing is zero, so must do some real blending + //b2XAlphaTest = 1; + bAlphaClamping = 3; + + SET_ALPHA_COLOR_FACTOR(1); + + SETRS(D3DRS_BLENDOP, a.a == 0 ? D3DBLENDOP_SUBTRACT : D3DBLENDOP_REVSUBTRACT); + SETRS(D3DRS_SRCBLEND, bDestAlphaColor == 2 ? D3DBLEND_ONE : blendalpha[usec]); + SETRS(D3DRS_DESTBLEND, bDestAlphaColor == 2 ? D3DBLEND_ONE : blendalpha[usec]); + } + else if( a.a == 2 ) { // zero + + //b2XAlphaTest = 1; + bAlphaClamping = 1; // min testing + + SET_ALPHA_COLOR_FACTOR(1); + + if( a.b == a.d ) { + // can get away with 1-A + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, (a.b == 0 && bDestAlphaColor != 2) ? blendinvalpha[usec] : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, (a.b == 0 || bDestAlphaColor == 2) ? D3DBLEND_ZERO : blendinvalpha[usec]); + } + else { + SETRS(D3DRS_BLENDOP, a.b==0 ? D3DBLENDOP_REVSUBTRACT : D3DBLENDOP_SUBTRACT); + SETRS(D3DRS_SRCBLEND, (a.b == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : D3DBLEND_ONE); + SETRS(D3DRS_DESTBLEND, (a.b == 0 || bDestAlphaColor == 2 ) ? D3DBLEND_ONE : blendalpha[usec]); + } + } + else if( a.b == 2 ) { + bAlphaClamping = 2; // max testing + + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) { + // can get away with 1+A, but need to set alpha to negative + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedAlphaColor = 1; + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : D3DBLEND_INVSRCALPHA); + } + else { + SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendinvalpha[usec] : D3DBLEND_ZERO); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_ZERO : blendinvalpha[usec]); + } + } + else { + //b2XAlphaTest = 1; + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + SETRS(D3DRS_SRCBLEND, (a.a == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : D3DBLEND_ONE); + SETRS(D3DRS_DESTBLEND, (a.a == 0 || bDestAlphaColor == 2) ? D3DBLEND_ONE : blendalpha[usec]); + } + } + else { + // all 3 components are valid! + bAlphaClamping = 3; // all testing + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) { + // can get away with 1+A, but need to set alpha to negative + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedAlphaColor = 1; + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + SETRS(D3DRS_SRCBLEND, a.a == 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? D3DBLEND_SRCALPHA : D3DBLEND_INVSRCALPHA); + } + else { + SETRS(D3DRS_SRCBLEND, a.a == 0 ? blendinvalpha[usec] : blendalpha[usec]); + SETRS(D3DRS_DESTBLEND, a.a == 0 ? blendalpha[usec] : blendinvalpha[usec]); + } + } + else { + assert(a.b == a.d); + SETRS(D3DRS_BLENDOP, D3DBLENDOP_ADD); + + if( bDestAlphaColor == 2 ) { + assert(usec==1); + + // all ones + bNeedAlphaColor = 1; + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = 1; + SETRS(D3DRS_SRCBLEND, a.a != 0 ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); + SETRS(D3DRS_DESTBLEND, a.a != 0 ? D3DBLEND_SRCALPHA : D3DBLEND_INVSRCALPHA); + } + else { + //b2XAlphaTest = 1; + SETRS(D3DRS_SRCBLEND, a.a != 0 ? blendinvalpha[usec] : blendalpha[usec]); + SETRS(D3DRS_DESTBLEND, a.a != 0 ? blendalpha[usec] : blendinvalpha[usec]); + } + } + } + +EndSetAlpha: + //b2XAlphaTest = b2XAlphaTest && bNeedAlphaColor && !bNeedBlendFactorInAlpha; + + INC_ALPHAVARS(); +} + +void ZeroGS::SetWriteDepth() +{ + if( conf.mrtdepth ) { + s_bWriteDepth = TRUE; + s_nWriteDepthCount = 4; + } +} + +BOOL ZeroGS::IsWriteDepth() +{ + return s_bWriteDepth; +} + +BOOL ZeroGS::IsWriteDestAlphaTest() +{ + return s_bWriteDepth; +} + +void ZeroGS::SetDestAlphaTest() +{ + s_bDestAlphaTest = TRUE; + s_nWriteDestAlphaTest = 4; +} + +void ZeroGS::SetFogColor(u32 fog) +{ + if( 1||gs.fogcol != fog ) { + gs.fogcol = fog; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + if( !g_bIsLost ) { + DXVEC4 v; + + // set it immediately + v.x = (gs.fogcol&0xff)/255.0f; + v.y = ((gs.fogcol>>8)&0xff)/255.0f; + v.z = ((gs.fogcol>>16)&0xff)/255.0f; + SETCONSTF(GPU_FOGCOLOR, v); + } + } +} + +void ZeroGS::ExtWrite() +{ + WARN_LOG("ExtWrite\n"); + + // use local DISPFB, EXTDATA, EXTBUF, and PMODE +// int bpp, start, end; +// tex0Info texframe; + +// bpp = 4; +// if( texframe.psm == 0x12 ) bpp = 3; +// else if( texframe.psm & 2 ) bpp = 2; +// +// // get the start and end addresses of the buffer +// GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); +} + +//////////// +// Caches // +//////////// +#ifdef __x86_64__ +extern "C" void TestClutChangeMMX(void* src, void* dst, int entries, void* pret); +#endif + +bool ZeroGS::CheckChangeInClut(u32 highdword, u32 psm) +{ + int cld = (highdword >> 29) & 0x7; + int cbp = ((highdword >> 5) & 0x3fff); + + // processing the CLUT after tex0/2 are written + switch(cld) { + case 0: return false; + case 1: break; // Seems to rarely not be 1. + // note sure about changing cbp[0,1] + case 4: return gs.cbp[0] != cbp; + case 5: return gs.cbp[1] != cbp; + + // default: load + default: break; + } + + int cpsm = (highdword >> 19) & 0xe; + int csm = (highdword >> 23) & 0x1; + + if( cpsm > 1 || csm ) + // don't support 16bit for now + return true; + + int csa = (highdword >> 24) & 0x1f; + + int entries = (psm&3)==3 ? 256 : 16; + + u64* src = (u64*)(g_pbyGSMemory + cbp*256); + u64* dst = (u64*)(g_pbyGSClut+64*csa); + + bool bRet = false; + +#ifdef __x86_64__ + TestClutChangeMMX(dst, src, entries, &bRet); +#else + int storeebx; + // do a fast test with MMX + __asm { + mov storeebx, ebx + mov edx, dst + mov ecx, src + mov ebx, entries + +Start: + movq mm0, [edx] + movq mm1, [edx+8] + pcmpeqd mm0, [ecx] + pcmpeqd mm1, [ecx+16] + + movq mm2, [edx+16] + movq mm3, [edx+24] + pcmpeqd mm2, [ecx+32] + pcmpeqd mm3, [ecx+48] + + pand mm0, mm1 + pand mm2, mm3 + movq mm4, [edx+32] + movq mm5, [edx+40] + pcmpeqd mm4, [ecx+8] + pcmpeqd mm5, [ecx+24] + + pand mm0, mm2 + pand mm4, mm5 + movq mm6, [edx+48] + movq mm7, [edx+56] + pcmpeqd mm6, [ecx+40] + pcmpeqd mm7, [ecx+56] + + pand mm0, mm4 + pand mm6, mm7 + pand mm0, mm6 + + pmovmskb eax, mm0 + cmp eax, 0xff + je Continue + mov bRet, 1 + jmp Return + +Continue: + cmp ebx, 16 + jle Return + + test ebx, 0x10 + jz AddEcx + sub ecx, 448 // go back and down one column, +AddEcx: + add ecx, 256 // go to the right block + + cmp ebx, 0x90 + jne Continue1 + add ecx, 256 // skip whole block +Continue1: + add edx, 64 + sub ebx, 16 + jmp Start + } + +Return: + __asm { + emms + mov ebx, storeebx + } +#endif + + return bRet; +} + +void ZeroGS::texClutWrite(int ctx) +{ + s_bTexFlush = 0; + if( g_bIsLost ) + return; + + tex0Info& tex0 = vb[ctx].tex0; + assert( PSMT_ISCLUT(tex0.psm) ); + + // processing the CLUT after tex0/2 are written + switch(tex0.cld) { + case 0: return; + case 1: break; // tex0.cld is usually 1. + case 2: gs.cbp[0] = tex0.cbp; break; + case 3: gs.cbp[1] = tex0.cbp; break; + // not sure about changing cbp[0,1] + case 4: + if( gs.cbp[0] == tex0.cbp ) + return; + gs.cbp[0] = tex0.cbp; + break; + case 5: + if( gs.cbp[1] == tex0.cbp ) + return; + gs.cbp[1] = tex0.cbp; + break; + default: //DEBUG_LOG("cld isn't 0-5!"); + break; + } + + Flush(!ctx); + + int entries = (tex0.psm&3)==3 ? 256 : 16; +if (tex0.csm) + { + switch (tex0.cpsm) + { + // 16bit psm + // eggomania uses non16bit textures for csm2 + case PSMCT16: + { + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for (int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress16_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + + // check for wrapping + if (((u32)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); + } + break; + } + + case PSMCT16S: + { + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for (int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress16S_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + + // check for wrapping + if (((u32)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); + } + break; + } + + case PSMCT32: + case PSMCT24: + { + u32* src = (u32*)g_pbyGSMemory + tex0.cbp*64; + u32 *dst = (u32*)(g_pbyGSClut+64*tex0.csa); + + // check if address exceeds src + if( src+getPixelAddress32_0(gs.clut.cou+entries-1, gs.clut.cov, gs.clut.cbw) >= (u32*)g_pbyGSMemory + 0x00100000 ) + ERROR_LOG("texClutWrite out of bounds\n"); + else + for(int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress32_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst++; + } + } + break; + + default: + { +#ifndef RELEASE_TO_PUBLIC + //DEBUG_LOG("unknown cpsm: %x (%x)\n", tex0.cpsm, tex0.psm); +#endif + break; + } + } + } + else + { + switch (tex0.cpsm) + { + case PSMCT24: + case PSMCT32: + if( entries == 16 ) + WriteCLUT_T32_I4_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + else + WriteCLUT_T32_I8_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + break; + + default: + if( entries == 16 ) + WriteCLUT_T16_I4_CSM1((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + else // sse2 for 256 is more complicated, so use regular + WriteCLUT_T16_I8_CSM1_c((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + break; + + } + } +} + +void ZeroGS::SetTexFlush() +{ + s_bTexFlush = TRUE; + +// if( PSMT_ISCLUT(vb[0].tex0.psm) ) +// texClutWrite(0); +// if( PSMT_ISCLUT(vb[1].tex0.psm) ) +// texClutWrite(1); + + if( !s_bForceTexFlush ) + { + if( s_ptexCurSet[0] != s_ptexNextSet[0] ) + { + s_ptexCurSet[0] = s_ptexNextSet[0]; + pd3dDevice->SetTexture(SAMP_MEMORY0, s_ptexNextSet[0]); + } + if( s_ptexCurSet[1] != s_ptexNextSet[1] ) + { + s_ptexCurSet[1] = s_ptexNextSet[1]; + pd3dDevice->SetTexture(SAMP_MEMORY1, s_ptexNextSet[1]); + } + } +} + +int ZeroGS::Save(char* pbydata) +{ + if( pbydata == NULL ) + return 40 + 0x00400000 + sizeof(gs) + 2*VBSAVELIMIT + 2*sizeof(frameInfo) + 4 + 256*4; + + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + vb[0].Unlock(); + vb[1].Unlock(); + + strcpy(pbydata, libraryName); + *(u32*)(pbydata+16) = ZEROGS_SAVEVER; + pbydata += 32; + + *(int*)pbydata = icurctx; pbydata += 4; + *(int*)pbydata = VBSAVELIMIT; pbydata += 4; + + memcpy(pbydata, g_pbyGSMemory, 0x00400000); + pbydata += 0x00400000; + + memcpy(pbydata, g_pbyGSClut, 256*4); + pbydata += 256*4; + + *(int*)pbydata = sizeof(gs); + pbydata += 4; + memcpy(pbydata, &gs, sizeof(gs)); + pbydata += sizeof(gs); + + for(int i = 0; i < 2; ++i) { + memcpy(pbydata, &vb[i], VBSAVELIMIT); + pbydata += VBSAVELIMIT; + } + + vb[0].Lock(); + vb[1].Lock(); + + return 0; +} + +extern u32 s_uTex1Data[2][2], s_uClampData[2]; +extern char *libraryName; +bool ZeroGS::Load(char* pbydata) +{ + memset(s_uTex1Data, 0, sizeof(s_uTex1Data)); + memset(s_uClampData, 0, sizeof(s_uClampData)); + + // first 32 bytes are the id + u32 savever = *(u32*)(pbydata+16); + + if( strncmp(pbydata, libraryName, 6) == 0 && (savever == ZEROGS_SAVEVER || savever == 0xaa000004) ) { + + g_MemTargs.Destroy(); + + GSStateReset(); + pbydata += 32; + + int context = *(int*)pbydata; pbydata += 4; + u32 savelimit = VBSAVELIMIT; + + savelimit = *(u32*)pbydata; pbydata += 4; + + memcpy(g_pbyGSMemory, pbydata, 0x00400000); + pbydata += 0x00400000; + + memcpy(g_pbyGSClut, pbydata, 256*4); + pbydata += 256*4; + + memset(&gs, 0, sizeof(gs)); + + int savedgssize; + if( savever == 0xaa000004 ) + savedgssize = 0x1d0; + else { + savedgssize = *(int*)pbydata; + pbydata += 4; + } + + memcpy(&gs, pbydata, savedgssize); + pbydata += savedgssize; + prim = &gs._prim[gs.prac]; + + LPD3DVB pvb = vb[0].pvb; + memcpy(&vb[0], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[0].pvb = pvb; + + pvb = vb[1].pvb; + memcpy(&vb[1], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[1].pvb = pvb; + + for(int i = 0; i < 2; ++i) { + vb[i].bNeedZCheck = vb[i].bNeedFrameCheck = 1; + + vb[i].bSyncVars = 0; vb[i].bNeedTexCheck = 1; + memset(vb[i].uCurTex0Data, 0, sizeof(vb[i].uCurTex0Data)); + } + + icurctx = -1; + + pd3dDevice->SetRenderTarget(0, psurfOrgTarg); + pd3dDevice->SetRenderTarget(1, NULL); + pd3dDevice->SetDepthStencilSurface(psurfOrgDepth); + SetFogColor(gs.fogcol); + + vb[0].Lock(); + vb[1].Lock(); + + return true; + } + + return false; +} + +void ZeroGS::SaveSnapshot(const char* filename) +{ + g_bMakeSnapshot = 1; + strSnapshot = filename; +} + +// AVI capture stuff +bool ZeroGS::StartCapture() +{ + if( !s_aviinit ) { + START_AVI("zerogs.avi"); + + assert( s_ptexAVICapture == NULL ); + if( FAILED(pd3dDevice->CreateOffscreenPlainSurface(width, height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &s_ptexAVICapture, NULL)) ) { + STOP_AVI(); + ZeroGS::AddMessage("Failed to create avi"); + return false; + } + + s_aviinit = 1; + } + else { + DEBUG_LOG("ZeroGS: Continuing from previous capture"); + } + + s_avicapturing = 1; + return true; +} + +void ZeroGS::StopCapture() +{ + s_avicapturing = 0; +} + +void ZeroGS::CaptureFrame() +{ + assert( s_avicapturing && s_aviinit && s_ptexAVICapture != NULL ); + + vector mem; + + pd3dDevice->GetRenderTargetData(psurfOrgTarg, s_ptexAVICapture); + + D3DLOCKED_RECT lock; + mem.resize(width * height * 4); + + s_ptexAVICapture->LockRect(&lock, NULL, D3DLOCK_READONLY); + assert( lock.Pitch == width*4 ); + + BYTE* pend = (BYTE*)lock.pBits + (conf.height-1)*width*4; + for(int i = 0; i < conf.height; ++i) { + memcpy_amd(&mem[width*4*i], pend - width*4*i, width * 4); + } + s_ptexAVICapture->UnlockRect(); + + int fps = SMODE1->CMOD == 3 ? 50 : 60; + bool bSuccess = ADD_FRAME_FROM_DIB_TO_AVI("AAAA", fps, width, height, 32, &mem[0]); + + if( !bSuccess ) { + s_avicapturing = 0; + STOP_AVI(); + s_aviinit = 0; + ZeroGS::AddMessage("Failed to create avi"); + return; + } +} diff --git a/plugins/zerogs/dx/zerogs.h b/plugins/zerogs/dx/zerogs.h new file mode 100644 index 0000000000..530288d82e --- /dev/null +++ b/plugins/zerogs/dx/zerogs.h @@ -0,0 +1,514 @@ +/* ZeroGS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __ZEROGS__H +#define __ZEROGS__H + +#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union + +#include +#include + +#include +#include +#include +#include +#include +using namespace std; + +#ifndef SAFE_DELETE +#define SAFE_DELETE(x) if( (x) != NULL ) { delete (x); (x) = NULL; } +#endif +#ifndef SAFE_DELETE_ARRAY +#define SAFE_DELETE_ARRAY(x) if( (x) != NULL ) { delete[] (x); (x) = NULL; } +#endif +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(x) if( (x) != NULL ) { (x)->Release(); (x) = NULL; } +#endif + +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) + +typedef D3DXVECTOR2 DXVEC2; +typedef D3DXVECTOR3 DXVEC3; +typedef D3DXVECTOR4 DXVEC4; +typedef D3DXMATRIX DXMAT; + +// sends a message to output window if assert fails +#define BMSG(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); } } +#define BMSG_RETURN(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return; } } +#define BMSG_RETURNX(x, str, rtype) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return (##rtype); } } +#define B(x) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); } } +#define B_RETURN(x) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); return; } } +#define B_RETURNX(x, rtype) { if( !(x) ) { GS_LOG(_T(#x"\n")); GS_LOG(#x"\n"); return (##rtype); } } +#define B_G(x, action) { if( !(x) ) { GS_LOG(#x"\n"); action; } } + +#ifndef RELEASE_TO_PUBLIC + #ifndef V +#define V(x) { hr = x; if( FAILED(hr) ) { ERROR_LOG("%s:%d: %s (%8.8x)\n", __FILE__, (DWORD)__LINE__, _T(#x), hr); } } + #endif + #ifndef V_RETURN + #define V_RETURN(x) { hr = x; if( FAILED(hr) ) { ERROR_LOG("%s:%d: %s (%8.8x)\n", __FILE__, (DWORD)__LINE__, _T(#x), hr); return hr; } } + #endif +#else + #ifndef V + #define V(x) { hr = x; } + #endif + #ifndef V_RETURN + #define V_RETURN(x) { hr = x; if( FAILED(hr) ) { return hr; } } + #endif +#endif + +#define SETRS(state, val) pd3dDevice->SetRenderState(state, val) +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// all textures have this width +//#define GPU_TEXWIDTH 512 +extern int GPU_TEXWIDTH; +extern float g_fiGPU_TEXWIDTH; +#define GPU_TEXMASKWIDTH 1024 // bitwise mask width for region repeat mode + +// set these shader constants +#define GPU_TEXALPHA20 (2|0x8000) +#define GPU_TEXOFFSET0 (4|0x8000) +#define GPU_TEXDIMS0 (6|0x8000) +#define GPU_TEXBLOCK0 (8|0x8000) +#define GPU_CLAMPEXTS0 (10|0x8000) +#define GPU_TEXWRAPMODE0 (12|0x8000) +#define GPU_REALTEXDIMS0 (14|0x8000) +#define GPU_TESTBLACK0 (16|0x8000) +#define GPU_PAGEOFFSET0 (18|0x8000) +#define GPU_TEXALPHA0 (20|0x8000) + +#define GPU_INVTEXDIMS (22|0x8000) +#define GPU_FOGCOLOR (23|0x8000) +#define GPU_BITBLTZ (24|0x8000) +#define GPU_ONECOLOR (25|0x8000) + +#define GPU_CLIPPLANE0 (24|0x8000) +#define GPU_CLIPPLANE1 (26|0x8000) + +#define GPU_POSXY0 2 + +#define GPU_BITBLTPOS 4 +#define GPU_Z 5 +#define GPU_ZNORM 6 +#define GPU_BITBLTTEX 7 + +#define SETCONSTF(id, ptr) { if( id & 0x8000 ) pd3dDevice->SetPixelShaderConstantF(id&0x7fff, (FLOAT*)ptr, 1); \ + else pd3dDevice->SetVertexShaderConstantF(id&0x7fff, (FLOAT*)ptr, 1); } + +#define SAMP_MEMORY0 0 +#define SAMP_MEMORY1 1 +#define SAMP_FINAL 2 +#define SAMP_BLOCKS 3 +#define SAMP_BILINEARBLOCKS 4 +#define SAMP_INTERLACE 5 +#define SAMP_BITWISEANDX 5 +#define SAMP_BITWISEANDY 6 + +// don't change these values! +#define GAME_TEXTURETARGS 0x01 +#define GAME_AUTORESET 0x02 +#define GAME_INTERLACE2X 0x04 +#define GAME_TEXAHACK 0x08 // apply texa to non textured polys +#define GAME_NOTARGETRESOLVE 0x10 +#define GAME_EXACTCOLOR 0x20 +#define GAME_NOCOLORCLAMP 0x40 +#define GAME_FFXHACK 0x80 +#define GAME_NODEPTHUPDATE 0x0200 +#define GAME_QUICKRESOLVE1 0x0400 +#define GAME_NOQUICKRESOLVE 0x0800 +#define GAME_NOTARGETCLUT 0x1000 // full 16 bit resolution +#define GAME_NOSTENCIL 0x2000 +#define GAME_VSSHACKOFF 0x4000 // vertical stripe syndrome +#define GAME_NODEPTHRESOLVE 0x8000 +#define GAME_FULL16BITRES 0x00010000 +#define GAME_RESOLVEPROMOTED 0x00020000 +#define GAME_FASTUPDATE 0x00040000 +#define GAME_NOALPHATEST 0x00080000 +#define GAME_DISABLEMRTDEPTH 0x00100000 +#define GAME_32BITTARGS 0x00200000 +#define GAME_PATH3HACK 0x00400000 +#define GAME_DOPARALLELCTX 0x00800000 // tries to parallelize both contexts so that render calls are reduced (xenosaga) + // makes the game faster, but can be buggy +#define GAME_XENOSPECHACK 0x01000000 // xenosaga specularity hack (ignore any zmask=1 draws) +#define GAME_PARTIALPOINTERS 0x02000000 // whenver the texture or render target are small, tries to look for bigger ones to read from +#define GAME_PARTIALDEPTH 0x04000000 // tries to save depth targets as much as possible across height changes +#define GAME_RELAXEDDEPTH 0x08000000 // tries to save depth targets as much as possible across height changes + +#define USEALPHABLENDING 1//(!(g_GameSettings&GAME_NOALPHABLEND)) +#define USEALPHATESTING (!(g_GameSettings&GAME_NOALPHATEST)) + +typedef IDirect3DDevice9* LPD3DDEV; +typedef IDirect3DVertexBuffer9* LPD3DVB; +typedef IDirect3DIndexBuffer9* LPD3DIB; +typedef IDirect3DBaseTexture9* LPD3DBASETEX; +typedef IDirect3DTexture9* LPD3DTEX; +typedef IDirect3DCubeTexture9* LPD3DCUBETEX; +typedef IDirect3DVolumeTexture9* LPD3DVOLUMETEX; +typedef IDirect3DSurface9* LPD3DSURF; +typedef IDirect3DVertexDeclaration9* LPD3DDECL; +typedef IDirect3DVertexShader9* LPD3DVS; +typedef IDirect3DPixelShader9* LPD3DPS; +typedef ID3DXAnimationController* LPD3DXAC; + +namespace ZeroGS +{ + typedef void (*DrawFn)(); + + // managers render-to-texture targets + class CRenderTarget + { + public: + CRenderTarget(); + CRenderTarget(const frameInfo& frame, CRenderTarget& r); // virtualized a target + virtual ~CRenderTarget(); + + virtual BOOL Create(const frameInfo& frame); + virtual void Destroy(); + + // set the GPU_POSXY variable, scissor rect, and current render target + void SetTarget(int fbplocal, const Rect2& scissor, int context); + void SetViewport(); + + // copies/creates the feedback contents + inline void CreateFeedback() { + if( ptexFeedback == NULL || !(status&TS_FeedbackReady) ) + _CreateFeedback(); + } + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* pdepth); + virtual void ConvertTo32(); // converts a psm==2 target, to a psm==0 + virtual void ConvertTo16(); // converts a psm==0 target, to a psm==2 + + virtual bool IsDepth() { return false; } + + LPD3DSURF psurf, psys; + LPD3DTEX ptex; + + int targoffx, targoffy; // the offset from the target that the real fbp starts at (in pixels) + int targheight; // height of ptex + CRenderTarget* pmimicparent; // if not NULL, this target is a subtarget of pmimicparent + + int fbp, fbw, fbh; // if fbp is negative, virtual target (not mapped to any real addr) + int start, end; // in bytes + u32 lastused; // time stamp since last used + DXVEC4 vposxy; + + u32 fbm; + u16 status; + u8 psm; + u8 resv0; + RECT scissorrect; + + //int startresolve, endresolve; + u32 nUpdateTarg; // use this target to update the texture if non 0 (one time only) + + // this is optionally used when feedback effects are used (render target is used as a texture when rendering to itself) + LPD3DTEX ptexFeedback; + LPD3DSURF psurfFeedback; + + enum TargetStatus { + TS_Resolved = 1, + TS_NeedUpdate = 2, + TS_Virtual = 4, // currently not mapped to memory + TS_FeedbackReady = 8, // feedback effect is ready and doesn't need to be updated + TS_NeedConvert32 = 16, + TS_NeedConvert16 = 32, + }; + + private: + void _CreateFeedback(); + }; + + // manages zbuffers + class CDepthTarget : public CRenderTarget + { + public: + CDepthTarget(); + virtual ~CDepthTarget(); + + virtual BOOL Create(const frameInfo& frame); + virtual void Destroy(); + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* prndr); + + virtual bool IsDepth() { return true; } + + void SetDepthTarget(); + + LPD3DSURF pdepth; + }; + + // manages contiguous chunks of memory (width is always 1024) + class CMemoryTarget + { + public: + struct MEMORY + { + inline MEMORY() : ptr(NULL), ref(0) {} + inline ~MEMORY() { _aligned_free(ptr); } + + BYTE* ptr; + int ref; + }; + + inline CMemoryTarget() : ptex(NULL), ptexsys(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), + cpsm(0), memory(NULL), clearminy(0), clearmaxy(0), validatecount(0) {} + inline CMemoryTarget(const CMemoryTarget& r) { + ptex = r.ptex; + ptexsys = r.ptexsys; + if( ptex != NULL ) ptex->AddRef(); + if( ptexsys != NULL ) ptexsys->AddRef(); + starty = r.starty; + height = r.height; + realy = r.realy; + realheight = r.realheight; + usedstamp = r.usedstamp; + psm = r.psm; + cpsm = r.cpsm; + clut = r.clut; + memory = r.memory; + clearminy = r.clearminy; + clearmaxy = r.clearmaxy; + widthmult = r.widthmult; + validatecount = r.validatecount; + fmt = r.fmt; + if( memory != NULL ) memory->ref++; + } + + ~CMemoryTarget() { Destroy(); } + + inline void Destroy() { + SAFE_RELEASE(ptex); + SAFE_RELEASE(ptexsys); + + if( memory != NULL && memory->ref > 0 ) { + if( --memory->ref <= 0 ) { + SAFE_DELETE(memory); + } + } + memory = NULL; + } + + // returns true if clut data is synced + bool ValidateClut(const tex0Info& tex0); + // returns true if tex data is synced + bool ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex); + + int clearminy, clearmaxy; // when maxy > 0, need to check for clearing + + // realy is offset in pixels from start of valid region + // so texture in memory is [realy,starty+height] + // valid texture is [starty,starty+height] + // offset in mem [starty-realy, height] + int starty, height; // assert(starty >= realy) + int realy, realheight; // this is never touched once allocated + u32 usedstamp; + LPD3DTEX ptex; // can be 16bit if + LPD3DTEX ptexsys; + D3DFORMAT fmt; + + int widthmult; + + int validatecount; // count how many times has been validated, if too many, destroy + + vector clut; // if nonzero, texture uses CLUT + MEMORY* memory; // system memory used to compare for changes + u8 psm, cpsm; // texture and clut format. For psm, only 16bit/32bit differentiation matters + }; + + + struct VB + { + VB(); + ~VB(); + + void Destroy(); + + inline bool IsLocked() { return pbuf != NULL; } + inline void Lock(); + inline void Unlock() { + if( pbuf != NULL ) { + pvb->Unlock(); + pbuf = NULL; + } + } + + __forceinline bool CheckPrim(); + void CheckFrame(int tbp); + + // context specific state + Point offset; + Rect2 scissor; + tex0Info tex0; + tex1Info tex1; + miptbpInfo miptbp0; + miptbpInfo miptbp1; + alphaInfo alpha; + fbaInfo fba; + clampInfo clamp; + pixTest test; + LPD3DTEX ptexClamp[2]; // textures for x and y dir region clamping + + public: + + void FlushTexData(); + + u8 bNeedFrameCheck; + u8 bNeedZCheck; + u8 bNeedTexCheck; + u8 dummy0; + + union { + struct { + u8 bTexConstsSync; // only pixel shader constants that context owns + u8 bVarsTexSync; // texture info + u8 bVarsSetTarg; + u8 dummy1; + }; + u32 bSyncVars; + }; + + int ictx; + VertexGPU* pbuf; + DWORD dwCurOff; + DWORD dwCount; + primInfo curprim; // the previous prim the current buffers are set to + + zbufInfo zbuf; + frameInfo gsfb; // the real info set by FRAME cmd + frameInfo frame; + int zprimmask; // zmask for incoming points + + u32 uCurTex0Data[2]; // current tex0 data + u32 uNextTex0Data[2]; // tex0 data that has to be applied if bNeedTexCheck is 1 + + //int nFrameHeights[8]; // frame heights for the past frame changes + int nNextFrameHeight; + + CMemoryTarget* pmemtarg; // the current mem target set + LPD3DVB pvb; + CRenderTarget* prndr; + CDepthTarget* pdepth; + }; + + // visible members + extern DrawFn drawfn[8]; + extern VB vb[2]; + extern float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + extern LONG width, height; + extern u8* g_pbyGSMemory; + extern u8* g_pbyGSClut; // the temporary clut buffer + + void AddMessage(const char* pstr, DWORD ms = 5000); + void ChangeWindowSize(int nNewWidth, int nNewHeight); + void SetChangeDeviceSize(int nNewWidth, int nNewHeight); + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + void SetAA(int mode); + void SetCRC(int crc); + + void ReloadEffects(); + + // Methods // + + HRESULT Create(LONG width, LONG height); + void Destroy(BOOL bD3D); + + void Restore(); // call to restore device + void Reset(); // call to destroy video resources + + HRESULT InitDeviceObjects(); + void DeleteDeviceObjects(); + + void GSStateReset(); + + // called on a primitive switch + void Prim(); + + void SetTexFlush(); + // flush current vertices, call before setting new registers (the main render method) + void Flush(int context); + + void ExtWrite(); + + void SetWriteDepth(); + BOOL IsWriteDepth(); + + void SetDestAlphaTest(); + BOOL IsWriteDestAlphaTest(); + + void SetFogColor(u32 fog); + void SaveTex(tex0Info* ptex, int usevid); + + // called when trxdir is accessed. If host is involved, transfers memory to temp buffer byTransferBuf. + // Otherwise performs the transfer. TODO: Perhaps divide the transfers into chunks? + void InitTransferHostLocal(); + void TransferHostLocal(const void* pbyMem, u32 nQWordSize); + + void InitTransferLocalHost(); + void TransferLocalHost(void* pbyMem, u32 nQWordSize); + inline void TerminateLocalHost() {} + + void TransferLocalLocal(); + + // switches the render target to the real target, flushes the current render targets and renders the real image + void RenderCRTC(int interlace); + + bool CheckChangeInClut(u32 highdword, u32 psm); // returns true if clut will change after this tex0 op + + // call to load CLUT data (depending on CLD) + void texClutWrite(int ctx); + + int Save(char* pbydata); + bool Load(char* pbydata); + + void SaveSnapshot(const char* filename); + + // private methods + void FlushSysMem(const RECT* prc); + void _Resolve(const D3DLOCKED_RECT& locksrc, int fbp, int fbw, int fbh, int psm, u32 fbm); + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + // inits the smallest rectangle in ptexMem that covers this region in ptexMem + // returns the offset that needs to be added to the locked rect to get the beginning of the buffer + //void GetMemRect(RECT& rc, int psm, int x, int y, int w, int h, int bp, int bw); + + // only sets a limited amount of state (for Update) + void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, ZeroGS::CMemoryTarget* pmemtarg, int force); + + void ResetAlphaVariables(); + + bool StartCapture(); + void StopCapture(); + void CaptureFrame(); +}; + +extern LPDIRECT3DDEVICE9 pd3dDevice; +extern const u32 g_primmult[8]; +extern const u32 g_primsub[8]; + +#endif diff --git a/plugins/zerogs/opengl/GS.h b/plugins/zerogs/opengl/GS.h new file mode 100644 index 0000000000..37f962b7c5 --- /dev/null +++ b/plugins/zerogs/opengl/GS.h @@ -0,0 +1,845 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __GS_H__ +#define __GS_H__ + +#ifdef _WIN32 + +#include +#include + +extern HWND GShwnd; + +#else // linux basic definitions + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +#include +#include +#include + +// need C definitions +extern "C" { +#define GSdefs +#include "PS2Edefs.h" + +extern "C" u32 CALLBACK PS2EgetLibType(void); +extern "C" u32 CALLBACK PS2EgetLibVersion2(u32 type); +extern "C" char* CALLBACK PS2EgetLibName(void); +} + +#include "zerogsmath.h" + +#ifndef _WIN32 +#include + +#include +#include +using namespace std; + +extern u32 THR_KeyEvent; // value for passing out key events beetwen threads +extern bool THR_bShift; + +#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) + +// declare linux equivalents +static __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) +{ + assert( align < 0x10000 ); + char* p = (char*)malloc(size+align); + int off = 2+align - ((int)(uptr)(p+2) % align); + + p += off; + *(u16*)(p-2) = off; + + return p; +} + +static __forceinline void pcsx2_aligned_free(void* pmem) +{ + if( pmem != NULL ) { + char* p = (char*)pmem; + free(p - (int)*(u16*)(p-2)); + } +} + +#define _aligned_malloc pcsx2_aligned_malloc +#define _aligned_free pcsx2_aligned_free + +#endif + +#include // ftime(), struct timeb + +inline unsigned long timeGetTime() +{ +#ifdef _WIN32 + _timeb t; + _ftime(&t); +#else + timeb t; + ftime(&t); +#endif + + return (unsigned long)(t.time*1000+t.millitm); +} + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +struct RECT +{ + int left, top; + int right, bottom; +}; + +typedef struct { + Display *dpy; + int screen; + Window win; + GLXContext ctx; + XSetWindowAttributes attr; + Bool fs; + Bool doubleBuffered; + XF86VidModeModeInfo deskMode; + int x, y; + unsigned int width, height; + unsigned int depth; +} GLWindow; + +extern GLWindow GLWin; + +#endif // linux basic definitions + +struct Vector_16F +{ + u16 x, y, z, w; +}; + +///////////////////// +// define when releasing +// The only code that uses it is commented out! +//#define ZEROGS_CACHEDCLEAR // much better performance +//#define RELEASE_TO_PUBLIC +// fixme - We should use ZEROGS_DEVBUILD to determine devel/debug builds from "public release" builds. +// Means a lot of search-and-replace though. (air) + +#ifdef ZEROGS_DEVBUILD +#define GS_LOG __Log +#else +#define GS_LOG 0&& +#endif + +#define ERROR_LOG __LogToConsole +#define DEBUG_LOG printf + +#ifdef RELEASE_TO_PUBLIC +#define WARN_LOG 0&& +#define PRIM_LOG 0&& +#else +#define WARN_LOG printf +#define PRIM_LOG if (conf.log & 0x00000010) GS_LOG +#endif + +#ifndef GREG_LOG +#define GREG_LOG 0&& +#endif +#ifndef PRIM_LOG +#define PRIM_LOG 0&& +#endif +#ifndef WARN_LOG +#define WARN_LOG 0&& +#endif + +#define REG64(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + struct { \ + +#define REG128(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + struct { \ + +#define REG64_(prefix, name) REG64(prefix##name) +#define REG128_(prefix, name) REG128(prefix##name) + +#define REG_END }; }; +#define REG_END2 }; + +#define REG64_SET(name) \ +union name \ +{ \ + u64 i64; \ + u32 ai32[2]; \ + +#define REG128_SET(name)\ +union name \ +{ \ + u64 ai64[2]; \ + u32 ai32[4]; \ + +#define REG_SET_END }; + +REG64_(GSReg, BGCOLOR) + u32 R:8; + u32 G:8; + u32 B:8; + u32 _PAD1:8; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, BUSDIR) + u32 DIR:1; + u32 _PAD1:31; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, CSR) + u32 SIGNAL:1; + u32 FINISH:1; + u32 HSINT:1; + u32 VSINT:1; + u32 EDWINT:1; + u32 ZERO1:1; + u32 ZERO2:1; + u32 _PAD1:1; + u32 FLUSH:1; + u32 RESET:1; + u32 _PAD2:2; + u32 NFIELD:1; + u32 FIELD:1; + u32 FIFO:2; + u32 REV:8; + u32 ID:8; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, DISPFB) // (-1/2) + u32 FBP:9; + u32 FBW:6; + u32 PSM:5; + u32 _PAD:12; + u32 DBX:11; + u32 DBY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, DISPLAY) // (-1/2) + u32 DX:12; + u32 DY:11; + u32 MAGH:4; + u32 MAGV:2; + u32 _PAD:3; + u32 DW:12; + u32 DH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTBUF) + u32 EXBP:14; + u32 EXBW:6; + u32 FBIN:2; + u32 WFFMD:1; + u32 EMODA:2; + u32 EMODC:2; + u32 _PAD1:5; + u32 WDX:11; + u32 WDY:11; + u32 _PAD2:10; +REG_END + +REG64_(GSReg, EXTDATA) + u32 SX:12; + u32 SY:11; + u32 SMPH:4; + u32 SMPV:2; + u32 _PAD1:3; + u32 WW:12; + u32 WH:11; + u32 _PAD2:9; +REG_END + +REG64_(GSReg, EXTWRITE) + u32 WRITE; + u32 _PAD2:32; +REG_END + +REG64_(GSReg, IMR) + u32 _PAD1:8; + u32 SIGMSK:1; + u32 FINISHMSK:1; + u32 HSMSK:1; + u32 VSMSK:1; + u32 EDWMSK:1; + u32 _PAD2:19; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, PMODE) + u32 EN1:1; + u32 EN2:1; + u32 CRTMD:3; + u32 MMOD:1; + u32 AMOD:1; + u32 SLBG:1; + u32 ALP:8; + u32 _PAD:16; + u32 _PAD1:32; +REG_END + +REG64_(GSReg, SIGLBLID) + u32 SIGID:32; + u32 LBLID:32; +REG_END + +REG64_(GSReg, SMODE1) + u32 RC:3; + u32 LC:7; + u32 T1248:2; + u32 SLCK:1; + u32 CMOD:2; + u32 EX:1; + u32 PRST:1; + u32 SINT:1; + u32 XPCK:1; + u32 PCK2:2; + u32 SPML:4; + u32 GCONT:1; + u32 PHS:1; + u32 PVS:1; + u32 PEHS:1; + u32 PEVS:1; + u32 CLKSEL:2; + u32 NVCK:1; + u32 SLCK2:1; + u32 VCKSEL:2; + u32 VHP:1; + u32 _PAD1:27; +REG_END + +REG64_(GSReg, SMODE2) + u32 INT:1; + u32 FFMD:1; + u32 DPMS:2; + u32 _PAD2:28; + u32 _PAD3:32; +REG_END + +REG64_(GSReg, SIGBLID) + u32 SIGID; + u32 LBLID; +REG_END + +extern int g_LastCRC; +extern u8* g_pBasePS2Mem; + +#define PMODE ((GSRegPMODE*)(g_pBasePS2Mem+0x0000)) +#define SMODE1 ((GSRegSMODE1*)(g_pBasePS2Mem+0x0010)) +#define SMODE2 ((GSRegSMODE2*)(g_pBasePS2Mem+0x0020)) +// SRFSH +#define SYNCH1 ((GSRegSYNCH1*)(g_pBasePS2Mem+0x0040)) +#define SYNCH2 ((GSRegSYNCH2*)(g_pBasePS2Mem+0x0050)) +#define SYNCV ((GSRegSYNCV*)(g_pBasePS2Mem+0x0060)) +#define DISPFB1 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0070)) +#define DISPLAY1 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x0080)) +#define DISPFB2 ((GSRegDISPFB*)(g_pBasePS2Mem+0x0090)) +#define DISPLAY2 ((GSRegDISPLAY*)(g_pBasePS2Mem+0x00a0)) +#define EXTBUF ((GSRegEXTBUF*)(g_pBasePS2Mem+0x00b0)) +#define EXTDATA ((GSRegEXTDATA*)(g_pBasePS2Mem+0x00c0)) +#define EXTWRITE ((GSRegEXTWRITE*)(g_pBasePS2Mem+0x00d0)) +#define BGCOLOR ((GSRegBGCOLOR*)(g_pBasePS2Mem+0x00e0)) +#define CSR ((GSRegCSR*)(g_pBasePS2Mem+0x1000)) +#define IMR ((GSRegIMR*)(g_pBasePS2Mem+0x1010)) +#define BUSDIR ((GSRegBUSDIR*)(g_pBasePS2Mem+0x1040)) +#define SIGLBLID ((GSRegSIGBLID*)(g_pBasePS2Mem+0x1080)) + +#define GET_GSFPS (((SMODE1->CMOD&1) ? 50 : 60) / (SMODE2->INT ? 1 : 2)) + +// +// sps2tags.h +// +#ifdef _M_AMD64 +#define GET_GIF_REG(tag, reg) \ + (((tag).ai64[1] >> ((reg) << 2)) & 0xf) +#else +#define GET_GIF_REG(tag, reg) \ + (((tag).ai32[2 + ((reg) >> 3)] >> (((reg) & 7) << 2)) & 0xf) +#endif + +// +// GIFTag +REG128(GIFTag) + u32 NLOOP:15; + u32 EOP:1; + u32 _PAD1:16; + u32 _PAD2:14; + u32 PRE:1; + u32 PRIM:11; + u32 FLG:2; // enum GIF_FLG + u32 NREG:4; + u64 REGS:64; +REG_END + +typedef struct { + int x, y, w, h; +} Rect; + +typedef struct { + int x, y; +} Point; + +typedef struct { + int x0, y0; + int x1, y1; +} Rect2; + +typedef struct { + int x, y, c; +} PointC; + +#define GSOPTION_FULLSCREEN 0x2 +#define GSOPTION_TGASNAP 0x4 +#define GSOPTION_CAPTUREAVI 0x8 + +#define GSOPTION_WINDIMS 0x30 +#define GSOPTION_WIN640 0x00 +#define GSOPTION_WIN800 0x10 +#define GSOPTION_WIN1024 0x20 +#define GSOPTION_WIN1280 0x30 + +#define GSOPTION_WIREFRAME 0x100 +#define GSOPTION_LOADED 0x8000 + +typedef struct { + u8 mrtdepth; // write color in render target + u8 interlace; + u8 aa; // antialiasing 0 - off, 1 - 2x, 2 - 4x + u8 bilinear; // set to enable bilinear support + u32 options; + u32 gamesettings; // default game settings + int width, height; + int winstyle; // window style before full screen +#ifdef GS_LOG + u32 log; +#endif +} GSconf; + +struct VertexGPU +{ + s16 x, y, f, resv0; // note: xy is 12d3 + u32 rgba; + u32 z; + float s, t, q; +}; + +struct Vertex +{ + u16 x, y, f, resv0; // note: xy is 12d3 + u32 rgba; + u32 z; + float s, t, q; + u16 u, v; +}; + +extern int g_GameSettings; +extern GSconf conf; +extern int ppf; + +#define PSMCT32 0 +#define PSMCT24 1 +#define PSMCT16 2 +#define PSMCT16S 10 +#define PSMT8 19 +#define PSMT4 20 +#define PSMT8H 27 +#define PSMT4HL 36 +#define PSMT4HH 44 +#define PSMT32Z 48 +#define PSMT24Z 49 +#define PSMT16Z 50 +#define PSMT16SZ 58 + +#define PSMT_ISCLUT(psm) (((psm)&0x7)>2) +#define PSMT_IS16BIT(psm) (((psm)&7)==2||((psm)&7)==10) + +typedef struct { + int nloop; + int eop; + int nreg; +} tagInfo; + +typedef union { + s64 SD; + u64 UD; + s32 SL[2]; + u32 UL[2]; + s16 SS[4]; + u16 US[4]; + s8 SC[8]; + u8 UC[8]; +} reg64; + +/* general purpose regs structs */ +typedef struct { + int fbp; + int fbw; + int fbh; + int psm; + u32 fbm; +} frameInfo; + +typedef struct { + u16 prim; + + union { + struct { + u16 iip : 1; + u16 tme : 1; + u16 fge : 1; + u16 abe : 1; + u16 aa1 : 1; + u16 fst : 1; + u16 ctxt : 1; + u16 fix : 1; + u16 resv : 8; + }; + u16 _val; + }; +} primInfo; + +extern primInfo *prim; + +typedef union { + struct { + u32 ate : 1; + u32 atst : 3; + u32 aref : 8; + u32 afail : 2; + u32 date : 1; + u32 datm : 1; + u32 zte : 1; + u32 ztst : 2; + u32 resv : 13; + }; + u32 _val; +} pixTest; + +typedef struct { + int bp; + int bw; + int psm; +} bufInfo; + +typedef struct { + int tbp0; + int tbw; + int cbp; + u16 tw, th; + u8 psm; + u8 tcc; + u8 tfx; + u8 cpsm; + u8 csm; + u8 csa; + u8 cld; +} tex0Info; + +#define TEX_MODULATE 0 +#define TEX_DECAL 1 +#define TEX_HIGHLIGHT 2 +#define TEX_HIGHLIGHT2 3 + +typedef struct { + int lcm; + int mxl; + int mmag; + int mmin; + int mtba; + int l; + int k; +} tex1Info; + +typedef struct { + int wms; + int wmt; + int minu; + int maxu; + int minv; + int maxv; +} clampInfo; + +typedef struct { + int cbw; + int cou; + int cov; +} clutInfo; + +typedef struct { + int tbp[3]; + int tbw[3]; +} miptbpInfo; + +typedef struct { + u16 aem; + u8 ta[2]; + float fta[2]; +} texaInfo; + +typedef struct { + int sx; + int sy; + int dx; + int dy; + int dir; +} trxposInfo; + +typedef struct { + union { + struct { + u8 a : 2; + u8 b : 2; + u8 c : 2; + u8 d : 2; + }; + u8 abcd; + }; + + u8 fix : 8; +} alphaInfo; + +typedef struct { + u16 zbp; // u16 address / 64 + u8 psm; + u8 zmsk; +} zbufInfo; + +typedef struct { + int fba; +} fbaInfo; + +typedef struct { + int mode; + int regn; + u64 regs; + tagInfo tag; +} pathInfo; + +typedef struct { + Vertex gsvertex[3]; + u32 rgba; + float q; + Vertex vertexregs; + + int primC; // number of verts current storing + int primIndex; // current prim index + int nTriFanVert; + + int prac; + int dthe; + int colclamp; + int fogcol; + int smask; + int pabe; + u64 buff[2]; + int buffsize; + int cbp[2]; // internal cbp registers + + u32 CSRw; + + primInfo _prim[2]; + bufInfo srcbuf, srcbufnew; + bufInfo dstbuf, dstbufnew; + + clutInfo clut; + + texaInfo texa; + trxposInfo trxpos, trxposnew; + + int imageWtemp, imageHtemp; + + int imageTransfer; + int imageWnew, imageHnew, imageX, imageY, imageEndX, imageEndY; + + pathInfo path1; + pathInfo path2; + pathInfo path3; + +} GSinternal; + +extern GSinternal gs; + +extern FILE *gsLog; + +void __Log(const char *fmt, ...); +void __LogToConsole(const char *fmt, ...); + +void LoadConfig(); +void SaveConfig(); + +extern void (*GSirq)(); + +void *SysLoadLibrary(char *lib); // Loads Library +void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library +char *SysLibError(); // Gets previous error loading sysbols +void SysCloseLibrary(void *lib); // Closes Library +void SysMessage(char *fmt, ...); + +extern "C" void * memcpy_amd(void *dest, const void *src, size_t n); +extern "C" u8 memcmp_mmx(const void *dest, const void *src, int n); + +template +class CInterfacePtr +{ +public: + inline CInterfacePtr() : ptr(NULL) {} + inline explicit CInterfacePtr(T* newptr) : ptr(newptr) { if ( ptr != NULL ) ptr->AddRef(); } + inline ~CInterfacePtr() { if( ptr != NULL ) ptr->Release(); } + + inline T* operator* () { assert( ptr != NULL); return *ptr; } + inline T* operator->() { return ptr; } + inline T* get() { return ptr; } + + inline void release() { + if( ptr != NULL ) { ptr->Release(); ptr = NULL; } + } + + inline operator T*() { return ptr; } + + inline bool operator==(T* rhs) { return ptr == rhs; } + inline bool operator!=(T* rhs) { return ptr != rhs; } + + inline CInterfacePtr& operator= (T* newptr) { + if( ptr != NULL ) ptr->Release(); + ptr = newptr; + + if( ptr != NULL ) ptr->AddRef(); + return *this; + } + +private: + T* ptr; +}; + +#define RGBA32to16(c) \ + (u16)((((c) & 0x000000f8) >> 3) | \ + (((c) & 0x0000f800) >> 6) | \ + (((c) & 0x00f80000) >> 9) | \ + (((c) & 0x80000000) >> 16)) \ + +#define RGBA16to32(c) \ + (((c) & 0x001f) << 3) | \ + (((c) & 0x03e0) << 6) | \ + (((c) & 0x7c00) << 9) | \ + (((c) & 0x8000) ? 0xff000000 : 0) \ + +// converts float16 [0,1] to BYTE [0,255] (assumes value is in range, otherwise will take lower 8bits) +// f is a u16 +static __forceinline u16 Float16ToBYTE(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + u16 d = ((((f&0x3ff)|0x400)*255)>>(10-((f>>10)&0x1f)+15)); + return d > 255 ? 255 : d; +} + +static __forceinline u16 Float16ToALPHA(u16 f) { + //assert( !(f & 0x8000) ); + if( f & 0x8000 ) return 0; + + // round up instead of down (crash and burn), too much and charlie breaks + u16 d = (((((f&0x3ff)|0x400))*255)>>(10-((f>>10)&0x1f)+15)); + d = (d)>>1; + return d > 255 ? 255 : d; +} + +#ifndef COLOR_ARGB +#define COLOR_ARGB(a,r,g,b) \ + ((u32)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) +#endif + +// assumes that positive in [1,2] (then extracts fraction by just looking at the specified bits) +#define Float16ToBYTE_2(f) ((u8)(*(u16*)&f>>2)) +#define Float16To5BIT(f) (Float16ToBYTE(f)>>3) + +#define Float16Alpha(f) (((*(u16*)&f&0x7c00)>=0x3900)?0x8000:0) // alpha is >= 1 + +// converts an array of 4 u16s to a u32 color +// f is a pointer to a u16 +#define Float16ToARGB(f) COLOR_ARGB(Float16ToALPHA(f.w), Float16ToBYTE(f.x), Float16ToBYTE(f.y), Float16ToBYTE(f.z)); + +#define Float16ToARGB16(f) (Float16Alpha(f.w)|(Float16To5BIT(f.x)<<10)|(Float16To5BIT(f.y)<<5)|Float16To5BIT(f.z)) + +// used for Z values +#define Float16ToARGB_Z(f) COLOR_ARGB((u32)Float16ToBYTE_2(f.w), Float16ToBYTE_2(f.x), Float16ToBYTE_2(f.y), Float16ToBYTE_2(f.z)) +#define Float16ToARGB16_Z(f) ((Float16ToBYTE_2(f.y)<<8)|Float16ToBYTE_2(f.z)) + + +inline float Clamp(float fx, float fmin, float fmax) +{ + if( fx < fmin ) return fmin; + return fx > fmax ? fmax : fx; +} + +// IMPORTANT: For every Register there must be an End +void DVProfRegister(char* pname); // first checks if this profiler exists in g_listProfilers +void DVProfEnd(u32 dwUserData); +void DVProfWrite(char* pfilename, u32 frames = 0); +void DVProfClear(); // clears all the profilers + +#define DVPROFILE +#ifdef DVPROFILE + +class DVProfileFunc +{ +public: + u32 dwUserData; + DVProfileFunc(char* pname) { DVProfRegister(pname); dwUserData = 0; } + DVProfileFunc(char* pname, u32 dwUserData) : dwUserData(dwUserData) { DVProfRegister(pname); } + ~DVProfileFunc() { DVProfEnd(dwUserData); } +}; + +#else + +class DVProfileFunc +{ +public: + u32 dwUserData; + static __forceinline DVProfileFunc(char* pname) {} + static __forceinline DVProfileFunc(char* pname, u32 dwUserData) { } + ~DVProfileFunc() {} +}; + +#endif + +#endif diff --git a/plugins/zerogs/opengl/GSmain.cpp b/plugins/zerogs/opengl/GSmain.cpp new file mode 100644 index 0000000000..e197e4f78e --- /dev/null +++ b/plugins/zerogs/opengl/GSmain.cpp @@ -0,0 +1,1400 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ +#if defined(_WIN32) +#include +#include "Win32.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +using namespace std; + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" +#include "ZeroGSShaders/zerogsshaders.h" + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +GSinternal gs; +char GStitle[256]; +GSconf conf; +int ppf; +primInfo *prim; +FILE *gsLog; +int g_GSMultiThreaded = 0; +void (*GSirq)(); +u8* g_pBasePS2Mem = NULL; +int g_TransferredToGPU = 0; +string s_strIniPath="inis/zerogs.ini"; + +static BOOL g_bHidden = 0; +int g_GameSettings = 0; + +// statistics +u32 g_nGenVars = 0, g_nTexVars = 0, g_nAlphaVars = 0, g_nResolve = 0; + +#define VER 96 +const unsigned char zgsversion = PS2E_GS_VERSION; +unsigned char zgsrevision = 0; // revision and build gives plugin version +unsigned char zgsbuild = VER; +unsigned char zgsminor = 7; + +#ifdef _DEBUG +char *libraryName = "ZeroGS-Pg OpenGL (Debug) "; +#elif defined(RELEASE_TO_PUBLIC) +char *libraryName = "ZeroGS Playground OpenGL "; +#else +char *libraryName = "ZeroGS-Pg OpenGL (Dev) "; +#endif + +static const char* s_aa[5] = { "AA none |", "AA 2x |", "AA 4x |", "AA 8x |", "AA 16x |" }; +static const char* pbilinear[] = { "off", "normal", "forced" }; + +extern GIFRegHandler g_GIFPackedRegHandlers[]; +extern GIFRegHandler g_GIFRegHandlers[]; +GIFRegHandler g_GIFTempRegHandlers[16] = {0}; +extern int g_nPixelShaderVer; +extern int g_nFrameRender; +extern int g_nFramesSkipped; + +#ifdef RELEASE_TO_PUBLIC +#define g_bWriteProfile 0 +#else +BOOL g_bWriteProfile = 0; +#endif + +int s_frameskipping = 0; +u32 CALLBACK PS2EgetLibType() { + return PS2E_LT_GS; +} + +char* CALLBACK PS2EgetLibName() { + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) { + return (zgsversion<<16) | (zgsrevision<<8) | zgsbuild | (zgsminor << 24); +} + +static u64 luPerfFreq; + +#ifdef _WIN32 + +HWND GShwnd = NULL; + +void SysMessage(char *fmt, ...) { + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf(tmp,fmt,list); + va_end(list); + MessageBox(0, tmp, "GSsoftdx Msg", 0); +} +#else + +GLWindow GLWin; +u32 THR_KeyEvent = 0; // Value for key event processing between threads +bool THR_bShift = false; + +#endif + +void __Log(const char *fmt, ...) { + va_list list; + + // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. + // (GSinit won't have been called then) + + if (gsLog == NULL || !conf.log) return; + + va_start(list, fmt); + vfprintf(gsLog, fmt, list); + va_end(list); +} + +void __LogToConsole(const char *fmt, ...) { + va_list list; + + va_start(list, fmt); + + // gsLog can be null if the config dialog is used prior to Pcsx2 an emulation session. + // (GSinit won't have been called then) + + if( gsLog != NULL ) + vfprintf(gsLog, fmt, list); + + printf("ZeroGS: "); + vprintf(fmt, list); + va_end(list); +} + +void CALLBACK GSsetBaseMem(void* pmem) { + g_pBasePS2Mem = (u8*)pmem; +} + +extern int VALIDATE_THRESH; +extern u32 TEXDESTROY_THRESH; +int g_LastCRC = 0; +void CALLBACK GSsetGameCRC(int crc, int options) +{ + VALIDATE_THRESH = 8; + g_GameSettings = conf.gamesettings|options; + conf.mrtdepth = 0;//!(conf.gamesettings&GAME_DISABLEMRTDEPTH); + + if( !conf.mrtdepth ) ERROR_LOG("Disabling MRT depth writing\n"); + + g_GameSettings |= GAME_PATH3HACK; + g_LastCRC = crc; + + switch(crc) { + case 0x54A548B4: // crash n burn + // overbright + break; + + case 0xA3D63039: // xenosaga(j) + case 0x0E7807B2: // xenosaga(u) + g_GameSettings |= GAME_DOPARALLELCTX; + VALIDATE_THRESH = 64; + TEXDESTROY_THRESH = 32; + break; + + case 0x7D2FE035: // espgaluda (j) + VALIDATE_THRESH = 24; + //g_GameSettings |= GAME_BIGVALIDATE; + break; + } +} + +void CALLBACK GSsetFrameSkip(int frameskip) +{ + s_frameskipping |= frameskip; + if( frameskip && g_nFrameRender > 1 ) { + + for(int i = 0; i < 16; ++i) { + g_GIFPackedRegHandlers[i] = GIFPackedRegHandlerNOP; + } + + // still keep certain handlers + g_GIFPackedRegHandlers[6] = GIFRegHandlerTEX0_1; + g_GIFPackedRegHandlers[7] = GIFRegHandlerTEX0_2; + g_GIFPackedRegHandlers[14] = GIFPackedRegHandlerA_D; + + g_GIFRegHandlers[0] = GIFRegHandlerNOP; + g_GIFRegHandlers[1] = GIFRegHandlerNOP; + g_GIFRegHandlers[2] = GIFRegHandlerNOP; + g_GIFRegHandlers[3] = GIFRegHandlerNOP; + g_GIFRegHandlers[4] = GIFRegHandlerNOP; + g_GIFRegHandlers[5] = GIFRegHandlerNOP; + g_GIFRegHandlers[12] = GIFRegHandlerNOP; + g_GIFRegHandlers[13] = GIFRegHandlerNOP; + g_GIFRegHandlers[26] = GIFRegHandlerNOP; + g_GIFRegHandlers[27] = GIFRegHandlerNOP; + g_nFrameRender = 0; + } + else if( !frameskip && g_nFrameRender <= 0 ) { + g_nFrameRender = 1; + + if( g_GIFTempRegHandlers[0] == NULL ) return; // not init yet + + // restore + memcpy(g_GIFPackedRegHandlers, g_GIFTempRegHandlers, sizeof(g_GIFTempRegHandlers)); + + g_GIFRegHandlers[0] = GIFRegHandlerPRIM; + g_GIFRegHandlers[1] = GIFRegHandlerRGBAQ; + g_GIFRegHandlers[2] = GIFRegHandlerST; + g_GIFRegHandlers[3] = GIFRegHandlerUV; + g_GIFRegHandlers[4] = GIFRegHandlerXYZF2; + g_GIFRegHandlers[5] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[12] = GIFRegHandlerXYZF3; + g_GIFRegHandlers[13] = GIFRegHandlerXYZ2; + g_GIFRegHandlers[26] = GIFRegHandlerPRMODECONT; + g_GIFRegHandlers[27] = GIFRegHandlerPRMODE; + } +} + +void CALLBACK GSreset() { + + memset(&gs, 0, sizeof(gs)); + + ZeroGS::GSStateReset(); + + gs.prac = 1; + prim = &gs._prim[0]; + gs.nTriFanVert = -1; + gs.imageTransfer = -1; + gs.q = 1; +} + +void CALLBACK GSgifSoftReset(u32 mask) +{ + if( mask & 1 ) memset(&gs.path1, 0, sizeof(gs.path1)); + if( mask & 2 ) memset(&gs.path2, 0, sizeof(gs.path2)); + if( mask & 4 ) memset(&gs.path3, 0, sizeof(gs.path3)); + gs.imageTransfer = -1; + gs.q = 1; + gs.nTriFanVert = -1; +} + +s32 CALLBACK GSinit() +{ + memcpy(g_GIFTempRegHandlers, g_GIFPackedRegHandlers, sizeof(g_GIFTempRegHandlers)); + +#ifdef GS_LOG + gsLog = fopen("logs/gsLog.txt", "w"); + if (gsLog == NULL) { + gsLog = fopen("gsLog.txt", "w"); + if (gsLog == NULL) { + SysMessage("Can't create gsLog.txt"); return -1; + } + } + setvbuf(gsLog, NULL, _IONBF, 0); + GS_LOG("GSinit\n"); +#endif + +#ifdef __LINUX__ + char strcurdir[256]; + getcwd(strcurdir, 256); + s_strIniPath = strcurdir; + s_strIniPath += "/inis/zerogs.ini"; +#endif + + GSreset(); + GS_LOG("GSinit ok\n"); + return 0; +} + +void CALLBACK GSshutdown() +{ +#ifdef GS_LOG + fclose(gsLog); +#endif +} + +// keyboard functions +void OnKeyboardF5(int shift) +{ + char strtitle[256]; + if( shift ) { + if( g_nPixelShaderVer == SHADER_REDUCED ) { + conf.bilinear = 0; + sprintf(strtitle, "reduced shaders don't support bilinear filtering"); + } + else { + conf.bilinear = (conf.bilinear+1)%3; + sprintf(strtitle, "bilinear filtering - %s", pbilinear[conf.bilinear]); + } + } + else { + conf.interlace++; + if( conf.interlace > 2 ) conf.interlace = 0; + if( conf.interlace < 2 ) sprintf(strtitle, "interlace on - mode %d", conf.interlace); + else sprintf(strtitle, "interlace off"); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); +} + +void OnKeyboardF6(int shift) +{ + char strtitle[256]; + if( shift ) { + conf.aa--; // -1 + if( conf.aa > 4 ) conf.aa = 4; // u8 in unsigned, so negative value is 255. + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + else { + conf.aa++; + if( conf.aa > 4 ) conf.aa = 0; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); + ZeroGS::SetAA(conf.aa); + } + + ZeroGS::AddMessage(strtitle); + SaveConfig(); +} + +void OnKeyboardF7(int shift) +{ + char strtitle[256]; + if( shift ) { + extern BOOL g_bDisplayFPS; + g_bDisplayFPS ^= 1; + } + else { + conf.options ^= GSOPTION_WIREFRAME; + glPolygonMode(GL_FRONT_AND_BACK, (conf.options&GSOPTION_WIREFRAME)?GL_LINE:GL_FILL); + sprintf(strtitle, "wireframe rendering - %s", (conf.options&GSOPTION_WIREFRAME)?"on":"off"); + } +} + +void OnKeyboardF9(int shift) +{ + char strtitle[256]; + g_GameSettings ^= GAME_PATH3HACK; + sprintf(strtitle, "path3 hack - %s", (g_GameSettings&GAME_PATH3HACK) ? "on" : "off"); + ZeroGS::AddMessage(strtitle); + //SaveConfig(); +} + +#ifdef _WIN32 + +#ifdef _DEBUG +HANDLE g_hCurrentThread = NULL; +#endif + +LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + static int nWindowWidth = 0, nWindowHeight = 0; + + switch( msg ) { + case WM_DESTROY: + PostQuitMessage( 0 ); + return 0; + + case WM_KEYDOWN: +// switch(wParam) { +// case VK_ESCAPE: +// SendMessage(hWnd, WM_DESTROY, 0L, 0L); +// break; +// } + break; + + case WM_ACTIVATE: + + if( wParam != WA_INACTIVE ) { + //DEBUG_LOG("restoring device\n"); + ZeroGS::Restore(); + } + + break; + + case WM_SIZE: + nWindowWidth = lParam&0xffff; + nWindowHeight = lParam>>16; + ZeroGS::ChangeWindowSize(nWindowWidth, nWindowHeight); + + break; + + case WM_SIZING: + // if button is 0, then just released so can resize + if( GetSystemMetrics(SM_SWAPBUTTON) ? !GetAsyncKeyState(VK_RBUTTON) : !GetAsyncKeyState(VK_LBUTTON) ) { + ZeroGS::SetChangeDeviceSize(nWindowWidth, nWindowHeight); + } + break; + + case WM_SETCURSOR: + SetCursor(NULL); + break; + } + + return DefWindowProc( hWnd, msg, wParam, lParam ); +} + +extern HINSTANCE hInst; +void CALLBACK GSconfigure() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_CONFIG), + GetActiveWindow(), + (DLGPROC)ConfigureDlgProc); + + if( g_nPixelShaderVer == SHADER_REDUCED ) + conf.bilinear = 0; +} + + +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) { + + g_GSMultiThreaded = multithread; + + GS_LOG("GSopen\n"); + +#ifdef _DEBUG + g_hCurrentThread = GetCurrentThread(); +#endif + + assert( GSirq != NULL ); + LoadConfig(); + + strcpy(GStitle, Title); + + RECT rc, rcdesktop; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, + GetModuleHandle(NULL), NULL, NULL, NULL, NULL, + "PS2EMU_ZEROGS", NULL }; + RegisterClassEx( &wc ); + + AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + GShwnd = CreateWindow( "PS2EMU_ZEROGS", "ZeroGS", WS_OVERLAPPEDWINDOW, + (rcdesktop.right-(rc.right-rc.left))/2, (rcdesktop.bottom-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, wc.hInstance, NULL ); + + if(GShwnd == NULL) { + GS_LOG("Failed to create window. Exiting..."); + return -1; + } + + if( pDsp != NULL ) + *(HWND*)pDsp = GShwnd; + + ERROR_LOG("creating zerogs\n"); + //if (conf.record) recOpen(); + if( !ZeroGS::Create(conf.width, conf.height) ) + return -1; + + ERROR_LOG("initialization successful\n"); + + if( conf.bilinear == 2 ) { + ZeroGS::AddMessage("forced bilinear filtering - on", 1000); + } + else if( conf.bilinear == 1 ) { + ZeroGS::AddMessage("normal bilinear filtering - on", 1000); + } + if( conf.aa ) { + char strtitle[64]; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); + ZeroGS::AddMessage(strtitle); + } + + // set just in case + SetWindowLongPtr(GShwnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)MsgProc); + + ShowWindow( GShwnd, SW_SHOWDEFAULT ); + UpdateWindow( GShwnd ); + SetFocus(GShwnd); + + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + + GS_LOG("GSopen ok\n"); + + LARGE_INTEGER temp; + QueryPerformanceFrequency(&temp); + luPerfFreq = temp.QuadPart; + + gs.path1.mode = 0; + gs.path2.mode = 0; + gs.path3.mode = 0; + + return 0; +} + +void ProcessMessages() +{ + MSG msg; + ZeroMemory( &msg, sizeof(msg) ); + while( 1 ) { + if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) + { + switch( msg.message ) { + case WM_KEYDOWN : + if( msg.wParam == VK_F5 ) { + OnKeyboardF5(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_F6 ) { + OnKeyboardF6(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_F7 ) { + OnKeyboardF7(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_F9 ) { + OnKeyboardF9(GetKeyState(VK_SHIFT)&0x8000); + } + else if( msg.wParam == VK_ESCAPE ) { + + if( conf.options & GSOPTION_FULLSCREEN ) { + // destroy that msg + conf.options &= ~GSOPTION_FULLSCREEN; + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + ZeroGS::ChangeDeviceSize(conf.width, conf.height); + UpdateWindow(GShwnd); + continue; // so that msg doesn't get sent + } + else { + SendMessage(GShwnd, WM_DESTROY, 0, 0); + g_bHidden = 1; + return; + } + } + + break; + } + + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + else + break; + } + + if( (GetKeyState(VK_MENU)&0x8000) && (GetKeyState(VK_RETURN)&0x8000) ) { + conf.options ^= GSOPTION_FULLSCREEN; + + if( conf.options & GSOPTION_FULLSCREEN ) { + conf.winstyle = GetWindowLong( GShwnd, GWL_STYLE ); + conf.winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style + } + + ZeroGS::SetChangeDeviceSize( + (conf.options&GSOPTION_FULLSCREEN) ? 1280 : conf.width, + (conf.options&GSOPTION_FULLSCREEN) ? 960 : conf.height); + } + +// if( conf.fullscreen && (GetKeyState(VK_ESCAPE)&0x8000)) { +// conf.fullscreen &= ~GSOPTION_FULLSCREEN; +// ZeroGS::SetChangeDeviceSize(conf.width, conf.height); +// } + + //if( conf.interlace && g_nGenVars + g_nTexVars + g_nAlphaVars + g_nResolve == 0 ) + // CSR->FIELD = 0; // 0 should always be the repeating at 0 +} + +#else // linux + +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread) +{ + GS_LOG("GSopen\n"); + + assert( GSirq != NULL ); + LoadConfig(); + + strcpy(GStitle, Title); + + GLWin.dpy = XOpenDisplay(0); + GLWin.screen = DefaultScreen(GLWin.dpy); + + if( pDsp != NULL ) + *(Display**)pDsp = GLWin.dpy; + + ERROR_LOG("creating zerogs\n"); + //if (conf.record) recOpen(); + if( !ZeroGS::Create(conf.width, conf.height) ) + return -1; + + ERROR_LOG("initialization successful\n"); + + if( conf.bilinear == 2 ) { + ZeroGS::AddMessage("bilinear filtering - forced", 1000); + } + else if( conf.bilinear == 1 ) { + ZeroGS::AddMessage("bilinear filtering - normal", 1000); + } + if( conf.aa ) { + char strtitle[64]; + sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa], 1000); + ZeroGS::AddMessage(strtitle); + } + + GS_LOG("GSopen ok\n"); + + gs.path1.mode = 0; + gs.path2.mode = 0; + gs.path3.mode = 0; + luPerfFreq = 1; + + return 0; +} + +void ProcessMessages() +{ + + XEvent event; + // check resizing + while(XCheckTypedEvent(GLWin.dpy, ConfigureNotify, &event)) { + if ((event.xconfigure.width != GLWin.width) || (event.xconfigure.height != GLWin.height)) { + ZeroGS::ChangeWindowSize(event.xconfigure.width, event.xconfigure.height); + GLWin.width = event.xconfigure.width; + GLWin.height = event.xconfigure.height; + } + } + + if ( THR_KeyEvent ) { // This values was passed from GSKeyEvents witch could be in another thread + int my_KeyEvent = THR_KeyEvent; + bool my_bShift = THR_bShift; + THR_KeyEvent = 0; + switch ( my_KeyEvent ) { + case XK_F5: + OnKeyboardF5(my_bShift); + break; + case XK_F6: + OnKeyboardF6(my_bShift); + break; + case XK_F7: + OnKeyboardF7(my_bShift); + break; + case XK_F9: + OnKeyboardF9(my_bShift); + break; + } + } +} + +#endif // linux + +void CALLBACK GSclose() { + ZeroGS::Destroy(1); + +#ifdef _WIN32 + if( GShwnd != NULL ) { + DestroyWindow(GShwnd); + GShwnd = NULL; + } +#else + if( GLWin.dpy != NULL ) { + XCloseDisplay(GLWin.dpy); + GLWin.dpy = NULL; + } +#endif +} + +void CALLBACK GSirqCallback(void (*callback)()) { + GSirq = callback; +} + +void CALLBACK GSwriteCSR(u32 write) +{ + gs.CSRw = write; +} + +void CALLBACK GSchangeSaveState(int newstate, const char* filename) +{ + char str[255]; + sprintf(str, "save state %d", newstate); + ZeroGS::AddMessage(str); +} + +void CALLBACK GSmakeSnapshot(char *path) +{ + FILE *bmpfile; + char filename[256]; + u32 snapshotnr = 0; + + // increment snapshot value & try to get filename + for (;;) { + snapshotnr++; + + sprintf(filename,"%ssnap%03ld.%s", path, snapshotnr, (conf.options&GSOPTION_TGASNAP)?"bmp":"jpg"); + + bmpfile=fopen(filename,"rb"); + if (bmpfile == NULL) break; + fclose(bmpfile); + } + + // try opening new snapshot file + if((bmpfile=fopen(filename,"wb"))==NULL) { + char strdir[255]; + +#ifdef _WIN32 + sprintf(strdir, "%s", path); + CreateDirectory(strdir, NULL); +#else + sprintf(strdir, "mkdir %s", path); + system(strdir); +#endif + + if((bmpfile=fopen(filename,"wb"))==NULL) return; + } + + fclose(bmpfile); + + // get the bits + ZeroGS::SaveSnapshot(filename); +} + +int UPDATE_FRAMES = 16; +int g_nFrame = 0; +int g_nRealFrame = 0; + +float fFPS = 0; + +void CALLBACK GSvsync(int interlace) +{ + GS_LOG("\nGSvsync\n\n"); + + static u32 dwTime = timeGetTime(); + static int nToNextUpdate = 1; + char strtitle[256]; + + GL_REPORT_ERRORD(); + + g_nRealFrame++; + + ZeroGS::RenderCRTC(!interlace); + + ProcessMessages(); + + if( --nToNextUpdate <= 0 ) { + + u32 d = timeGetTime(); + fFPS = UPDATE_FRAMES * 1000.0f / (float)max(d-dwTime,1); + dwTime = d; + g_nFrame += UPDATE_FRAMES; + +#ifdef RELEASE_TO_PUBLIC + const char* g_pShaders[4] = { "full", "reduced", "accurate", "accurate-reduced" }; + + sprintf(strtitle, "ZeroGS KOSMOS 0.%d.%d %.1f fps | %s%s%s%s %s (%.1f)", zgsbuild, zgsminor, fFPS, + (conf.interlace < 2) ? "interlace | " : "", + conf.bilinear ? (conf.bilinear==2?"forced bilinear | ":"bilinear | ") : "", + conf.aa ? s_aa[conf.aa] : "", + (g_GameSettings&GAME_FFXHACK) ? "ffxhack | " : "", + g_pShaders[g_nPixelShaderVer], (ppf&0xfffff)/(float)UPDATE_FRAMES); +#else + sprintf(strtitle, "%d | %.1f fps (sk:%d%%) | g: %.1f, t: %.1f, a: %.1f, r: %.1f | p: %.1f | tex: %d %d (%d kbpf)", g_nFrame, fFPS, + 100*g_nFramesSkipped/g_nFrame, + g_nGenVars/(float)UPDATE_FRAMES, g_nTexVars/(float)UPDATE_FRAMES, g_nAlphaVars/(float)UPDATE_FRAMES, + g_nResolve/(float)UPDATE_FRAMES, (ppf&0xfffff)/(float)UPDATE_FRAMES, + ZeroGS::g_MemTargs.listTargets.size(), ZeroGS::g_MemTargs.listClearedTargets.size(), g_TransferredToGPU>>10); + //_snprintf(strtitle, 512, "%x %x", *(int*)(g_pbyGSMemory + 256 * 0x3e0c + 4), *(int*)(g_pbyGSMemory + 256 * 0x3e04 + 4)); + +#endif + +// if( g_nFrame > 100 && fFPS > 60.0f ) { +// DEBUG_LOG("set profile\n"); +// g_bWriteProfile = 1; +// } + +#ifdef _WIN32 + if( !(conf.options&GSOPTION_FULLSCREEN) ) + SetWindowText(GShwnd, strtitle); +#else // linux + XTextProperty prop; + memset(&prop, 0, sizeof(prop)); + char* ptitle = strtitle; + if( XStringListToTextProperty(&ptitle, 1, &prop) ) + XSetWMName(GLWin.dpy, GLWin.win, &prop); + XFree(prop.value); +#endif + + if( fFPS < 16 ) UPDATE_FRAMES = 4; + else if( fFPS < 32 ) UPDATE_FRAMES = 8; + else UPDATE_FRAMES = 16; + + nToNextUpdate = UPDATE_FRAMES; + + g_TransferredToGPU = 0; + g_nGenVars = 0; + g_nTexVars = 0; + g_nAlphaVars = 0; + g_nResolve = 0; + ppf = 0; + g_nFramesSkipped = 0; + } + +#ifndef RELEASE_TO_PUBLIC + if( g_bWriteProfile ) { + //g_bWriteProfile = 0; + DVProfWrite("prof.txt", UPDATE_FRAMES); + DVProfClear(); + } +#endif + GL_REPORT_ERRORD(); +} + +void GIFtag(pathInfo *path, u32 *data) { + + path->tag.nloop = data[0] & 0x7fff; + path->tag.eop = (data[0] >> 15) & 0x1; + u32 tagpre = (data[1] >> 14) & 0x1; + u32 tagprim = (data[1] >> 15) & 0x7ff; + u32 tagflg = (data[1] >> 26) & 0x3; + path->tag.nreg = (data[1] >> 28)<<2; + + if (path->tag.nreg == 0) path->tag.nreg = 64; + + gs.q = 1; + +// GS_LOG("GIFtag: %8.8lx_%8.8lx_%8.8lx_%8.8lx: EOP=%d, NLOOP=%x, FLG=%x, NREG=%d, PRE=%d\n", +// data[3], data[2], data[1], data[0], +// path->tag.eop, path->tag.nloop, tagflg, path->tag.nreg, tagpre); + + path->mode = tagflg+1; + + switch (tagflg) { + case 0x0: + path->regs = *(u64 *)(data+2); + path->regn = 0; + if (tagpre) + GIFRegHandlerPRIM((u32*)&tagprim); + + break; + + case 0x1: + path->regs = *(u64 *)(data+2); + path->regn = 0; + break; + } +} + +void _GSgifPacket(pathInfo *path, u32 *pMem) { // 128bit + + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +void _GSgifRegList(pathInfo *path, u32 *pMem) { // 64bit + int reg; + + reg = (int)((path->regs >> path->regn) & 0xf); + + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) { + path->regn = 0; + path->tag.nloop--; + } +} + +static int nPath3Hack = 0; + +void CALLBACK GSgetLastTag(u64* ptag) +{ + *(u32*)ptag = nPath3Hack; + nPath3Hack = 0; +} + +void _GSgifTransfer(pathInfo *path, u32 *pMem, u32 size) +{ +#ifdef _WIN32 + assert( g_hCurrentThread == GetCurrentThread() ); +#endif + +#ifdef _DEBUG + if( conf.log & 0x20 ) { + static int nSaveIndex=0; + GS_LOG("%d: p:%d %x\n", nSaveIndex++, (path==&gs.path3)?3:(path==&gs.path2?2:1), size); + int vals[4] = {0}; + for(int i = 0; i < size; i++) { + for(int j = 0; j < 4; ++j ) + vals[j] ^= pMem[4*i+j]; + } + GS_LOG("%x %x %x %x\n", vals[0], vals[1], vals[2], vals[3]); + } +#endif + + while(size > 0) + { + //LOG(_T("Transfer(%08x, %d) START\n"), pMem, size); + if (path->tag.nloop == 0) + { + GIFtag(path, pMem); + pMem+= 4; + size--; + + if ((g_GameSettings & GAME_PATH3HACK) && path == &gs.path3 && gs.path3.tag.eop) + nPath3Hack = 1; + + if (path == &gs.path1) + { + // if too much data, just ignore + if (path->tag.nloop * (path->tag.nreg / 4) > (int)size * (path->mode==2?2:1)) + { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) + { + ERROR_LOG("VU1 too much data, ignore if gfx are fine\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + + if (path->mode == 1) + { + // check if 0xb is in any reg, if yes, exit (kh2) + for(int i = 0; i < path->tag.nreg; i += 4) + { + if (((path->regs >> i)&0xf) == 11) + { + static int lasttime = 0; + if( timeGetTime() - lasttime > 5000 ) + { + ERROR_LOG("Invalid unpack type\n"); + lasttime = timeGetTime(); + } + path->tag.nloop = 0; + return; + } + } + } + } + + if(path->tag.nloop == 0 ) + { + if( path == &gs.path1 ) + { + // ffx hack + if( g_GameSettings & GAME_FFXHACK ) + { + if( path->tag.eop ) + return; + continue; + } + + return; + } + + if( !path->tag.eop ) + { + //DEBUG_LOG("continuing from eop\n"); + continue; + } + + break; + } + } + + switch(path->mode) { + case 1: // PACKED + { + assert( path->tag.nloop > 0 ); + for(; size > 0; size--, pMem += 4) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + + g_GIFPackedRegHandlers[reg](pMem); + + path->regn += 4; + if (path->tag.nreg == path->regn) + { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) + { + size--; + pMem += 4; + break; + } + } + } + break; + } + case 2: // REGLIST + { + //GS_LOG("%8.8x%8.8x %d L\n", ((u32*)&gs.regs)[1], *(u32*)&gs.regs, path->tag.nreg/4); + assert( path->tag.nloop > 0 ); + size *= 2; + for(; size > 0; pMem+= 2, size--) + { + int reg = (int)((path->regs >> path->regn) & 0xf); + g_GIFRegHandlers[reg](pMem); + path->regn += 4; + if (path->tag.nreg == path->regn) + { + path->regn = 0; + if( path->tag.nloop-- <= 1 ) + { + size--; + pMem += 2; + break; + } + } + } + + if( size & 1 ) pMem += 2; + size /= 2; + break; + } + case 3: // GIF_IMAGE (FROM_VFRAM) + case 4: // Used in the DirectX version, so we'll use it here too. + { + if(gs.imageTransfer >= 0 && gs.imageTransfer <= 1) + { + int process = min((int)size, path->tag.nloop); + + if( process > 0 ) + { + if ( gs.imageTransfer ) + ZeroGS::TransferLocalHost(pMem, process); + else + ZeroGS::TransferHostLocal(pMem, process*4); + + path->tag.nloop -= process; + pMem += process*4; size -= process; + + assert( size == 0 || path->tag.nloop == 0 ); + } + break; + } + else + { + // simulate + int process = min((int)size, path->tag.nloop); + path->tag.nloop -= process; + pMem += process*4; size -= process; + } + + break; + } + default: // GIF_IMAGE + GS_LOG("*** WARNING **** Unexpected GIFTag flag\n"); + assert(0); + path->tag.nloop = 0; + break; + } + + if( path == &gs.path1 && path->tag.eop ) + return; + } +} + +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size) +{ + //GS_LOG("GSgifTransfer2 size = %lx (mode %d, gs.path2.tag.nloop = %d)\n", size, gs.path2.mode, gs.path2.tag.nloop); + + _GSgifTransfer(&gs.path2, pMem, size); +} + +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size) +{ + //GS_LOG("GSgifTransfer3 size = %lx (mode %d, gs.path3.tag.nloop = %d)\n", size, gs.path3.mode, gs.path3.tag.nloop); + + nPath3Hack = 0; + _GSgifTransfer(&gs.path3, pMem, size); +} + +static int count = 0; +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr) +{ + pathInfo *path = &gs.path1; + + //GS_LOG("GSgifTransfer1 0x%x (mode %d)\n", addr, path->mode); + + addr &= 0x3fff; + +#ifdef _DEBUG + PRIM_LOG("count: %d\n", count); + count++; +#endif + + gs.path1.tag.nloop = 0; + gs.path1.tag.eop = 0; + _GSgifTransfer(&gs.path1, (u32*)((u8*)pMem+addr), (0x4000-addr)/16); + + if( !gs.path1.tag.eop && gs.path1.tag.nloop > 0 ) { + assert( (addr&0xf) == 0 ); //BUG + gs.path1.tag.nloop = 0; + ERROR_LOG("Transfer1 - 2\n"); + return; + } +} + +void CALLBACK GSreadFIFO(u64 *pMem) +{ + //GS_LOG("GSreadFIFO\n"); + + ZeroGS::TransferLocalHost((u32*)pMem, 1); +} + +void CALLBACK GSreadFIFO2(u64 *pMem, int qwc) +{ + //GS_LOG("GSreadFIFO2\n"); + + ZeroGS::TransferLocalHost((u32*)pMem, qwc); +} + +int CALLBACK GSsetupRecording(int start, void* pData) +{ + if( start ) { + if( conf.options & GSOPTION_CAPTUREAVI ) + return 1; + ZeroGS::StartCapture(); + conf.options |= GSOPTION_CAPTUREAVI; + WARN_LOG("ZeroGS: started recording at zerogs.avi\n"); + } + else { + if( !(conf.options & GSOPTION_CAPTUREAVI) ) + return 1; + conf.options &= ~GSOPTION_CAPTUREAVI; + ZeroGS::StopCapture(); + WARN_LOG("ZeroGS: stopped recording\n"); + } + + return 1; +} + +s32 CALLBACK GSfreeze(int mode, freezeData *data) +{ + switch (mode) + { + case FREEZE_LOAD: + if (!ZeroGS::Load(data->data)) ERROR_LOG("GS: Bad load format!"); + g_nRealFrame += 100; + break; + case FREEZE_SAVE: + ZeroGS::Save(data->data); + break; + case FREEZE_SIZE: + data->size = ZeroGS::Save(NULL); + break; + default: + break; + } + + return 0; +} + +//////////////////// +// Small profiler // +//////////////////// +#include +#include +#include +using namespace std; + +#ifdef _WIN32 + +__forceinline u64 GET_PROFILE_TIME() +{ + LARGE_INTEGER lu; + QueryPerformanceCounter(&lu); + return lu.QuadPart; +} +#else +#define GET_PROFILE_TIME() //GetCpuTick() +#endif + + +struct DVPROFSTRUCT; + +struct DVPROFSTRUCT +{ + struct DATA + { + DATA(u64 time, u32 user = 0) : dwTime(time), dwUserData(user) {} + DATA() : dwTime(0), dwUserData(0) {} + + u64 dwTime; + u32 dwUserData; + }; + + ~DVPROFSTRUCT() { + list::iterator it = listpChild.begin(); + while(it != listpChild.end() ) { + SAFE_DELETE(*it); + ++it; + } + } + + list listTimes; // before DVProfEnd is called, contains the global time it started + // after DVProfEnd is called, contains the time it lasted + // the list contains all the tracked times + char pname[256]; + + list listpChild; // other profilers called during this profiler period +}; + +struct DVPROFTRACK +{ + u32 dwUserData; + DVPROFSTRUCT::DATA* pdwTime; + DVPROFSTRUCT* pprof; +}; + +list g_listCurTracking; // the current profiling functions, the back element is the + // one that will first get popped off the list when DVProfEnd is called + // the pointer is an element in DVPROFSTRUCT::listTimes +list g_listProfilers; // the current profilers, note that these are the parents + // any profiler started during the time of another is held in + // DVPROFSTRUCT::listpChild +list g_listAllProfilers; // ignores the hierarchy, pointer to elements in g_listProfilers + +void DVProfRegister(char* pname) +{ + if( !g_bWriteProfile ) + return; + + list::iterator it = g_listAllProfilers.begin(); + +// while(it != g_listAllProfilers.end() ) { +// +// if( _tcscmp(pname, (*it)->pname) == 0 ) { +// (*it)->listTimes.push_back(timeGetTime()); +// DVPROFTRACK dvtrack; +// dvtrack.pdwTime = &(*it)->listTimes.back(); +// dvtrack.pprof = *it; +// g_listCurTracking.push_back(dvtrack); +// return; +// } +// +// ++it; +// } + + // else add in a new profiler to the appropriate parent profiler + DVPROFSTRUCT* pprof = NULL; + + if( g_listCurTracking.size() > 0 ) { + assert( g_listCurTracking.back().pprof != NULL ); + g_listCurTracking.back().pprof->listpChild.push_back(new DVPROFSTRUCT()); + pprof = g_listCurTracking.back().pprof->listpChild.back(); + } + else { + g_listProfilers.push_back(DVPROFSTRUCT()); + pprof = &g_listProfilers.back(); + } + + strncpy(pprof->pname, pname, 256); + + // setup the profiler for tracking + pprof->listTimes.push_back(DVPROFSTRUCT::DATA(GET_PROFILE_TIME())); + + DVPROFTRACK dvtrack; + dvtrack.pdwTime = &pprof->listTimes.back(); + dvtrack.pprof = pprof; + dvtrack.dwUserData = 0; + + g_listCurTracking.push_back(dvtrack); + + // add to all profiler list + g_listAllProfilers.push_back(pprof); +} + +void DVProfEnd(u32 dwUserData) +{ + if( !g_bWriteProfile ) + return; + B_RETURN( g_listCurTracking.size() > 0 ); + + DVPROFTRACK dvtrack = g_listCurTracking.back(); + + assert( dvtrack.pdwTime != NULL && dvtrack.pprof != NULL ); + + dvtrack.pdwTime->dwTime = 1000000 * (GET_PROFILE_TIME()- dvtrack.pdwTime->dwTime) / luPerfFreq; + dvtrack.pdwTime->dwUserData= dwUserData; + + g_listCurTracking.pop_back(); +} + +struct DVTIMEINFO +{ + DVTIMEINFO() : uInclusive(0), uExclusive(0) {} + u64 uInclusive, uExclusive; +}; + +map mapAggregateTimes; + +u64 DVProfWriteStruct(FILE* f, DVPROFSTRUCT* p, int ident) +{ + fprintf(f, "%*s%s - ", ident, "", p->pname); + + list::iterator ittime = p->listTimes.begin(); + + u32 utime = 0; + + while(ittime != p->listTimes.end() ) { + utime += (u32)ittime->dwTime; + + if( ittime->dwUserData ) + fprintf(f, "time: %d, user: 0x%8.8x", (u32)ittime->dwTime, ittime->dwUserData); + else + fprintf(f, "time: %d", (u32)ittime->dwTime); + ++ittime; + } + + mapAggregateTimes[p->pname].uInclusive += utime; + + fprintf(f, "\n"); + + list::iterator itprof = p->listpChild.begin(); + + u32 uex = utime; + while(itprof != p->listpChild.end() ) { + + uex -= DVProfWriteStruct(f, *itprof, ident+4); + ++itprof; + } + + mapAggregateTimes[p->pname].uExclusive += uex; + return utime; +} + +void DVProfWrite(char* pfilename, u32 frames) +{ + assert( pfilename != NULL ); + FILE* f = fopen(pfilename, "wb"); + + mapAggregateTimes.clear(); + list::iterator it = g_listProfilers.begin(); + + while(it != g_listProfilers.end() ) { + DVProfWriteStruct(f, &(*it), 0); + ++it; + } + + { + map::iterator it; + fprintf(f, "\n\n-------------------------------------------------------------------\n\n"); + + u64 uTotal[2] = {0}; + double fiTotalTime[2]; + + for(it = mapAggregateTimes.begin(); it != mapAggregateTimes.end(); ++it) { + uTotal[0] += it->second.uExclusive; + uTotal[1] += it->second.uInclusive; + } + + fprintf(f, "total times (%d): ex: %Lu ", frames, uTotal[0]/frames); + fprintf(f, "inc: %Lu\n", uTotal[1]/frames); + + fiTotalTime[0] = 1.0 / (double)uTotal[0]; + fiTotalTime[1] = 1.0 / (double)uTotal[1]; + + // output the combined times + for(it = mapAggregateTimes.begin(); it != mapAggregateTimes.end(); ++it) { + fprintf(f, "%s - ex: %f inc: %f\n", it->first.c_str(), (double)it->second.uExclusive * fiTotalTime[0], + (double)it->second.uInclusive * fiTotalTime[1]); + } + } + + + fclose(f); +} + +void DVProfClear() +{ + g_listCurTracking.clear(); + g_listProfilers.clear(); + g_listAllProfilers.clear(); +} diff --git a/plugins/zerogs/opengl/Linux/Conf.cpp b/plugins/zerogs/opengl/Linux/Conf.cpp new file mode 100644 index 0000000000..23cf91b75a --- /dev/null +++ b/plugins/zerogs/opengl/Linux/Conf.cpp @@ -0,0 +1,114 @@ +/* GSsoft + * Copyright (C) 2002-2004 GSsoft Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "GS.h" + +extern string s_strIniPath; + +void SaveConfig() +{ + FILE *f; + char cfg[255]; + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg,"w"); + if (f == NULL) + { + printf("failed to open %s\n", s_strIniPath.c_str()); + return; + } + + fprintf(f, "interlace = %x\n", conf.interlace); + fprintf(f, "mrtdepth = %x\n", conf.mrtdepth); + fprintf(f, "options = %x\n", conf.options); + fprintf(f, "bilinear = %x\n", conf.bilinear); + fprintf(f, "aliasing = %x\n", conf.aa); + fprintf(f, "gamesettings = %x\n", conf.gamesettings); + fclose(f); +} + +void LoadConfig() +{ + FILE *f; + char cfg[255]; + + memset(&conf, 0, sizeof(conf)); + conf.interlace = 0; // on, mode 1 + conf.mrtdepth = 1; + conf.options = 0; + conf.bilinear = 1; + conf.width = 640; + conf.height = 480; + conf.aa = 0; + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg, "r"); + if (f == NULL) + { + printf("failed to open %s\n", s_strIniPath.c_str()); + SaveConfig();//save and return + return; + } + fscanf(f, "interlace = %x\n", &conf.interlace); + fscanf(f, "mrtdepth = %x\n", &conf.mrtdepth); + fscanf(f, "options = %x\n", &conf.options); + fscanf(f, "bilinear = %x\n", &conf.bilinear); + fscanf(f, "aliasing = %x\n", &conf.aa); + fscanf(f, "gamesettings = %x\n", &conf.gamesettings); + fclose(f); + + // filter bad files + if ((conf.aa < 0) || (conf.aa > 4)) conf.aa = 0; + + switch(conf.options & GSOPTION_WINDIMS) + { + case GSOPTION_WIN640: + conf.width = 640; + conf.height = 480; + break; + case GSOPTION_WIN800: + conf.width = 800; + conf.height = 600; + break; + case GSOPTION_WIN1024: + conf.width = 1024; + conf.height = 768; + break; + case GSOPTION_WIN1280: + conf.width = 1280; + conf.height = 960; + break; + } + + // turn off all hacks by default + conf.options &= ~(GSOPTION_FULLSCREEN | GSOPTION_WIREFRAME | GSOPTION_CAPTUREAVI); + conf.options |= GSOPTION_LOADED; + + if( conf.width <= 0 || conf.height <= 0 ) + { + conf.width = 640; + conf.height = 480; + } +} + diff --git a/plugins/zerogs/opengl/Linux/Linux.cpp b/plugins/zerogs/opengl/Linux/Linux.cpp new file mode 100644 index 0000000000..88f81d61c0 --- /dev/null +++ b/plugins/zerogs/opengl/Linux/Linux.cpp @@ -0,0 +1,430 @@ +/* ZeroGS + * Copyright (C) 2002-2004 GSsoft Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "GS.h" + +extern "C" { +#include "interface.h" +#include "support.h" +#include "callbacks.h" +} + +#include "Linux.h" + +#include + +static int prevbilinearfilter; +//static map mapConfOpts; +struct confOptsStruct +{ + int value; + const char *desc; +}confOpts; + +static map mapConfOpts; + +extern void OnKeyboardF5(int); +extern void OnKeyboardF6(int); +extern void OnKeyboardF7(int); +extern void OnKeyboardF9(int); + +GtkWidget *About; + +void CALLBACK GSkeyEvent(keyEvent *ev) +{ + //static bool bShift = false; + static bool bAlt = false; + + switch(ev->evt) { + case KEYPRESS: + switch(ev->key) { + case XK_F5: + case XK_F6: + case XK_F7: + case XK_F9: + THR_KeyEvent = ev->key ; + break; + case XK_Escape: + break; + case XK_Shift_L: + case XK_Shift_R: + //bShift = true; + THR_bShift = true; + break; + case XK_Alt_L: + case XK_Alt_R: + bAlt = true; + break; + } + break; + case KEYRELEASE: + switch(ev->key) { + case XK_Shift_L: + case XK_Shift_R: + //bShift = false; + THR_bShift = false; + break; + case XK_Alt_L: + case XK_Alt_R: + bAlt = false; + break; + } + } +} + +GtkWidget *Conf; +GtkWidget *Logging; +GList *fresl; +GList *wresl; +GList *cachesizel; +GList *codecl; +GList *filtersl; + +void OnConf_Ok(GtkButton *button, gpointer user_data) +{ + GtkWidget *Btn; + GtkWidget *treeview; + GtkTreeModel *treemodel; + GtkTreeIter treeiter; + gboolean treeoptval; + gchar *gbuf; + char *str; + int i; + + u32 newinterlace = is_checked(Conf, "checkInterlace"); + + if (!conf.interlace ) + conf.interlace = newinterlace; + else if (!newinterlace ) + conf.interlace = 2; // off + + conf.bilinear = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkBilinear"))); + // restore + if (conf.bilinear && prevbilinearfilter) + conf.bilinear = prevbilinearfilter; + + //conf.mrtdepth = 1;//IsDlgButtonChecked(hW, IDC_CONFIG_DEPTHWRITE); + + if is_checked(Conf, "radioAANone") + conf.aa = 0; + else if is_checked(Conf, "radioAA2X") + conf.aa = 1; + else if is_checked(Conf, "radioAA4X") + conf.aa = 2; + else if is_checked(Conf, "radioAA8X") + conf.aa = 3; + else + conf.aa = 4; + + conf.options = 0; + conf.options |= is_checked(Conf, "checkAVI") ? GSOPTION_CAPTUREAVI : 0; + conf.options |= is_checked(Conf, "checkWireframe") ? GSOPTION_WIREFRAME : 0; + conf.options |= is_checked(Conf, "checkfullscreen") ? GSOPTION_FULLSCREEN : 0; + conf.options |= is_checked(Conf, "checkTGA") ? GSOPTION_TGASNAP : 0; + + //------- get advanced options from the treeview model -------// + treeview = lookup_widget(Conf,"treeview1"); + treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); + gtk_tree_model_get_iter_first(treemodel, &treeiter); + + conf.gamesettings = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) + { + treeoptval = FALSE; + gtk_tree_model_get(treemodel, &treeiter, 0, &treeoptval, -1); + + if(treeoptval) conf.gamesettings |= it->second.value; + + gtk_tree_model_iter_next(treemodel,&treeiter); + } + + GSsetGameCRC(0, conf.gamesettings); + //---------- done getting advanced options ---------// + + if is_checked(Conf, "radioSize640") + conf.options |= GSOPTION_WIN640; + else if is_checked(Conf, "radioSize800") + conf.options |= GSOPTION_WIN800; + else if is_checked(Conf, "radioSize1024") + conf.options |= GSOPTION_WIN1024; + else if is_checked(Conf, "radioSize1280") + conf.options |= GSOPTION_WIN1280; + + SaveConfig(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void CALLBACK GSconfigure() +{ + char name[32]; + char descbuf[255]; + int nmodes, i; + bool itval; + GtkWidget *treeview; + GtkCellRenderer *treerend; + GtkListStore *treestore;//Gets typecast as GtkTreeModel as needed. + GtkTreeIter treeiter; + GtkTreeViewColumn *treecol; + + if (!(conf.options & GSOPTION_LOADED)) LoadConfig(); + Conf = create_Config(); + + set_checked(Conf, "checkBilinear", !!conf.bilinear); + //set_checked(Conf, "checkbutton6", conf.mrtdepth); + set_checked(Conf, "radioAANone", conf.aa==0); + set_checked(Conf, "radioAA2X", conf.aa==1); + set_checked(Conf, "radioAA4X", conf.aa==2); + set_checked(Conf, "radioAA8X", conf.aa==3); + set_checked(Conf, "radioAA16X", conf.aa==4); + set_checked(Conf, "checkWireframe", (conf.options&GSOPTION_WIREFRAME)?1:0); + set_checked(Conf, "checkAVI", (conf.options&GSOPTION_CAPTUREAVI)?1:0); + set_checked(Conf, "checkfullscreen", (conf.options&GSOPTION_FULLSCREEN)?1:0); + set_checked(Conf, "checkTGA", (conf.options&GSOPTION_TGASNAP)?1:0); + + set_checked(Conf, "radioSize640", ((conf.options&GSOPTION_WINDIMS)>>4)==0); + set_checked(Conf, "radioSize800", ((conf.options&GSOPTION_WINDIMS)>>4)==1); + set_checked(Conf, "radioSize1024", ((conf.options&GSOPTION_WINDIMS)>>4)==2); + set_checked(Conf, "radioSize1280", ((conf.options&GSOPTION_WINDIMS)>>4)==3); + + prevbilinearfilter = conf.bilinear; + + //--------- Let's build a treeview for our advanced options! --------// + treeview = lookup_widget(Conf,"treeview1"); + treestore = gtk_list_store_new(2,G_TYPE_BOOLEAN, G_TYPE_STRING); + + //setup columns in treeview + //COLUMN 0 is the checkboxes + treecol = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(treecol, "Select"); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), treecol); + treerend = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(treecol, treerend, TRUE); + gtk_tree_view_column_add_attribute(treecol, treerend, "active", 0);//link 'active' attrib to first column of model + g_object_set(treerend, "activatable", TRUE, NULL);//set 'activatable' attrib true by default for all rows regardless of model. + g_signal_connect(treerend, "toggled", (GCallback) OnToggle_advopts, treestore);//set a global callback, we also pass a reference to our treestore. + + //COLUMN 1 is the text descriptions + treecol = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(treecol, "Description"); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), treecol); + treerend = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(treecol, treerend, TRUE); + gtk_tree_view_column_add_attribute(treecol, treerend, "text", 1);//link 'text' attrib to second column of model + + //setup the model with all our rows of option data + mapConfOpts.clear(); + confOpts.value = 0x00000001; + confOpts.desc = "Tex Target checking - 00000001\nLego Racers"; + mapConfOpts["00000001"] = confOpts; + confOpts.value = 0x00000002; + confOpts.desc = "Auto reset targs - 00000002\nShadow Hearts, Samurai Warriors. Use when game is slow and toggling AA fixes it."; + mapConfOpts["00000002"] = confOpts; + confOpts.value = 0x00000004; + confOpts.desc = "Interlace 2X - 00000004\nFixes 2x bigger screen (Gradius 3)."; + mapConfOpts["00000004"] = confOpts; + confOpts.value = 0x00000008; + confOpts.desc = "Text Alpha hack - 00000008\nNightmare Before Christmas."; + mapConfOpts["00000008"] = confOpts; + confOpts.value = 0x00000010; + confOpts.desc = "No target resolves - 00000010\nStops all resolving of targets. Try this first for really slow games."; + mapConfOpts["00000010"] = confOpts; + confOpts.value = 0x00000020; + confOpts.desc = "Exact color testing - 00000020\nFixes overbright or shadow/black artifacts (Crash 'n Burn)."; + mapConfOpts["00000020"] = confOpts; + confOpts.value = 0x00000040; + confOpts.desc = "No color clamping - 00000040\nSpeeds up games, but might be too bright or too dim."; + mapConfOpts["00000040"] = confOpts; + confOpts.value = 0x00000080; + confOpts.desc = "FFX hack - 00000080\nShows missing geometry."; + mapConfOpts["00000080"] = confOpts; + confOpts.value = 0x00000200; + confOpts.desc = "Disable depth updates - 00000200"; + mapConfOpts["00000200"] = confOpts; + confOpts.value = 0x00000400; + confOpts.desc = "Resolve Hack #1 - 00000400\nKingdom Hearts. Speeds some games."; + mapConfOpts["00000400"] = confOpts; + confOpts.value = 0x00000800; + confOpts.desc = "Resolve Hack #2 - 00000800\nShadow Hearts, Urbz."; + mapConfOpts["00000800"] = confOpts; + confOpts.value = 0x00001000; + confOpts.desc = "No target CLUT - 00001000\nResident Evil 4, or foggy scenes."; + mapConfOpts["00001000"] = confOpts; + confOpts.value = 0x00002000; + confOpts.desc = "Disable stencil buffer - 00002000\nUsually safe to do for simple scenes."; + mapConfOpts["00002000"] = confOpts; + confOpts.value = 0x00004000; + confOpts.desc = "No vertical stripes - 00004000\nTry when there's a lot of garbage on screen."; + mapConfOpts["00004000"] = confOpts; + confOpts.value = 0x00008000; + confOpts.desc = "No depth resolve - 00008000\nMight give z buffer artifacts."; + mapConfOpts["00008000"] = confOpts; + confOpts.value = 0x00010000; + confOpts.desc = "Full 16 bit resolution - 00010000\nUse when half the screen is missing."; + mapConfOpts["00010000"] = confOpts; + confOpts.value = 0x00020000; + confOpts.desc = "Resolve Hack #3 - 00020000\nNeopets"; + mapConfOpts["00020000"] = confOpts; + confOpts.value = 0x00040000; + confOpts.desc = "Fast Update - 00040000\nOkami. Speeds some games."; + mapConfOpts["00040000"] = confOpts; + confOpts.value = 0x00080000; + confOpts.desc = "Disable alpha testing - 00080000"; + mapConfOpts["00080000"] = confOpts; + confOpts.value = 0x00100000; + confOpts.desc = "Disable Multiple RTs - 00100000"; + mapConfOpts["00100000"] = confOpts; + confOpts.value = 0x00200000; + confOpts.desc = "32 bit render targets - 00200000"; + mapConfOpts["00200000"] = confOpts; + + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) + { + gtk_list_store_append(treestore, &treeiter);//new row + itval = (conf.gamesettings&it->second.value)?TRUE:FALSE; + snprintf(descbuf, 254, "%s", it->second.desc); + gtk_list_store_set(treestore, &treeiter, 0, itval, 1, descbuf, -1); + } + + gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(treestore));//NB: store is cast as tree model. + g_object_unref(treestore);//allow model to be destroyed when the tree is destroyed. + + //don't select/highlight rows + gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), GTK_SELECTION_NONE); + //------treeview done -------// + + //Let's do it! + gtk_widget_show_all(Conf); + gtk_main(); +} + +void OnToggle_advopts(GtkCellRendererToggle *cell, gchar *path, gpointer user_data) +{ + GtkTreeIter treeiter; + gboolean val; + + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(user_data), &treeiter, path); + gtk_tree_model_get(GTK_TREE_MODEL(user_data), &treeiter, 0, &val, -1); + val = !val; + gtk_list_store_set(GTK_LIST_STORE(user_data), &treeiter, 0, val, -1); + +} + +void OnAbout_Ok(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CALLBACK GSabout() +{ + About = create_About(); + + gtk_widget_show_all(About); + gtk_main(); +} + +s32 CALLBACK GStest() +{ + return 0; +} + +GtkWidget *MsgDlg; + +void OnMsg_Ok() +{ + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void SysMessage(char *fmt, ...) +{ + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "GSsoft Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +void *SysLoadLibrary(char *lib) +{ + return dlopen(lib, RTLD_NOW | RTLD_GLOBAL); +} + +void *SysLoadSym(void *lib, char *sym) +{ + void *ret = dlsym(lib, sym); + if (ret == NULL) printf("null: %s\n", sym); + return dlsym(lib, sym); +} + +char *SysLibError() +{ + return dlerror(); +} + +void SysCloseLibrary(void *lib) +{ + dlclose(lib); +} diff --git a/plugins/zerogs/opengl/Linux/Linux.h b/plugins/zerogs/opengl/Linux/Linux.h new file mode 100644 index 0000000000..6e52bc220f --- /dev/null +++ b/plugins/zerogs/opengl/Linux/Linux.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2002-2004 GSsoft Team + * + * 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 __LINUX_H__ +#define __LINUX_H__ +#endif + +void OnToggle_advopts(GtkCellRendererToggle *cell, gchar *path, gpointer user_data); + +#define is_checked(main_widget, widget_name) (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)))) +#define set_checked(main_widget,widget_name, state) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)), state) diff --git a/plugins/zerogs/opengl/Linux/Makefile.am b/plugins/zerogs/opengl/Linux/Makefile.am new file mode 100644 index 0000000000..b95d86a02a --- /dev/null +++ b/plugins/zerogs/opengl/Linux/Makefile.am @@ -0,0 +1,6 @@ +noinst_LIBRARIES = libZeroGSLinux.a +libZeroGSLinux_a_CPPFLAGS = -fPIC +libZeroGSLinux_a_CXXFLAGS = -fPIC +libZeroGSLinux_a_CFLAGS = -fPIC +INCLUDES = $(shell pkg-config --cflags gtk+-2.0) -I@srcdir@/../ -I@srcdir@/../common +libZeroGSLinux_a_SOURCES = callbacks.c Conf.cpp interface.c Linux.cpp support.c diff --git a/plugins/zerogs/opengl/Linux/buildgui.sh b/plugins/zerogs/opengl/Linux/buildgui.sh new file mode 100644 index 0000000000..9f0d1fcefb --- /dev/null +++ b/plugins/zerogs/opengl/Linux/buildgui.sh @@ -0,0 +1,9 @@ +# builds the GUI C classes +mkdir temp +cp zerogs.glade temp/ +cd temp +glade-2 --write-source zerogs.glade +rm src/main.c +cp src/*.h src/*.c ../ +cd .. +/bin/rm -rf temp diff --git a/plugins/zerogs/opengl/Linux/callbacks.c b/plugins/zerogs/opengl/Linux/callbacks.c new file mode 100644 index 0000000000..e87ed8be2d --- /dev/null +++ b/plugins/zerogs/opengl/Linux/callbacks.c @@ -0,0 +1,34 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/zerogs/opengl/Linux/callbacks.h b/plugins/zerogs/opengl/Linux/callbacks.h new file mode 100644 index 0000000000..e606c242f0 --- /dev/null +++ b/plugins/zerogs/opengl/Linux/callbacks.h @@ -0,0 +1,14 @@ +#include + + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnAbout_Ok (GtkButton *button, + gpointer user_data); diff --git a/plugins/zerogs/opengl/Linux/interface.c b/plugins/zerogs/opengl/Linux/interface.c new file mode 100644 index 0000000000..29af19426e --- /dev/null +++ b/plugins/zerogs/opengl/Linux/interface.c @@ -0,0 +1,341 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ + g_object_set_data (G_OBJECT (component), name, widget) + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *vbox4; + GtkWidget *checkInterlace; + GtkWidget *checkBilinear; + GtkWidget *frame4; + GtkWidget *alignment1; + GtkWidget *hbox6; + GtkWidget *radioAANone; + GSList *radioAANone_group = NULL; + GtkWidget *radioAA2X; + GtkWidget *radioAA4X; + GtkWidget *radioAA8X; + GtkWidget *radioAA16X; + GtkWidget *label9; + GtkWidget *checkWireframe; + GtkWidget *checkAVI; + GtkWidget *checkTGA; + GtkWidget *checkfullscreen; + GtkWidget *frame5; + GtkWidget *alignment2; + GtkWidget *hbox7; + GtkWidget *radioSize640; + GSList *radioSize640_group = NULL; + GtkWidget *radioSize800; + GtkWidget *radioSize1024; + GtkWidget *radioSize1280; + GtkWidget *label10; + GtkWidget *frame6; + GtkWidget *alignment3; + GtkWidget *scrolledwindow1; + GtkWidget *treeview1; + GtkWidget *label12; + GtkWidget *label11; + GtkWidget *hbuttonbox1; + GtkWidget *button1; + GtkWidget *button2; + + Config = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (Config), 5); + gtk_window_set_title (GTK_WINDOW (Config), _("ZeroOGS Configuration")); + + vbox4 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox4); + gtk_container_add (GTK_CONTAINER (Config), vbox4); + + checkInterlace = gtk_check_button_new_with_mnemonic (_("Interlace Enable (toggle with F5)\n there are 2 modes + interlace off")); + gtk_widget_show (checkInterlace); + gtk_box_pack_start (GTK_BOX (vbox4), checkInterlace, FALSE, FALSE, 0); + + checkBilinear = gtk_check_button_new_with_mnemonic (_("Bilinear Filtering (Shift+F5)\n Best quality is on, turn off for speed")); + gtk_widget_show (checkBilinear); + gtk_box_pack_start (GTK_BOX (vbox4), checkBilinear, FALSE, FALSE, 0); + + frame4 = gtk_frame_new (NULL); + gtk_widget_show (frame4); + gtk_box_pack_start (GTK_BOX (vbox4), frame4, TRUE, TRUE, 0); + + alignment1 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (frame4), alignment1); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment1), 0, 0, 12, 0); + + hbox6 = gtk_hbox_new (TRUE, 0); + gtk_widget_show (hbox6); + gtk_container_add (GTK_CONTAINER (alignment1), hbox6); + + radioAANone = gtk_radio_button_new_with_mnemonic (NULL, _("None")); + gtk_widget_show (radioAANone); + gtk_box_pack_start (GTK_BOX (hbox6), radioAANone, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioAANone), radioAANone_group); + radioAANone_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioAANone)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radioAANone), TRUE); + + radioAA2X = gtk_radio_button_new_with_mnemonic (NULL, _("2X")); + gtk_widget_show (radioAA2X); + gtk_box_pack_start (GTK_BOX (hbox6), radioAA2X, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioAA2X), radioAANone_group); + radioAANone_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioAA2X)); + + radioAA4X = gtk_radio_button_new_with_mnemonic (NULL, _("4X")); + gtk_widget_show (radioAA4X); + gtk_box_pack_start (GTK_BOX (hbox6), radioAA4X, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioAA4X), radioAANone_group); + radioAANone_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioAA4X)); + + radioAA8X = gtk_radio_button_new_with_mnemonic (NULL, _("8X")); + gtk_widget_show (radioAA8X); + gtk_box_pack_start (GTK_BOX (hbox6), radioAA8X, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioAA8X), radioAANone_group); + radioAANone_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioAA8X)); + + radioAA16X = gtk_radio_button_new_with_mnemonic (NULL, _("16X")); + gtk_widget_show (radioAA16X); + gtk_box_pack_start (GTK_BOX (hbox6), radioAA16X, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioAA16X), radioAANone_group); + radioAANone_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioAA16X)); + + label9 = gtk_label_new (_("Anti-aliasing for higher quality (F6)")); + gtk_widget_show (label9); + gtk_frame_set_label_widget (GTK_FRAME (frame4), label9); + gtk_label_set_use_markup (GTK_LABEL (label9), TRUE); + + checkWireframe = gtk_check_button_new_with_mnemonic (_("Wireframe rendering (Shift+F6)")); + gtk_widget_show (checkWireframe); + gtk_box_pack_start (GTK_BOX (vbox4), checkWireframe, FALSE, FALSE, 0); + + checkAVI = gtk_check_button_new_with_mnemonic (_("Capture Avi (zerogs.avi)(F7)")); + gtk_widget_show (checkAVI); + gtk_box_pack_start (GTK_BOX (vbox4), checkAVI, FALSE, FALSE, 0); + + checkTGA = gtk_check_button_new_with_mnemonic (_("Save Snapshots as TGAs (default is JPG)")); + gtk_widget_show (checkTGA); + gtk_box_pack_start (GTK_BOX (vbox4), checkTGA, FALSE, FALSE, 0); + + checkfullscreen = gtk_check_button_new_with_mnemonic (_("Fullscreen (Alt+Enter)\n to get out press Alt+Enter again (or ESC)")); + gtk_widget_show (checkfullscreen); + gtk_box_pack_start (GTK_BOX (vbox4), checkfullscreen, FALSE, FALSE, 0); + + frame5 = gtk_frame_new (NULL); + gtk_widget_show (frame5); + gtk_box_pack_start (GTK_BOX (vbox4), frame5, TRUE, TRUE, 0); + + alignment2 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment2); + gtk_container_add (GTK_CONTAINER (frame5), alignment2); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment2), 0, 0, 12, 0); + + hbox7 = gtk_hbox_new (TRUE, 0); + gtk_widget_show (hbox7); + gtk_container_add (GTK_CONTAINER (alignment2), hbox7); + + radioSize640 = gtk_radio_button_new_with_mnemonic (NULL, _("640x480")); + gtk_widget_show (radioSize640); + gtk_box_pack_start (GTK_BOX (hbox7), radioSize640, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioSize640), radioSize640_group); + radioSize640_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioSize640)); + + radioSize800 = gtk_radio_button_new_with_mnemonic (NULL, _("800x600")); + gtk_widget_show (radioSize800); + gtk_box_pack_start (GTK_BOX (hbox7), radioSize800, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioSize800), radioSize640_group); + radioSize640_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioSize800)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radioSize800), TRUE); + + radioSize1024 = gtk_radio_button_new_with_mnemonic (NULL, _("1024x768")); + gtk_widget_show (radioSize1024); + gtk_box_pack_start (GTK_BOX (hbox7), radioSize1024, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioSize1024), radioSize640_group); + radioSize640_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioSize1024)); + + radioSize1280 = gtk_radio_button_new_with_mnemonic (NULL, _("1280x960")); + gtk_widget_show (radioSize1280); + gtk_box_pack_start (GTK_BOX (hbox7), radioSize1280, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (radioSize1280), radioSize640_group); + radioSize640_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radioSize1280)); + + label10 = gtk_label_new (_("Default Window Size (no speed impact)")); + gtk_widget_show (label10); + gtk_frame_set_label_widget (GTK_FRAME (frame5), label10); + gtk_label_set_use_markup (GTK_LABEL (label10), TRUE); + + frame6 = gtk_frame_new (NULL); + gtk_widget_show (frame6); + gtk_box_pack_start (GTK_BOX (vbox4), frame6, TRUE, TRUE, 0); + + alignment3 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment3); + gtk_container_add (GTK_CONTAINER (frame6), alignment3); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment3), 0, 0, 12, 0); + + scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_show (scrolledwindow1); + gtk_container_add (GTK_CONTAINER (alignment3), scrolledwindow1); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_SHADOW_IN); + + treeview1 = gtk_tree_view_new (); + gtk_widget_show (treeview1); + gtk_container_add (GTK_CONTAINER (scrolledwindow1), treeview1); + + label12 = gtk_label_new (_("Advanced Options")); + gtk_widget_show (label12); + gtk_frame_set_label_widget (GTK_FRAME (frame6), label12); + gtk_label_set_use_markup (GTK_LABEL (label12), TRUE); + + label11 = gtk_label_new (_("Show Frames Per Second (Shift+F7)\n (value is the average over 4-16 PS2 frames)")); + gtk_widget_show (label11); + gtk_box_pack_start (GTK_BOX (vbox4), label11, FALSE, FALSE, 0); + + hbuttonbox1 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox1); + gtk_box_pack_start (GTK_BOX (vbox4), hbuttonbox1, TRUE, TRUE, 0); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); + gtk_box_set_spacing (GTK_BOX (hbuttonbox1), 30); + + button1 = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (button1); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + button2 = gtk_button_new_with_mnemonic (_("Cancel")); + gtk_widget_show (button2); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); + GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button1, "clicked", + G_CALLBACK (OnConf_Ok), + NULL); + g_signal_connect ((gpointer) button2, "clicked", + G_CALLBACK (OnConf_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (Config, Config, "Config"); + GLADE_HOOKUP_OBJECT (Config, vbox4, "vbox4"); + GLADE_HOOKUP_OBJECT (Config, checkInterlace, "checkInterlace"); + GLADE_HOOKUP_OBJECT (Config, checkBilinear, "checkBilinear"); + GLADE_HOOKUP_OBJECT (Config, frame4, "frame4"); + GLADE_HOOKUP_OBJECT (Config, alignment1, "alignment1"); + GLADE_HOOKUP_OBJECT (Config, hbox6, "hbox6"); + GLADE_HOOKUP_OBJECT (Config, radioAANone, "radioAANone"); + GLADE_HOOKUP_OBJECT (Config, radioAA2X, "radioAA2X"); + GLADE_HOOKUP_OBJECT (Config, radioAA4X, "radioAA4X"); + GLADE_HOOKUP_OBJECT (Config, radioAA8X, "radioAA8X"); + GLADE_HOOKUP_OBJECT (Config, radioAA16X, "radioAA16X"); + GLADE_HOOKUP_OBJECT (Config, label9, "label9"); + GLADE_HOOKUP_OBJECT (Config, checkWireframe, "checkWireframe"); + GLADE_HOOKUP_OBJECT (Config, checkAVI, "checkAVI"); + GLADE_HOOKUP_OBJECT (Config, checkTGA, "checkTGA"); + GLADE_HOOKUP_OBJECT (Config, checkfullscreen, "checkfullscreen"); + GLADE_HOOKUP_OBJECT (Config, frame5, "frame5"); + GLADE_HOOKUP_OBJECT (Config, alignment2, "alignment2"); + GLADE_HOOKUP_OBJECT (Config, hbox7, "hbox7"); + GLADE_HOOKUP_OBJECT (Config, radioSize640, "radioSize640"); + GLADE_HOOKUP_OBJECT (Config, radioSize800, "radioSize800"); + GLADE_HOOKUP_OBJECT (Config, radioSize1024, "radioSize1024"); + GLADE_HOOKUP_OBJECT (Config, radioSize1280, "radioSize1280"); + GLADE_HOOKUP_OBJECT (Config, label10, "label10"); + GLADE_HOOKUP_OBJECT (Config, frame6, "frame6"); + GLADE_HOOKUP_OBJECT (Config, alignment3, "alignment3"); + GLADE_HOOKUP_OBJECT (Config, scrolledwindow1, "scrolledwindow1"); + GLADE_HOOKUP_OBJECT (Config, treeview1, "treeview1"); + GLADE_HOOKUP_OBJECT (Config, label12, "label12"); + GLADE_HOOKUP_OBJECT (Config, label11, "label11"); + GLADE_HOOKUP_OBJECT (Config, hbuttonbox1, "hbuttonbox1"); + GLADE_HOOKUP_OBJECT (Config, button1, "button1"); + GLADE_HOOKUP_OBJECT (Config, button2, "button2"); + + return Config; +} + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + GtkWidget *vbox2; + GtkWidget *label2; + GtkWidget *label3; + GtkWidget *label4; + GtkWidget *hbuttonbox2; + GtkWidget *button3; + + About = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_window_set_title (GTK_WINDOW (About), _("ZeroGS KOSMOS About")); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (About), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + label2 = gtk_label_new (_("OpenGL version")); + gtk_widget_show (label2); + gtk_box_pack_start (GTK_BOX (vbox2), label2, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_CENTER); + + label3 = gtk_label_new (_("Author: zerofrog(@gmail.com)")); + gtk_widget_show (label3); + gtk_box_pack_start (GTK_BOX (vbox2), label3, FALSE, FALSE, 0); + + label4 = gtk_label_new (_("Many thanks to the Pcsx2 testing team")); + gtk_widget_show (label4); + gtk_box_pack_start (GTK_BOX (vbox2), label4, FALSE, FALSE, 0); + + hbuttonbox2 = gtk_hbutton_box_new (); + gtk_widget_show (hbuttonbox2); + gtk_box_pack_start (GTK_BOX (vbox2), hbuttonbox2, TRUE, TRUE, 0); + gtk_box_set_spacing (GTK_BOX (hbuttonbox2), 30); + + button3 = gtk_button_new_with_mnemonic (_("Ok")); + gtk_widget_show (button3); + gtk_container_add (GTK_CONTAINER (hbuttonbox2), button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) button3, "clicked", + G_CALLBACK (OnAbout_Ok), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (About, About, "About"); + GLADE_HOOKUP_OBJECT (About, vbox2, "vbox2"); + GLADE_HOOKUP_OBJECT (About, label2, "label2"); + GLADE_HOOKUP_OBJECT (About, label3, "label3"); + GLADE_HOOKUP_OBJECT (About, label4, "label4"); + GLADE_HOOKUP_OBJECT (About, hbuttonbox2, "hbuttonbox2"); + GLADE_HOOKUP_OBJECT (About, button3, "button3"); + + return About; +} + diff --git a/plugins/zerogs/opengl/Linux/interface.h b/plugins/zerogs/opengl/Linux/interface.h new file mode 100644 index 0000000000..69c303ba3b --- /dev/null +++ b/plugins/zerogs/opengl/Linux/interface.h @@ -0,0 +1,6 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_Config (void); +GtkWidget* create_About (void); diff --git a/plugins/zerogs/opengl/Linux/support.c b/plugins/zerogs/opengl/Linux/support.c new file mode 100644 index 0000000000..00aff29822 --- /dev/null +++ b/plugins/zerogs/opengl/Linux/support.c @@ -0,0 +1,144 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "support.h" + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (!parent) + parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to find pixmap files. */ +static gchar* +find_pixmap_file (const gchar *filename) +{ + GList *elem; + + /* We step through each of the pixmaps directory to find it. */ + elem = pixmaps_directories; + while (elem) + { + gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, + G_DIR_SEPARATOR_S, filename); + if (g_file_test (pathname, G_FILE_TEST_EXISTS)) + return pathname; + g_free (pathname); + elem = elem->next; + } + return NULL; +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *pathname = NULL; + GtkWidget *pixmap; + + if (!filename || !filename[0]) + return gtk_image_new (); + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return gtk_image_new (); + } + + pixmap = gtk_image_new_from_file (pathname); + g_free (pathname); + return pixmap; +} + +/* This is an internally used function to create pixmaps. */ +GdkPixbuf* +create_pixbuf (const gchar *filename) +{ + gchar *pathname = NULL; + GdkPixbuf *pixbuf; + GError *error = NULL; + + if (!filename || !filename[0]) + return NULL; + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return NULL; + } + + pixbuf = gdk_pixbuf_new_from_file (pathname, &error); + if (!pixbuf) + { + fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", + pathname, error->message); + g_error_free (error); + } + g_free (pathname); + return pixbuf; +} + +/* This is used to set ATK action descriptions. */ +void +glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description) +{ + gint n_actions, i; + + n_actions = atk_action_get_n_actions (action); + for (i = 0; i < n_actions; i++) + { + if (!strcmp (atk_action_get_name (action, i), action_name)) + atk_action_set_description (action, i, description); + } +} + diff --git a/plugins/zerogs/opengl/Linux/support.h b/plugins/zerogs/opengl/Linux/support.h new file mode 100644 index 0000000000..a32649e53c --- /dev/null +++ b/plugins/zerogs/opengl/Linux/support.h @@ -0,0 +1,69 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# define Q_(String) g_strip_context ((String), gettext (String)) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define Q_(String) g_strip_context ((String), (String)) +# define N_(String) (String) +#endif + + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps used in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + +/* This is used to create the pixbufs used in the interface. */ +GdkPixbuf* create_pixbuf (const gchar *filename); + +/* This is used to set ATK action descriptions. */ +void glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description); + diff --git a/plugins/zerogs/opengl/Linux/zerogs.glade b/plugins/zerogs/opengl/Linux/zerogs.glade new file mode 100644 index 0000000000..1a82012798 --- /dev/null +++ b/plugins/zerogs/opengl/Linux/zerogs.glade @@ -0,0 +1,714 @@ + + + + + + + 5 + True + ZeroOGS Configuration + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + True + Interlace Enable (toggle with F5) + there are 2 modes + interlace off + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Bilinear Filtering (Shift+F5) + Best quality is on, turn off for speed + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + True + 0 + + + + True + True + None + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 0 + False + False + + + + + + True + True + 2X + True + GTK_RELIEF_NORMAL + True + False + False + True + radioAANone + + + 0 + False + False + + + + + + True + True + 4X + True + GTK_RELIEF_NORMAL + True + False + False + True + radioAANone + + + 0 + False + False + + + + + + True + True + 8X + True + GTK_RELIEF_NORMAL + True + False + False + True + radioAANone + + + 0 + False + False + + + + + + True + True + 16X + True + GTK_RELIEF_NORMAL + True + False + False + True + radioAANone + + + 0 + False + False + + + + + + + + + + True + <b>Anti-aliasing for higher quality (F6)</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + True + True + Wireframe rendering (Shift+F6) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Capture Avi (zerogs.avi)(F7) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Save Snapshots as TGAs (default is JPG) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Fullscreen (Alt+Enter) + to get out press Alt+Enter again (or ESC) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + True + 0 + + + + True + True + 640x480 + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + 800x600 + True + GTK_RELIEF_NORMAL + True + True + False + True + radioSize640 + + + 0 + False + False + + + + + + True + True + 1024x768 + True + GTK_RELIEF_NORMAL + True + False + False + True + radioSize640 + + + 0 + False + False + + + + + + True + True + 1280x960 + True + GTK_RELIEF_NORMAL + True + False + False + True + radioSize640 + + + 0 + False + False + + + + + + + + + + True + <b>Default Window Size (no speed impact)</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + False + False + False + + + + + + + + + + True + <b>Advanced Options</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + True + True + + + + + + True + Show Frames Per Second (Shift+F7) + (value is the average over 4-16 PS2 frames) + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_SPREAD + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + Cancel + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + + 5 + True + ZeroGS KOSMOS About + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + 5 + True + False + 5 + + + + True + OpenGL version + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + Author: zerofrog(@gmail.com) + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + Many thanks to the Pcsx2 testing team + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + + + + True + True + True + Ok + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + True + True + + + + + + + diff --git a/plugins/zerogs/opengl/Makefile.am b/plugins/zerogs/opengl/Makefile.am new file mode 100644 index 0000000000..70e456411f --- /dev/null +++ b/plugins/zerogs/opengl/Makefile.am @@ -0,0 +1,49 @@ +# Create a shared library libZeroGSogl +AUTOMAKE_OPTIONS = foreign +noinst_LIBRARIES = libZeroGSogl.a +INCLUDES = -I@srcdir@/common + +libZeroGSogl_a_CPPFLAGS = $(shell pkg-config --cflags gtk+-2.0) +libZeroGSogl_a_CXXFLAGS = $(shell pkg-config --cflags gtk+-2.0) + +if X86_64 +libZeroGSogl_a_CPPFLAGS += -fPIC +libZeroGSogl_a_CXXFLAGS += -fPIC +CCASFLAGS += -fPIC +endif + +# Create a shared object by faking an exe (thanks to ODE makefiles) +traplibdir=$(prefix) + + +if RELEASE_TO_PUBLIC +preext=r +endif + +EXEEXT=$(preext)@so_ext@ + +traplib_PROGRAMS=libZeroGSogl +libZeroGSogl_SOURCES= +libZeroGSogl_DEPENDENCIES = libZeroGSogl.a +libZeroGSogl_LDFLAGS= @SHARED_LDFLAGS@ +libZeroGSogl_LDFLAGS+=-Wl,-soname,@ZEROGS_SONAME@ +libZeroGSogl_LDADD=$(libZeroGSogl_a_OBJECTS) + +libZeroGSogl_a_SOURCES = \ +GSmain.cpp memcpy_amd.cpp Regs.cpp x86.cpp zpipe.cpp \ +Mem.cpp rasterfont.cpp targets.cpp zerogs.cpp + +if X86_64 +libZeroGSogl_a_SOURCES += x86-64.S +else +libZeroGSogl_a_SOURCES += x86-32.S +endif + +if SSE2 +CCASFLAGS+= -DZEROGS_SSE2 +endif + +libZeroGSogl_a_DEPENDENCIES = Linux/libZeroGSLinux.a +libZeroGSogl_LDADD += Linux/libZeroGSLinux.a + +SUBDIRS = Linux . diff --git a/plugins/zerogs/opengl/Mem.cpp b/plugins/zerogs/opengl/Mem.cpp new file mode 100644 index 0000000000..2133533409 --- /dev/null +++ b/plugins/zerogs/opengl/Mem.cpp @@ -0,0 +1,903 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 "GS.h" +#include "Mem.h" +#include "zerogs.h" +#include "targets.h" +#include "x86.h" + +u32 g_blockTable32[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable32Z[4][8] = { + { 24, 25, 28, 29, 8, 9, 12, 13}, + { 26, 27, 30, 31, 10, 11, 14, 15}, + { 16, 17, 20, 21, 0, 1, 4, 5}, + { 18, 19, 22, 23, 2, 3, 6, 7} +}; + +u32 g_blockTable16[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_blockTable16S[8][4] = { + { 0, 2, 16, 18 }, + { 1, 3, 17, 19 }, + { 8, 10, 24, 26 }, + { 9, 11, 25, 27 }, + { 4, 6, 20, 22 }, + { 5, 7, 21, 23 }, + { 12, 14, 28, 30 }, + { 13, 15, 29, 31 } +}; + +u32 g_blockTable16Z[8][4] = { + { 24, 26, 16, 18 }, + { 25, 27, 17, 19 }, + { 28, 30, 20, 22 }, + { 29, 31, 21, 23 }, + { 8, 10, 0, 2 }, + { 9, 11, 1, 3 }, + { 12, 14, 4, 6 }, + { 13, 15, 5, 7 } +}; + +u32 g_blockTable16SZ[8][4] = { + { 24, 26, 8, 10 }, + { 25, 27, 9, 11 }, + { 16, 18, 0, 2 }, + { 17, 19, 1, 3 }, + { 28, 30, 12, 14 }, + { 29, 31, 13, 15 }, + { 20, 22, 4, 6 }, + { 21, 23, 5, 7 } +}; + +u32 g_blockTable8[4][8] = { + { 0, 1, 4, 5, 16, 17, 20, 21}, + { 2, 3, 6, 7, 18, 19, 22, 23}, + { 8, 9, 12, 13, 24, 25, 28, 29}, + { 10, 11, 14, 15, 26, 27, 30, 31} +}; + +u32 g_blockTable4[8][4] = { + { 0, 2, 8, 10 }, + { 1, 3, 9, 11 }, + { 4, 6, 12, 14 }, + { 5, 7, 13, 15 }, + { 16, 18, 24, 26 }, + { 17, 19, 25, 27 }, + { 20, 22, 28, 30 }, + { 21, 23, 29, 31 } +}; + +u32 g_columnTable32[8][8] = { + { 0, 1, 4, 5, 8, 9, 12, 13 }, + { 2, 3, 6, 7, 10, 11, 14, 15 }, + { 16, 17, 20, 21, 24, 25, 28, 29 }, + { 18, 19, 22, 23, 26, 27, 30, 31 }, + { 32, 33, 36, 37, 40, 41, 44, 45 }, + { 34, 35, 38, 39, 42, 43, 46, 47 }, + { 48, 49, 52, 53, 56, 57, 60, 61 }, + { 50, 51, 54, 55, 58, 59, 62, 63 }, +}; + +u32 g_columnTable16[8][16] = { + { 0, 2, 8, 10, 16, 18, 24, 26, + 1, 3, 9, 11, 17, 19, 25, 27 }, + { 4, 6, 12, 14, 20, 22, 28, 30, + 5, 7, 13, 15, 21, 23, 29, 31 }, + { 32, 34, 40, 42, 48, 50, 56, 58, + 33, 35, 41, 43, 49, 51, 57, 59 }, + { 36, 38, 44, 46, 52, 54, 60, 62, + 37, 39, 45, 47, 53, 55, 61, 63 }, + { 64, 66, 72, 74, 80, 82, 88, 90, + 65, 67, 73, 75, 81, 83, 89, 91 }, + { 68, 70, 76, 78, 84, 86, 92, 94, + 69, 71, 77, 79, 85, 87, 93, 95 }, + { 96, 98, 104, 106, 112, 114, 120, 122, + 97, 99, 105, 107, 113, 115, 121, 123 }, + { 100, 102, 108, 110, 116, 118, 124, 126, + 101, 103, 109, 111, 117, 119, 125, 127 }, +}; + +u32 g_columnTable8[16][16] = { + { 0, 4, 16, 20, 32, 36, 48, 52, // column 0 + 2, 6, 18, 22, 34, 38, 50, 54 }, + { 8, 12, 24, 28, 40, 44, 56, 60, + 10, 14, 26, 30, 42, 46, 58, 62 }, + { 33, 37, 49, 53, 1, 5, 17, 21, + 35, 39, 51, 55, 3, 7, 19, 23 }, + { 41, 45, 57, 61, 9, 13, 25, 29, + 43, 47, 59, 63, 11, 15, 27, 31 }, + { 96, 100, 112, 116, 64, 68, 80, 84, // column 1 + 98, 102, 114, 118, 66, 70, 82, 86 }, + { 104, 108, 120, 124, 72, 76, 88, 92, + 106, 110, 122, 126, 74, 78, 90, 94 }, + { 65, 69, 81, 85, 97, 101, 113, 117, + 67, 71, 83, 87, 99, 103, 115, 119 }, + { 73, 77, 89, 93, 105, 109, 121, 125, + 75, 79, 91, 95, 107, 111, 123, 127 }, + { 128, 132, 144, 148, 160, 164, 176, 180, // column 2 + 130, 134, 146, 150, 162, 166, 178, 182 }, + { 136, 140, 152, 156, 168, 172, 184, 188, + 138, 142, 154, 158, 170, 174, 186, 190 }, + { 161, 165, 177, 181, 129, 133, 145, 149, + 163, 167, 179, 183, 131, 135, 147, 151 }, + { 169, 173, 185, 189, 137, 141, 153, 157, + 171, 175, 187, 191, 139, 143, 155, 159 }, + { 224, 228, 240, 244, 192, 196, 208, 212, // column 3 + 226, 230, 242, 246, 194, 198, 210, 214 }, + { 232, 236, 248, 252, 200, 204, 216, 220, + 234, 238, 250, 254, 202, 206, 218, 222 }, + { 193, 197, 209, 213, 225, 229, 241, 245, + 195, 199, 211, 215, 227, 231, 243, 247 }, + { 201, 205, 217, 221, 233, 237, 249, 253, + 203, 207, 219, 223, 235, 239, 251, 255 }, +}; + +u32 g_columnTable4[16][32] = { + { 0, 8, 32, 40, 64, 72, 96, 104, // column 0 + 2, 10, 34, 42, 66, 74, 98, 106, + 4, 12, 36, 44, 68, 76, 100, 108, + 6, 14, 38, 46, 70, 78, 102, 110 }, + { 16, 24, 48, 56, 80, 88, 112, 120, + 18, 26, 50, 58, 82, 90, 114, 122, + 20, 28, 52, 60, 84, 92, 116, 124, + 22, 30, 54, 62, 86, 94, 118, 126 }, + { 65, 73, 97, 105, 1, 9, 33, 41, + 67, 75, 99, 107, 3, 11, 35, 43, + 69, 77, 101, 109, 5, 13, 37, 45, + 71, 79, 103, 111, 7, 15, 39, 47 }, + { 81, 89, 113, 121, 17, 25, 49, 57, + 83, 91, 115, 123, 19, 27, 51, 59, + 85, 93, 117, 125, 21, 29, 53, 61, + 87, 95, 119, 127, 23, 31, 55, 63 }, + { 192, 200, 224, 232, 128, 136, 160, 168, // column 1 + 194, 202, 226, 234, 130, 138, 162, 170, + 196, 204, 228, 236, 132, 140, 164, 172, + 198, 206, 230, 238, 134, 142, 166, 174 }, + { 208, 216, 240, 248, 144, 152, 176, 184, + 210, 218, 242, 250, 146, 154, 178, 186, + 212, 220, 244, 252, 148, 156, 180, 188, + 214, 222, 246, 254, 150, 158, 182, 190 }, + { 129, 137, 161, 169, 193, 201, 225, 233, + 131, 139, 163, 171, 195, 203, 227, 235, + 133, 141, 165, 173, 197, 205, 229, 237, + 135, 143, 167, 175, 199, 207, 231, 239 }, + { 145, 153, 177, 185, 209, 217, 241, 249, + 147, 155, 179, 187, 211, 219, 243, 251, + 149, 157, 181, 189, 213, 221, 245, 253, + 151, 159, 183, 191, 215, 223, 247, 255 }, + { 256, 264, 288, 296, 320, 328, 352, 360, // column 2 + 258, 266, 290, 298, 322, 330, 354, 362, + 260, 268, 292, 300, 324, 332, 356, 364, + 262, 270, 294, 302, 326, 334, 358, 366 }, + { 272, 280, 304, 312, 336, 344, 368, 376, + 274, 282, 306, 314, 338, 346, 370, 378, + 276, 284, 308, 316, 340, 348, 372, 380, + 278, 286, 310, 318, 342, 350, 374, 382 }, + { 321, 329, 353, 361, 257, 265, 289, 297, + 323, 331, 355, 363, 259, 267, 291, 299, + 325, 333, 357, 365, 261, 269, 293, 301, + 327, 335, 359, 367, 263, 271, 295, 303 }, + { 337, 345, 369, 377, 273, 281, 305, 313, + 339, 347, 371, 379, 275, 283, 307, 315, + 341, 349, 373, 381, 277, 285, 309, 317, + 343, 351, 375, 383, 279, 287, 311, 319 }, + { 448, 456, 480, 488, 384, 392, 416, 424, // column 3 + 450, 458, 482, 490, 386, 394, 418, 426, + 452, 460, 484, 492, 388, 396, 420, 428, + 454, 462, 486, 494, 390, 398, 422, 430 }, + { 464, 472, 496, 504, 400, 408, 432, 440, + 466, 474, 498, 506, 402, 410, 434, 442, + 468, 476, 500, 508, 404, 412, 436, 444, + 470, 478, 502, 510, 406, 414, 438, 446 }, + { 385, 393, 417, 425, 449, 457, 481, 489, + 387, 395, 419, 427, 451, 459, 483, 491, + 389, 397, 421, 429, 453, 461, 485, 493, + 391, 399, 423, 431, 455, 463, 487, 495 }, + { 401, 409, 433, 441, 465, 473, 497, 505, + 403, 411, 435, 443, 467, 475, 499, 507, + 405, 413, 437, 445, 469, 477, 501, 509, + 407, 415, 439, 447, 471, 479, 503, 511 }, +}; + +u32 g_pageTable32[32][64]; +u32 g_pageTable32Z[32][64]; +u32 g_pageTable16[64][64]; +u32 g_pageTable16S[64][64]; +u32 g_pageTable16Z[64][64]; +u32 g_pageTable16SZ[64][64]; +u32 g_pageTable8[64][128]; +u32 g_pageTable4[128][128]; + +BLOCK m_Blocks[0x40]; // do so blocks are indexable +static PCSX2_ALIGNED16(u32 tempblock[64]); + +#define DSTPSM gs.dstbuf.psm + +#define START_HOSTLOCAL() \ + assert( gs.imageTransfer == 0 ); \ + u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; \ + \ + const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; \ + int i = gs.imageY, j = gs.imageX; \ + +extern BOOL g_bSaveTrans; + +#define END_HOSTLOCAL() \ +End: \ + if( i >= gs.imageEndY ) { \ + assert( gs.imageTransfer == -1 || i == gs.imageEndY ); \ + gs.imageTransfer = -1; \ + /*int start, end; \ + ZeroGS::GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); \ + ZeroGS::g_MemTargs.ClearRange(start, end);*/ \ + } \ + else { \ + /* update new params */ \ + gs.imageY = i; \ + gs.imageX = j; \ + } \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_(psm, T, widthlimit, endY) { \ + assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 1) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + } \ + } \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ + /* write as many pixel at one time as possible */ \ + if( nSize < widthlimit ) goto End; \ + writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize*sizeof(T)/4 == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0], gs.dstbuf.bw); \ + } \ + pbuf += pitch-fracX; \ + } \ +} \ + +// transfers whole rows +#define TRANSMIT_HOSTLOCAL_Y_24(psm, T, widthlimit, endY) { \ + if( widthlimit != 8 || ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { \ + /*GS_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM);*/ \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += 1, nSize -= 1, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || nSize == 0 ); goto End; } \ + } \ + } \ + else { \ + assert( /*(nSize%widthlimit) == 0 &&*/ widthlimit == 8 ); \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += 3*widthlimit) { \ + if( nSize < widthlimit ) goto End; \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *(u32*)(pbuf+0), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *(u32*)(pbuf+3), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *(u32*)(pbuf+6), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *(u32*)(pbuf+9), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *(u32*)(pbuf+12), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *(u32*)(pbuf+15), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *(u32*)(pbuf+18), gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *(u32*)(pbuf+21), gs.dstbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert(gs.imageTransfer == -1 || j == gs.imageEndX); j = gs.trxpos.dx; } \ + else { \ + if( nSize < 0 ) { \ + /* extracted too much */ \ + assert( (nSize%3)==0 && nSize > -24 ); \ + j += nSize/3; \ + nSize = 0; \ + } \ + assert( gs.imageTransfer == -1 || nSize == 0 ); \ + goto End; \ + } \ + } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_24(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j++, pbuf += 3) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, *(u32*)pbuf, gs.dstbuf.bw); \ + } \ + pbuf += 3*(pitch-fracX); \ + } \ +} \ + +// meant for 4bit transfers +#define TRANSMIT_HOSTLOCAL_Y_4(psm, T, widthlimit, endY) { \ + for(; i < endY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit) { \ + /* write as many pixel at one time as possible */ \ + writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + if( widthlimit > 2 ) { \ + writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 4 ) { \ + writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + \ + if( widthlimit > 6 ) { \ + writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ + pbuf++; \ + } \ + } \ + } \ + } \ + \ + if( j >= gs.imageEndX ) { j = gs.trxpos.dx; } \ + else { assert( gs.imageTransfer == -1 || (nSize/32) == 0 ); goto End; } \ + } \ +} \ + +// transmit until endX, don't check size since it has already been prevalidated +#define TRANSMIT_HOSTLOCAL_X_4(psm, T, widthlimit, blockheight, startX) { \ + for(int tempi = 0; tempi < blockheight; ++tempi) { \ + for(j = startX; j < gs.imageEndX; j+=2, pbuf++) { \ + writePixel##psm##_0(pstart, j%2048, (i+tempi)%2048, pbuf[0]&0x0f, gs.dstbuf.bw); \ + writePixel##psm##_0(pstart, (j+1)%2048, (i+tempi)%2048, pbuf[0]>>4, gs.dstbuf.bw); \ + } \ + pbuf += (pitch-fracX)/2; \ + } \ +} \ + +// calculate pitch in source buffer +#define TRANSMIT_PITCH_(pitch, T) (pitch*sizeof(T)) +#define TRANSMIT_PITCH_24(pitch, T) (pitch*3) +#define TRANSMIT_PITCH_4(pitch, T) (pitch/2) + +// special swizzle macros +#define SwizzleBlock24(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 7; ++by, pblock += 8, pnewsrc += pitch-24) { \ + for(int bx = 0; bx < 8; ++bx, pnewsrc += 3) { \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + } \ + for(int bx = 0; bx < 7; ++bx, pnewsrc += 3) { \ + /* might be 1 byte out of bounds of GS memory */ \ + pblock[bx] = *(u32*)pnewsrc; \ + } \ + /* do 3 bytes for the last copy */ \ + *((u8*)pblock+28) = pnewsrc[0]; \ + *((u8*)pblock+29) = pnewsrc[1]; \ + *((u8*)pblock+30) = pnewsrc[2]; \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x00ffffff); \ +} \ + +#define SwizzleBlock24u SwizzleBlock24 + +#define SwizzleBlock8H(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<16; \ + pblock[2] = u<<8; \ + pblock[3] = u; \ + u = *(u32*)(pnewsrc+4); \ + pblock[4] = u<<24; \ + pblock[5] = u<<16; \ + pblock[6] = u<<8; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xff000000); \ +} \ + +#define SwizzleBlock8Hu SwizzleBlock8H + +#define SwizzleBlock4HH(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<28; \ + pblock[1] = u<<24; \ + pblock[2] = u<<20; \ + pblock[3] = u<<16; \ + pblock[4] = u<<12; \ + pblock[5] = u<<8; \ + pblock[6] = u<<4; \ + pblock[7] = u; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0xf0000000); \ +} \ + +#define SwizzleBlock4HHu SwizzleBlock4HH + +#define SwizzleBlock4HL(dst, src, pitch) { \ + u8* pnewsrc = src; \ + u32* pblock = tempblock; \ + \ + for(int by = 0; by < 8; ++by, pblock += 8, pnewsrc += pitch) { \ + u32 u = *(u32*)pnewsrc; \ + pblock[0] = u<<24; \ + pblock[1] = u<<20; \ + pblock[2] = u<<16; \ + pblock[3] = u<<12; \ + pblock[4] = u<<8; \ + pblock[5] = u<<4; \ + pblock[6] = u; \ + pblock[7] = u>>4; \ + } \ + SwizzleBlock32((u8*)dst, (u8*)tempblock, 32, 0x0f000000); \ +} \ + +#define SwizzleBlock4HLu SwizzleBlock4HL + +// ------------------------ +// | Y | +// ------------------------ +// | block | | +// | aligned area | X | +// | | | +// ------------------------ +// | Y | +// ------------------------ +#define DEFINE_TRANSFERLOCAL(psm, T, widthlimit, blockbits, blockwidth, blockheight, TransSfx, SwizzleBlock) \ +int TransferHostLocal##psm(const void* pbyMem, u32 nQWordSize) \ +{ \ + START_HOSTLOCAL(); \ + \ + const T* pbuf = (const T*)pbyMem; \ + int nLeftOver = (nQWordSize*4*2)%(TRANSMIT_PITCH##TransSfx(2, T)); \ + int nSize = nQWordSize*4*2/TRANSMIT_PITCH##TransSfx(2, T); \ + nSize = min(nSize, gs.imageWnew * gs.imageHnew); \ + \ + int pitch, area, fracX; \ + int endY = ROUND_UPPOW2(i, blockheight); \ + int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); \ + int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); \ + bool bAligned, bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; \ + \ + if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { \ + /* hack */ \ + int testwidth = (int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx); \ + if( testwidth <= widthlimit && testwidth >= -widthlimit ) { \ + /* don't transfer */ \ + /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ \ + gs.imageTransfer = -1; \ + } \ + bCanAlign = false; \ + } \ + \ + /* first align on block boundary */ \ + if( MOD_POW2(i, blockheight) || !bCanAlign ) { \ + \ + if( !bCanAlign ) \ + endY = gs.imageEndY; /* transfer the whole image */ \ + else \ + assert( endY < gs.imageEndY); /* part of alignment condition */ \ + \ + if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) || ((gs.imageEndX-j)%widthlimit) ) { \ + /* transmit with a width of 1 */ \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, (1+(DSTPSM == 0x14)), endY); \ + } \ + else { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, endY); \ + } \ + \ + if( nSize == 0 || i == gs.imageEndY ) \ + goto End; \ + } \ + \ + assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); \ + \ + /* can align! */ \ + pitch = gs.imageEndX-gs.trxpos.dx; \ + area = pitch*blockheight; \ + fracX = gs.imageEndX-alignedX; \ + \ + /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ \ + bAligned = !((uptr)pbuf & 0xf) && (TRANSMIT_PITCH##TransSfx(pitch, T)&0xf) == 0; \ + \ + /* transfer aligning to blocks */ \ + for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { \ + \ + if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + else { \ + for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH##TransSfx(blockwidth, T)/sizeof(T)) { \ + SwizzleBlock##u(pstart + getPixelAddress##psm##_0(tempj, i, gs.dstbuf.bw)*blockbits/8, \ + (u8*)pbuf, TRANSMIT_PITCH##TransSfx(pitch, T)); \ + } \ + } \ + \ + /* transfer the rest */ \ + if( alignedX < gs.imageEndX ) { \ + TRANSMIT_HOSTLOCAL_X##TransSfx(psm, T, widthlimit, blockheight, alignedX); \ + pbuf -= TRANSMIT_PITCH##TransSfx((alignedX-gs.trxpos.dx), T)/sizeof(T); \ + } \ + else pbuf += (blockheight-1)*TRANSMIT_PITCH##TransSfx(pitch, T)/sizeof(T); \ + j = gs.trxpos.dx; \ + } \ + \ + if( TRANSMIT_PITCH##TransSfx(nSize, T)/4 > 0 ) { \ + TRANSMIT_HOSTLOCAL_Y##TransSfx(psm, T, widthlimit, gs.imageEndY); \ + /* sometimes wrong sizes are sent (tekken tag) */ \ + assert( gs.imageTransfer == -1 || TRANSMIT_PITCH##TransSfx(nSize,T)/4 <= 2 ); \ + } \ + \ + END_HOSTLOCAL(); \ + return (nSize * TRANSMIT_PITCH##TransSfx(2, T) + nLeftOver)/2; \ +} \ + +DEFINE_TRANSFERLOCAL(32, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(32Z, u32, 2, 32, 8, 8, _, SwizzleBlock32); +DEFINE_TRANSFERLOCAL(24, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(24Z, u8, 8, 32, 8, 8, _24, SwizzleBlock24); +DEFINE_TRANSFERLOCAL(16, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16S, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16Z, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(16SZ, u16, 4, 16, 16, 8, _, SwizzleBlock16); +DEFINE_TRANSFERLOCAL(8, u8, 4, 8, 16, 16, _, SwizzleBlock8); +DEFINE_TRANSFERLOCAL(4, u8, 8, 4, 32, 16, _4, SwizzleBlock4); +DEFINE_TRANSFERLOCAL(8H, u8, 4, 32, 8, 8, _, SwizzleBlock8H); +DEFINE_TRANSFERLOCAL(4HL, u8, 8, 32, 8, 8, _4, SwizzleBlock4HL); +DEFINE_TRANSFERLOCAL(4HH, u8, 8, 32, 8, 8, _4, SwizzleBlock4HH); + +//#define T u8 +//#define widthlimit 8 +//#define blockbits 4 +//#define blockwidth 32 +//#define blockheight 16 +// +//void TransferHostLocal4(const void* pbyMem, u32 nQWordSize) +//{ +// START_HOSTLOCAL(); +// +// const T* pbuf = (const T*)pbyMem; +// u32 nSize = nQWordSize*16*2/TRANSMIT_PITCH_4(2, T); +// nSize = min(nSize, gs.imageWnew * gs.imageHnew); +// +// int endY = ROUND_UPPOW2(i, blockheight); +// int alignedY = ROUND_DOWNPOW2(gs.imageEndY, blockheight); +// int alignedX = ROUND_DOWNPOW2(gs.imageEndX, blockwidth); +// bool bCanAlign = MOD_POW2(gs.trxpos.dx, blockwidth) == 0 && (j == gs.trxpos.dx) && (alignedY > endY) && alignedX > gs.trxpos.dx; +// +// if( (gs.imageEndX-gs.trxpos.dx)%widthlimit ) { +// /* hack */ +// if( abs((int)nSize - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= widthlimit ) { +// /* don't transfer */ +// /*DEBUG_LOG("bad texture %s: %d %d %d\n", #psm, gs.trxpos.dx, gs.imageEndX, nQWordSize);*/ +// gs.imageTransfer = -1; +// } +// bCanAlign = false; +// } +// +// /* first align on block boundary */ +// if( MOD_POW2(i, blockheight) || !bCanAlign ) { +// +// if( !bCanAlign ) +// endY = gs.imageEndY; /* transfer the whole image */ +// else +// assert( endY < gs.imageEndY); /* part of alignment condition */ +// +// if( (DSTPSM == 0x13 || DSTPSM == 0x14) && ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) { +// /* transmit with a width of 1 */ +// TRANSMIT_HOSTLOCAL_Y_4(4, T, (1+(DSTPSM == 0x14)), endY); +// } +// else { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, endY); +// } +// +// if( nSize == 0 || i == gs.imageEndY ) +// goto End; +// } +// +// assert( MOD_POW2(i, blockheight) == 0 && j == gs.trxpos.dx); +// +// /* can align! */ +// int pitch = gs.imageEndX-gs.trxpos.dx; +// u32 area = pitch*blockheight; +// int fracX = gs.imageEndX-alignedX; +// +// /* on top of checking whether pbuf is alinged, make sure that the width is at least aligned to its limits (due to bugs in pcsx2) */ +// bool bAligned = !((u32)pbuf & 0xf) && (TRANSMIT_PITCH_4(pitch, T)&0xf) == 0; +// +// /* transfer aligning to blocks */ +// for(; i < alignedY && nSize >= area; i += blockheight, nSize -= area) { +// +// if( bAligned || ((DSTPSM==PSMCT24) || (DSTPSM==PSMT8H) || (DSTPSM==PSMT4HH) || (DSTPSM==PSMT4HL)) ) { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// else { +// for(int tempj = gs.trxpos.dx; tempj < alignedX; tempj += blockwidth, pbuf += TRANSMIT_PITCH_4(blockwidth, T)/sizeof(T)) { +// SwizzleBlock4u(pstart + getPixelAddress4_0(tempj, i, gs.dstbuf.bw)*blockbits/8, +// (u8*)pbuf, TRANSMIT_PITCH_4(pitch, T)); +// } +// } +// +// /* transfer the rest */ +// if( alignedX < gs.imageEndX ) { +// TRANSMIT_HOSTLOCAL_X_4(4, T, widthlimit, blockheight, alignedX); +// pbuf -= TRANSMIT_PITCH_4((alignedX-gs.trxpos.dx), T)/sizeof(T); +// } +// else pbuf += (blockheight-1)*TRANSMIT_PITCH_4(pitch, T)/sizeof(T); +// j = 0; +// } +// +// if( TRANSMIT_PITCH_4(nSize, T)/4 > 0 ) { +// TRANSMIT_HOSTLOCAL_Y_4(4, T, widthlimit, gs.imageEndY); +// /* sometimes wrong sizes are sent (tekken tag) */ +// assert( gs.imageTransfer == -1 || TRANSMIT_PITCH_4(nSize,T)/4 <= 2 ); +// } +// +// END_HOSTLOCAL(); +//} + +void TransferLocalHost32(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16S(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost8H(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HL(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost4HH(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost32Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost24Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16Z(void* pbyMem, u32 nQWordSize) +{ +} + +void TransferLocalHost16SZ(void* pbyMem, u32 nQWordSize) +{ +} + +#define FILL_BLOCK(bw, bh, ox, oy, mult, psm, psmcol) { \ + b.vTexDims = Vector(BLOCK_TEXWIDTH/(float)(bw), BLOCK_TEXHEIGHT/(float)bh, 0, 0); \ + b.vTexBlock = Vector((float)bw/BLOCK_TEXWIDTH, (float)bh/BLOCK_TEXHEIGHT, ((float)ox+0.2f)/BLOCK_TEXWIDTH, ((float)oy+0.05f)/BLOCK_TEXHEIGHT); \ + b.width = bw; \ + b.height = bh; \ + b.colwidth = bh / 4; \ + b.colheight = bw / 8; \ + b.bpp = 32/mult; \ + \ + b.pageTable = &g_pageTable##psm[0][0]; \ + b.blockTable = &g_blockTable##psm[0][0]; \ + b.columnTable = &g_columnTable##psmcol[0][0]; \ + assert( sizeof(g_pageTable##psm) == bw*bh*sizeof(g_pageTable##psm[0][0]) ); \ + psrcf = (float*)&vBlockData[0] + ox + oy * BLOCK_TEXWIDTH; \ + psrcw = (u16*)&vBlockData[0] + ox + oy * BLOCK_TEXWIDTH; \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + /* fill the table */ \ + u32 u = g_blockTable##psm[(i / b.colheight)][(j / b.colwidth)] * 64 * mult + g_columnTable##psmcol[i%b.colheight][j%b.colwidth]; \ + b.pageTable[i*bw+j] = u; \ + if( floatfmt ) { \ + psrcf[i*BLOCK_TEXWIDTH+j] = (float)(u) / (float)(GPU_TEXWIDTH*mult); \ + } \ + else { \ + psrcw[i*BLOCK_TEXWIDTH+j] = u; \ + } \ + } \ + } \ + \ + if( floatfmt ) { \ + assert( floatfmt ); \ + psrcv = (Vector*)&vBilinearData[0] + ox + oy * BLOCK_TEXWIDTH; \ + for(i = 0; i < bh; ++i) { \ + for(j = 0; j < bw; ++j) { \ + Vector* pv = &psrcv[i*BLOCK_TEXWIDTH+j]; \ + pv->x = psrcf[i*BLOCK_TEXWIDTH+j]; \ + pv->y = psrcf[i*BLOCK_TEXWIDTH+((j+1)%bw)]; \ + pv->z = psrcf[((i+1)%bh)*BLOCK_TEXWIDTH+j]; \ + pv->w = psrcf[((i+1)%bh)*BLOCK_TEXWIDTH+((j+1)%bw)]; \ + } \ + } \ + } \ + b.getPixelAddress = getPixelAddress##psm; \ + b.getPixelAddress_0 = getPixelAddress##psm##_0; \ + b.writePixel = writePixel##psm; \ + b.writePixel_0 = writePixel##psm##_0; \ + b.readPixel = readPixel##psm; \ + b.readPixel_0 = readPixel##psm##_0; \ + b.TransferHostLocal = TransferHostLocal##psm; \ + b.TransferLocalHost = TransferLocalHost##psm; \ +} \ + +void BLOCK::FillBlocks(vector& vBlockData, vector& vBilinearData, int floatfmt) +{ + vBlockData.resize(BLOCK_TEXWIDTH * BLOCK_TEXHEIGHT * (floatfmt ? 4 : 2)); + if( floatfmt ) + vBilinearData.resize(BLOCK_TEXWIDTH * BLOCK_TEXHEIGHT * sizeof(Vector)); + + int i, j; + BLOCK b; + float* psrcf = NULL; + u16* psrcw = NULL; + Vector* psrcv = NULL; + + memset(m_Blocks, 0, sizeof(m_Blocks)); + + // 32 + FILL_BLOCK(64, 32, 0, 0, 1, 32, 32); + m_Blocks[PSMCT32] = b; + + // 24 (same as 32 except write/readPixel are different) + m_Blocks[PSMCT24] = b; + m_Blocks[PSMCT24].writePixel = writePixel24; + m_Blocks[PSMCT24].writePixel_0 = writePixel24_0; + m_Blocks[PSMCT24].readPixel = readPixel24; + m_Blocks[PSMCT24].readPixel_0 = readPixel24_0; + m_Blocks[PSMCT24].TransferHostLocal = TransferHostLocal24; + m_Blocks[PSMCT24].TransferLocalHost = TransferLocalHost24; + + // 8H (same as 32 except write/readPixel are different) + m_Blocks[PSMT8H] = b; + m_Blocks[PSMT8H].writePixel = writePixel8H; + m_Blocks[PSMT8H].writePixel_0 = writePixel8H_0; + m_Blocks[PSMT8H].readPixel = readPixel8H; + m_Blocks[PSMT8H].readPixel_0 = readPixel8H_0; + m_Blocks[PSMT8H].TransferHostLocal = TransferHostLocal8H; + m_Blocks[PSMT8H].TransferLocalHost = TransferLocalHost8H; + + m_Blocks[PSMT4HL] = b; + m_Blocks[PSMT4HL].writePixel = writePixel4HL; + m_Blocks[PSMT4HL].writePixel_0 = writePixel4HL_0; + m_Blocks[PSMT4HL].readPixel = readPixel4HL; + m_Blocks[PSMT4HL].readPixel_0 = readPixel4HL_0; + m_Blocks[PSMT4HL].TransferHostLocal = TransferHostLocal4HL; + m_Blocks[PSMT4HL].TransferLocalHost = TransferLocalHost4HL; + + m_Blocks[PSMT4HH] = b; + m_Blocks[PSMT4HH].writePixel = writePixel4HH; + m_Blocks[PSMT4HH].writePixel_0 = writePixel4HH_0; + m_Blocks[PSMT4HH].readPixel = readPixel4HH; + m_Blocks[PSMT4HH].readPixel_0 = readPixel4HH_0; + m_Blocks[PSMT4HH].TransferHostLocal = TransferHostLocal4HH; + m_Blocks[PSMT4HH].TransferLocalHost = TransferLocalHost4HH; + + // 32z + FILL_BLOCK(64, 32, 64, 0, 1, 32Z, 32); + m_Blocks[PSMT32Z] = b; + + // 24Z (same as 32Z except write/readPixel are different) + m_Blocks[PSMT24Z] = b; + m_Blocks[PSMT24Z].writePixel = writePixel24Z; + m_Blocks[PSMT24Z].writePixel_0 = writePixel24Z_0; + m_Blocks[PSMT24Z].readPixel = readPixel24Z; + m_Blocks[PSMT24Z].readPixel_0 = readPixel24Z_0; + m_Blocks[PSMT24Z].TransferHostLocal = TransferHostLocal24Z; + m_Blocks[PSMT24Z].TransferLocalHost = TransferLocalHost24Z; + + // 16 + FILL_BLOCK(64, 64, 0, 32, 2, 16, 16); + m_Blocks[PSMCT16] = b; + + // 16s + FILL_BLOCK(64, 64, 64, 32, 2, 16S, 16); + m_Blocks[PSMCT16S] = b; + + // 16z + FILL_BLOCK(64, 64, 0, 96, 2, 16Z, 16); + m_Blocks[PSMT16Z] = b; + + // 16sz + FILL_BLOCK(64, 64, 64, 96, 2, 16SZ, 16); + m_Blocks[PSMT16SZ] = b; + + // 8 + FILL_BLOCK(128, 64, 0, 160, 4, 8, 8); + m_Blocks[PSMT8] = b; + + // 4 + FILL_BLOCK(128, 128, 0, 224, 8, 4, 4); + m_Blocks[PSMT4] = b; +} diff --git a/plugins/zerogs/opengl/Mem.h b/plugins/zerogs/opengl/Mem.h new file mode 100644 index 0000000000..e77f6b370c --- /dev/null +++ b/plugins/zerogs/opengl/Mem.h @@ -0,0 +1,487 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __MEM_H__ +#define __MEM_H__ + +#include +#include + +// works only when base is a power of 2 +#define ROUND_UPPOW2(val, base) (((val)+(base-1))&~(base-1)) +#define ROUND_DOWNPOW2(val, base) ((val)&~(base-1)) +#define MOD_POW2(val, base) ((val)&(base-1)) + +// d3d texture dims +#define BLOCK_TEXWIDTH 128 +#define BLOCK_TEXHEIGHT 512 + +// rest not visible externally +struct BLOCK +{ + BLOCK() { memset(this, 0, sizeof(BLOCK)); } + + // shader constants for this block + Vector vTexBlock; + Vector vTexDims; + int width, height; // dims of one page in pixels + int bpp; + int colwidth, colheight; + u32* pageTable; // offset inside each page + u32* blockTable; + u32* columnTable; + + u32 (*getPixelAddress)(int x, int y, u32 bp, u32 bw); + u32 (*getPixelAddress_0)(int x, int y, u32 bw); + void (*writePixel)(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw); + void (*writePixel_0)(void* pmem, int x, int y, u32 pixel, u32 bw); + u32 (*readPixel)(const void* pmem, int x, int y, u32 bp, u32 bw); + u32 (*readPixel_0)(const void* pmem, int x, int y, u32 bw); + int (*TransferHostLocal)(const void* pbyMem, u32 nQWordSize); + void (*TransferLocalHost)(void* pbyMem, u32 nQWordSize); + + // texture must be of dims BLOCK_TEXWIDTH and BLOCK_TEXHEIGHT + static void FillBlocks(std::vector& vBlockData, std::vector& vBilinearData, int floatfmt); +}; + +extern BLOCK m_Blocks[]; + +extern u32 g_blockTable32[4][8]; +extern u32 g_blockTable32Z[4][8]; +extern u32 g_blockTable16[8][4]; +extern u32 g_blockTable16S[8][4]; +extern u32 g_blockTable16Z[8][4]; +extern u32 g_blockTable16SZ[8][4]; +extern u32 g_blockTable8[4][8]; +extern u32 g_blockTable4[8][4]; + +extern u32 g_columnTable32[8][8]; +extern u32 g_columnTable16[8][16]; +extern u32 g_columnTable8[16][16]; +extern u32 g_columnTable4[16][32]; + +extern u32 g_pageTable32[32][64]; +extern u32 g_pageTable32Z[32][64]; +extern u32 g_pageTable16[64][64]; +extern u32 g_pageTable16S[64][64]; +extern u32 g_pageTable16Z[64][64]; +extern u32 g_pageTable16SZ[64][64]; +extern u32 g_pageTable8[64][128]; +extern u32 g_pageTable4[128][128]; + +static __forceinline u32 getPixelAddress32(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +static __forceinline u32 getPixelAddress32_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24 getPixelAddress32 +#define getPixelAddress24_0 getPixelAddress32_0 +#define getPixelAddress8H getPixelAddress32 +#define getPixelAddress8H_0 getPixelAddress32_0 +#define getPixelAddress4HL getPixelAddress32 +#define getPixelAddress4HL_0 getPixelAddress32_0 +#define getPixelAddress4HH getPixelAddress32 +#define getPixelAddress4HH_0 getPixelAddress32_0 + +static __forceinline u32 getPixelAddress16(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16S(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16S_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16S[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress8(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 256 + basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +static __forceinline u32 getPixelAddress8_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 8192 + g_pageTable8[y&63][x&127]; + //assert (word < 0x400000); + //word = min(word, 0x3fffff); + return word; +} + +static __forceinline u32 getPixelAddress4(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = bp * 512 + basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +static __forceinline u32 getPixelAddress4_0(int x, int y, u32 bw) { + u32 basepage = ((y>>7) * ((bw+127)>>7)) + (x>>7); + u32 word = basepage * 16384 + g_pageTable4[y&127][x&127]; + //assert (word < 0x800000); + //word = min(word, 0x7fffff); + return word; +} + +static __forceinline u32 getPixelAddress32Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = bp * 64 + basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +static __forceinline u32 getPixelAddress32Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>5) * (bw>>6)) + (x>>6); + u32 word = basepage * 2048 + g_pageTable32Z[y&31][x&63]; + //assert (word < 0x100000); + //word = min(word, 0xfffff); + return word; +} + +#define getPixelAddress24Z getPixelAddress32Z +#define getPixelAddress24Z_0 getPixelAddress32Z_0 + +static __forceinline u32 getPixelAddress16Z(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16Z_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16Z[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16SZ(int x, int y, u32 bp, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = bp * 128 + basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline u32 getPixelAddress16SZ_0(int x, int y, u32 bw) { + u32 basepage = ((y>>6) * (bw>>6)) + (x>>6); + u32 word = basepage * 4096 + g_pageTable16SZ[y&63][x&63]; + //assert (word < 0x200000); + //word = min(word, 0x1fffff); + return word; +} + +static __forceinline void writePixel32(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel24(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +static __forceinline void writePixel16(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel16S(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16S(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel8(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[getPixelAddress8(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel8H(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32(x, y, bp, bw)+3] = pixel; +} + +static __forceinline void writePixel4(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +static __forceinline void writePixel4HL(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL(x, y, bp, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +static __forceinline void writePixel4HH(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH(x, y, bp, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +static __forceinline void writePixel32Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel24Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z(x, y, bp, bw); + u8 *pix = (u8*)&pixel; + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +} + +static __forceinline void writePixel16Z(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)] = pixel; +} + +static __forceinline void writePixel16SZ(void* pmem, int x, int y, u32 pixel, u32 bp, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)] = pixel; +} + + +/////////////// + +static __forceinline u32 readPixel32(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel24(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32(x, y, bp, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel16S(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel8(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel8H(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32(x, y, bp, bw) + 3]; +} + +static __forceinline u32 readPixel4(const void* pmem, int x, int y, u32 bp, u32 bw) { + u32 addr = getPixelAddress4(x, y, bp, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +static __forceinline u32 readPixel4HL(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL(x, y, bp, bw)+3; + return *p & 0x0f; +} + +static __forceinline u32 readPixel4HH(const void* pmem, int x, int y, u32 bp, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH(x, y, bp, bw) + 3; + return *p >> 4; +} + +/////////////// + +static __forceinline u32 readPixel32Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel24Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z(x, y, bp, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16Z(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z(x, y, bp, bw)]; +} + +static __forceinline u32 readPixel16SZ(const void* pmem, int x, int y, u32 bp, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ(x, y, bp, bw)]; +} + +/////////////////////////////// +// Functions that take 0 bps // +/////////////////////////////// + +static __forceinline void writePixel32_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel24_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)&((u32*)pmem)[getPixelAddress32_0(x, y, bw)]; + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +static __forceinline void writePixel16_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel16S_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16S_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel8_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[getPixelAddress8_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel8H_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u8*)pmem)[4*getPixelAddress32_0(x, y, bw)+3] = pixel; +} + +static __forceinline void writePixel4_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((u8*)pmem)[addr/2]; + if (addr & 0x1) ((u8*)pmem)[addr/2] = (pix & 0x0f) | (pixel << 4); + else ((u8*)pmem)[addr/2] = (pix & 0xf0) | (pixel); +} + +static __forceinline void writePixel4HL_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HL_0(x, y, bw)+3; + *p = (*p & 0xf0) | pixel; +} + +static __forceinline void writePixel4HH_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *p = (u8*)pmem + 4*getPixelAddress4HH_0(x, y, bw)+3; + *p = (*p & 0x0f) | (pixel<<4); +} + +static __forceinline void writePixel32Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel24Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + u8 *buf = (u8*)pmem + 4*getPixelAddress32Z_0(x, y, bw); + u8 *pix = (u8*)&pixel; +#if defined(_MSC_VER) && defined(__x86_64__) + memcpy(buf, pix, 3); +#else + buf[0] = pix[0]; buf[1] = pix[1]; buf[2] = pix[2]; +#endif +} + +static __forceinline void writePixel16Z_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16Z_0(x, y, bw)] = pixel; +} + +static __forceinline void writePixel16SZ_0(void* pmem, int x, int y, u32 pixel, u32 bw) { + ((u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)] = pixel; +} + + +/////////////// + +static __forceinline u32 readPixel32_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)]; +} + +static __forceinline u32 readPixel24_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32_0(x, y, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16_0(x, y, bw)]; +} + +static __forceinline u32 readPixel16S_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16S_0(x, y, bw)]; +} + +static __forceinline u32 readPixel8_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[getPixelAddress8_0(x, y, bw)]; +} + +static __forceinline u32 readPixel8H_0(const void* pmem, int x, int y, u32 bw) { + return ((const u8*)pmem)[4*getPixelAddress32_0(x, y, bw) + 3]; +} + +static __forceinline u32 readPixel4_0(const void* pmem, int x, int y, u32 bw) { + u32 addr = getPixelAddress4_0(x, y, bw); + u8 pix = ((const u8*)pmem)[addr/2]; + if (addr & 0x1) + return pix >> 4; + else return pix & 0xf; +} + +static __forceinline u32 readPixel4HL_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HL_0(x, y, bw)+3; + return *p & 0x0f; +} + +static __forceinline u32 readPixel4HH_0(const void* pmem, int x, int y, u32 bw) { + const u8 *p = (const u8*)pmem+4*getPixelAddress4HH_0(x, y, bw) + 3; + return *p >> 4; +} + +/////////////// + +static __forceinline u32 readPixel32Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)]; +} + +static __forceinline u32 readPixel24Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u32*)pmem)[getPixelAddress32Z_0(x, y, bw)] & 0xffffff; +} + +static __forceinline u32 readPixel16Z_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16Z_0(x, y, bw)]; +} + +static __forceinline u32 readPixel16SZ_0(const void* pmem, int x, int y, u32 bw) { + return ((const u16*)pmem)[getPixelAddress16SZ_0(x, y, bw)]; +} + +#endif /* __MEM_H__ */ diff --git a/plugins/zerogs/opengl/README.txt b/plugins/zerogs/opengl/README.txt new file mode 100644 index 0000000000..edeb776031 --- /dev/null +++ b/plugins/zerogs/opengl/README.txt @@ -0,0 +1,13 @@ +ZeroGS OpenGL +------------- +author: zerofrog (@gmail.com) + +ZeroGS heavily uses GPU shaders. All the shaders are written in nVidia's Cg language and can be found in ps2hw.fx. + +'Dev' versions of ZeroGS directly read ps2hw.fx +'Release' versions of ZeroGS read a precompiled version of ps2hw.fx from ps2hw.dat. In order to build ps2hw.dat, compile ZeroGSShaders and execute: + +./ZeroGSShaders ps2hw.fx ps2hw.dat + +For Windows users, once ZeroGSShaders is built, run buildshaders.bat directly. It will update all necessary resource files. +Note that ZeroGSShaders has only been tested in Windows so far, but the Windows ps2hw.dat can be used in linux builds. \ No newline at end of file diff --git a/plugins/zerogs/opengl/Regs.cpp b/plugins/zerogs/opengl/Regs.cpp new file mode 100644 index 0000000000..f092c4f9e8 --- /dev/null +++ b/plugins/zerogs/opengl/Regs.cpp @@ -0,0 +1,1008 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerorog@gmail.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "Regs.h" + +#include "zerogs.h" +#include "targets.h" + +const u32 g_primmult[8] = { 1, 2, 2, 3, 3, 3, 2, 0xff }; +const u32 g_primsub[8] = { 1, 2, 1, 3, 1, 1, 2, 0 }; + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +GIFRegHandler g_GIFPackedRegHandlers[16] = { + GIFRegHandlerPRIM, GIFPackedRegHandlerRGBA, GIFPackedRegHandlerSTQ, GIFPackedRegHandlerUV, + GIFPackedRegHandlerXYZF2, GIFPackedRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFPackedRegHandlerFOG, GIFPackedRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFPackedRegHandlerA_D, GIFPackedRegHandlerNOP }; + +GIFRegHandler g_GIFRegHandlers[] = { + GIFRegHandlerPRIM, GIFRegHandlerRGBAQ, GIFRegHandlerST, GIFRegHandlerUV, + GIFRegHandlerXYZF2, GIFRegHandlerXYZ2, GIFRegHandlerTEX0_1, GIFRegHandlerTEX0_2, + GIFRegHandlerCLAMP_1, GIFRegHandlerCLAMP_2, GIFRegHandlerFOG, GIFRegHandlerNull, + GIFRegHandlerXYZF3, GIFRegHandlerXYZ3, GIFRegHandlerNOP, GIFRegHandlerNOP, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerTEX1_1, GIFRegHandlerTEX1_2, GIFRegHandlerTEX2_1, GIFRegHandlerTEX2_2, + GIFRegHandlerXYOFFSET_1,GIFRegHandlerXYOFFSET_2,GIFRegHandlerPRMODECONT,GIFRegHandlerPRMODE, + GIFRegHandlerTEXCLUT, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerSCANMSK, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerMIPTBP1_1, GIFRegHandlerMIPTBP1_2, GIFRegHandlerMIPTBP2_1, GIFRegHandlerMIPTBP2_2, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerTEXA, + GIFRegHandlerNull, GIFRegHandlerFOGCOL, GIFRegHandlerNull, GIFRegHandlerTEXFLUSH, + GIFRegHandlerSCISSOR_1, GIFRegHandlerSCISSOR_2, GIFRegHandlerALPHA_1, GIFRegHandlerALPHA_2, + GIFRegHandlerDIMX, GIFRegHandlerDTHE, GIFRegHandlerCOLCLAMP, GIFRegHandlerTEST_1, + GIFRegHandlerTEST_2, GIFRegHandlerPABE, GIFRegHandlerFBA_1, GIFRegHandlerFBA_2, + GIFRegHandlerFRAME_1, GIFRegHandlerFRAME_2, GIFRegHandlerZBUF_1, GIFRegHandlerZBUF_2, + GIFRegHandlerBITBLTBUF, GIFRegHandlerTRXPOS, GIFRegHandlerTRXREG, GIFRegHandlerTRXDIR, + GIFRegHandlerHWREG, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, GIFRegHandlerNull, + GIFRegHandlerSIGNAL, GIFRegHandlerFINISH, GIFRegHandlerLABEL, GIFRegHandlerNull }; + +C_ASSERT(sizeof(g_GIFRegHandlers)/sizeof(g_GIFRegHandlers[0]) == 100 ); + +// values for keeping track of changes +u32 s_uTex1Data[2][2] = {0}, s_uClampData[2] = {0}; + +void __fastcall GIFPackedRegHandlerNull(u32* data) +{ + DEBUG_LOG("Unexpected packed reg handler %8.8lx_%8.8lx %x\n", data[0], data[1], data[2]); +} + +void __fastcall GIFPackedRegHandlerRGBA(u32* data) +{ + gs.rgba = (data[0] & 0xff) | + ((data[1] & 0xff) << 8) | + ((data[2] & 0xff) << 16) | + ((data[3] & 0xff) << 24); + gs.vertexregs.rgba = gs.rgba; + gs.vertexregs.q = gs.q; +} + +void __fastcall GIFPackedRegHandlerSTQ(u32* data) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + *(u32*)&gs.q = data[2]; +} + +void __fastcall GIFPackedRegHandlerUV(u32* data) +{ + gs.vertexregs.u = data[0] & 0x3fff; + gs.vertexregs.v = data[1] & 0x3fff; +} + +void __forceinline KICK_VERTEX2() +{ + if (++gs.primC >= (int)g_primmult[prim->prim]) + { + if (!(g_GameSettings&GAME_XENOSPECHACK) || !ZeroGS::vb[prim->ctxt].zbuf.zmsk) + (*ZeroGS::drawfn[prim->prim])(); + gs.primC -= g_primsub[prim->prim]; + } +} + +void __forceinline KICK_VERTEX3() +{ + if (++gs.primC >= (int)g_primmult[prim->prim]) + { + gs.primC -= g_primsub[prim->prim]; + if (prim->prim == 5) + { + /* tri fans need special processing */ + if (gs.nTriFanVert == gs.primIndex) + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + } + } +} + +void __fastcall GIFPackedRegHandlerXYZF2(u32* data) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = (data[2] >> 4) & 0xffffff; + gs.vertexregs.f = (data[3] >> 4) & 0xff; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void __fastcall GIFPackedRegHandlerXYZ2(u32* data) +{ + gs.vertexregs.x = (data[0] >> 0) & 0xffff; + gs.vertexregs.y = (data[1] >> 0) & 0xffff; + gs.vertexregs.z = data[2]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAYSIZE(gs.gsvertex); + + if( data[3] & 0x8000 ) { + KICK_VERTEX3(); + } + else { + KICK_VERTEX2(); + } +} + +void __fastcall GIFPackedRegHandlerFOG(u32* data) +{ + gs.vertexregs.f = (data[3]&0xff0)>>4; +} + +void __fastcall GIFPackedRegHandlerA_D(u32* data) +{ + if((data[2] & 0xff) < 100) + g_GIFRegHandlers[data[2] & 0xff](data); + else + GIFRegHandlerNull(data); +} + +void __fastcall GIFPackedRegHandlerNOP(u32* data) +{ +} + +extern int g_PrevBitwiseTexX, g_PrevBitwiseTexY; + +void tex0Write(int i, u32 *data) +{ + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + if( m_Blocks[psm].bpp == 0 ) { + // kh and others + return; + } + + ZeroGS::vb[i].uNextTex0Data[0] = data[0]; + ZeroGS::vb[i].uNextTex0Data[1] = data[1]; + ZeroGS::vb[i].bNeedTexCheck = 1; + + // don't update unless necessary + if( PSMT_ISCLUT(psm) ) { + if( ZeroGS::CheckChangeInClut(data[1], psm) ) { + // loading clut, so flush whole texture + ZeroGS::vb[i].FlushTexData(); + } + // check if csa is the same!! (ffx bisaid island, grass) + else if( (data[1]&0x1f780000) != (ZeroGS::vb[i].uCurTex0Data[1]&0x1f780000) ) { + ZeroGS::Flush(i); // flush any previous entries + } + } +} + +void tex2Write(int i, u32 *data) +{ + tex0Info& tex0 = ZeroGS::vb[i].tex0; + + if( ZeroGS::vb[i].bNeedTexCheck ) + ZeroGS::vb[i].FlushTexData(); + + u32 psm = (data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + u32* s_uTex0Data = ZeroGS::vb[i].uCurTex0Data; + + // don't update unless necessary + if( (s_uTex0Data[0]&0x03f00000) == (data[0]&0x03f00000) ) { // psm is the same + + if( PSMT_ISCLUT(psm) ) { + // have to write the CLUT again if changed + if( (s_uTex0Data[1]&0x1fffffe0) == (data[1]&0x1fffffe0) ) { + + if( data[1]&0xe0000000 ) { + tex0.cld = (data[1]>>29)&7; + ZeroGS::texClutWrite(i); + // invalidate to make sure target didn't change! + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + + return; + } + + // CSAs have to be the same! +// if( (data[1]&0xe0000000) == 0 ) { +// +// if( (s_uTex0Data[1]&0x1f100000) != (data[1]&0x1f100000) ) +// ZeroGS::Flush(i); +// +// // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! +// ZeroGS::vb[i].uCurTex0Data[1] = (ZeroGS::vb[i].uCurTex0Data[1]&0xe087ffff)|(data[1]&0x1f780000); +// +// if( ZeroGS::vb[i].tex0.cpsm <= 1 ) ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0xf; +// else ZeroGS::vb[i].tex0.csa = (data[1] >> 24) & 0x1f; +// +// ZeroGS::vb[i].tex0.cpsm = (data[1] >> 19) & 0xe; +// +// ZeroGS::vb[i].bVarsTexSync = FALSE; +// return; +// } + + // fall through + } + else { + //ZeroGS::vb[i].bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + ZeroGS::vb[i].bTexConstsSync = FALSE; + + s_uTex0Data[0] = (s_uTex0Data[0]&~0x03f00000)|(psm<<20); + s_uTex0Data[1] = (s_uTex0Data[1]&0x1f)|(data[1]&~0x1f); + + tex0.psm = psm; + + if( PSMT_ISCLUT(tex0.psm) ) { + tex0.cbp = (data[1] >> 5) & 0x3fff; + tex0.cpsm = (data[1] >> 19) & 0xe; + tex0.csm = (data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (data[1] >> 24) & 0xf; + else tex0.csa = (data[1] >> 24) & 0x1f; + + tex0.cld = (data[1] >> 29) & 0x7; + ZeroGS::texClutWrite(i); + } +} + +__forceinline void frameWrite(int i, u32 *data) +{ + frameInfo& gsfb = ZeroGS::vb[i].gsfb; + + if( (gsfb.fbp == ((data[0] ) & 0x1ff) * 32) && + (gsfb.fbw == ((data[0] >> 16) & 0x3f) * 64) && + gsfb.psm == ((data[0] >> 24) & 0x3f) && + (gsfb.fbm == data[1]) ) { + return; + } + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gsfb.fbp = ((data[0] ) & 0x1ff) * 32; + gsfb.fbw = ((data[0] >> 16) & 0x3f) * 64; + gsfb.psm = (data[0] >> 24) & 0x3f; + gsfb.fbm = data[1]; + + if (gsfb.fbw > 0) { + + gsfb.fbh = (1024*1024-64*gsfb.fbp) / gsfb.fbw; + gsfb.fbh &= ~0x1f; + if( gsfb.psm & 2 ) + gsfb.fbh *= 2; + if( gsfb.fbh > 1024 ) gsfb.fbh = 1024; + } + else gsfb.fbh = 0; + + if( gsfb.psm == 1 ) gsfb.fbm |= 0xff000000; + else if( gsfb.psm & 2 ) { + + } + + ZeroGS::vb[i].bNeedFrameCheck = 1; +} + +__forceinline void testWrite(int i, u32 *data) +{ + pixTest* test = &ZeroGS::vb[i].test; + + if( (*(u32*)test & 0x0007ffff) == (data[0] & 0x0007ffff) ) + return; + + ZeroGS::Flush(i); + *(u32*)test = data[0]; + +// test.ate = (data[0] ) & 0x1; +// test.atst = (data[0] >> 1) & 0x7; +// test.aref = (data[0] >> 4) & 0xff; +// test.afail = (data[0] >> 12) & 0x3; +// test.date = (data[0] >> 14) & 0x1; +// test.datm = (data[0] >> 15) & 0x1; +// test.zte = (data[0] >> 16) & 0x1; +// test.ztst = (data[0] >> 17) & 0x3; +} + +__forceinline void clampWrite(int i, u32 *data) +{ + clampInfo& clamp = ZeroGS::vb[i].clamp; + + if( s_uClampData[i] != data[0] || ((clamp.minv>>8)|(clamp.maxv<<2)) != (data[1]&0x0fff) ) { + +// if( ZeroGS::vb[i].bNeedTexCheck ) +// ZeroGS::vb[i].FlushTexData(); + + ZeroGS::Flush(i); + s_uClampData[i] = data[0]; + + clamp.wms = (data[0] ) & 0x3; + clamp.wmt = (data[0] >> 2) & 0x3; + clamp.minu = (data[0] >> 4) & 0x3ff; + clamp.maxu = (data[0] >> 14) & 0x3ff; + clamp.minv =((data[0] >> 24) & 0xff) | ((data[1] & 0x3) << 8); + clamp.maxv = (data[1] >> 2) & 0x3ff; + + ZeroGS::vb[i].bTexConstsSync = FALSE; + } +} + +void __fastcall GIFRegHandlerNull(u32* data) +{ +#ifdef _DEBUG + if( (((uptr)&data[2])&0xffff) == 0 ) + return; + + // 0x7f happens on a lot of games + if( data[2] != 0x7f && (data[0] || data[1]) ) { + DEBUG_LOG("Unexpected reg handler %x %x %x\n", data[0], data[1], data[2]); + } +#endif +} + +void __fastcall GIFRegHandlerPRIM(u32 *data) +{ + if (data[0] & ~0x3ff) { + //WARN_LOG("warning: unknown bits in prim %8.8lx_%8.8lx\n", data[1], data[0]); + } + + gs.nTriFanVert = gs.primIndex; + gs.primC = 0; + prim->prim = (data[0]) & 0x7; + gs._prim[0].prim = (data[0]) & 0x7; + gs._prim[1].prim = (data[0]) & 0x7; + gs._prim[1]._val = (data[0]>>3)&0xff; + + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerRGBAQ(u32* data) +{ + gs.rgba = data[0]; + gs.vertexregs.rgba = data[0]; + *(u32*)&gs.vertexregs.q = data[1]; +} + +void __fastcall GIFRegHandlerST(u32* data) +{ + *(u32*)&gs.vertexregs.s = data[0]&0xffffff00; + *(u32*)&gs.vertexregs.t = data[1]&0xffffff00; + //*(u32*)&gs.q = data[2]; +} + +void __fastcall GIFRegHandlerUV(u32* data) +{ + gs.vertexregs.u = (data[0]) & 0x3fff; + gs.vertexregs.v = (data[0] >> 16) & 0x3fff; +} + +void __fastcall GIFRegHandlerXYZF2(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void __fastcall GIFRegHandlerXYZ2(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX2(); +} + +void __fastcall GIFRegHandlerTEX0_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + tex0Write(0, data); +} + +void __fastcall GIFRegHandlerTEX0_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + tex0Write(1, data); +} + +void __fastcall GIFRegHandlerCLAMP_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + clampWrite(0, data); +} + +void __fastcall GIFRegHandlerCLAMP_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) { + return; + } + clampWrite(1, data); +} + +void __fastcall GIFRegHandlerFOG(u32* data) +{ + //gs.gsvertex[gs.primIndex].f = (data[1] >> 24); // shift to upper bits + gs.vertexregs.f = data[1]>>24; +} + +void __fastcall GIFRegHandlerXYZF3(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1] & 0xffffff; + gs.vertexregs.f = data[1] >> 24; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void __fastcall GIFRegHandlerXYZ3(u32* data) +{ + gs.vertexregs.x = (data[0]) & 0xffff; + gs.vertexregs.y = (data[0] >> (16)) & 0xffff; + gs.vertexregs.z = data[1]; + gs.gsvertex[gs.primIndex] = gs.vertexregs; + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + + KICK_VERTEX3(); +} + +void __fastcall GIFRegHandlerNOP(u32* data) +{ +} + +void tex1Write(int i, u32* data) +{ + tex1Info& tex1 = ZeroGS::vb[i].tex1; + + if( conf.bilinear == 1 && (tex1.mmag != ((data[0] >> 5) & 0x1) || tex1.mmin != ((data[0] >> 6) & 0x7)) ) { + ZeroGS::Flush(i); + ZeroGS::vb[i].bVarsTexSync = FALSE; + } + tex1.lcm = (data[0] ) & 0x1; + tex1.mxl = (data[0] >> 2) & 0x7; + tex1.mmag = (data[0] >> 5) & 0x1; + tex1.mmin = (data[0] >> 6) & 0x7; + tex1.mtba = (data[0] >> 9) & 0x1; + tex1.l = (data[0] >> 19) & 0x3; + tex1.k = (data[1] >> 4) & 0xff; +} + +void __fastcall GIFRegHandlerTEX1_1(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[0].zbuf.zmsk ) { + return; + } + + tex1Write(0, data); +} + +void __fastcall GIFRegHandlerTEX1_2(u32* data) +{ + if( (g_GameSettings&GAME_XENOSPECHACK) && ZeroGS::vb[1].zbuf.zmsk ) + return; + + tex1Write(1, data); +} + +void __fastcall GIFRegHandlerTEX2_1(u32* data) +{ + tex2Write(0, data); +} + +void __fastcall GIFRegHandlerTEX2_2(u32* data) +{ + tex2Write(1, data); +} + +void __fastcall GIFRegHandlerXYOFFSET_1(u32* data) +{ + // eliminator low 4 bits for now + ZeroGS::vb[0].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[0].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[0].offset.x &= ~15; +// ZeroGS::vb[0].offset.y &= ~15; +// } +} + +void __fastcall GIFRegHandlerXYOFFSET_2(u32* data) +{ + ZeroGS::vb[1].offset.x = (data[0]) & 0xffff; + ZeroGS::vb[1].offset.y = (data[1]) & 0xffff; + +// if( !conf.interlace ) { +// ZeroGS::vb[1].offset.x &= ~15; +// ZeroGS::vb[1].offset.y &= ~15; +// } +} + +void __fastcall GIFRegHandlerPRMODECONT(u32* data) +{ + gs.prac = data[0] & 0x1; + prim = &gs._prim[gs.prac]; + + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerPRMODE(u32* data) +{ + gs._prim[0]._val = (data[0]>>3)&0xff; + + if (gs.prac == 0) + ZeroGS::Prim(); +} + +void __fastcall GIFRegHandlerTEXCLUT(u32* data) +{ + if( ZeroGS::vb[0].bNeedTexCheck ) + ZeroGS::vb[0].FlushTexData(); + if( ZeroGS::vb[1].bNeedTexCheck ) + ZeroGS::vb[1].FlushTexData(); + gs.clut.cbw = ((data[0] ) & 0x3f) * 64; + gs.clut.cou = ((data[0] >> 6) & 0x3f) * 16; + gs.clut.cov = (data[0] >> 12) & 0x3ff; +} + +void __fastcall GIFRegHandlerSCANMSK(u32* data) +{ +// ZeroGS::Flush(0); +// ZeroGS::Flush(1); +// ZeroGS::ResolveC(&ZeroGS::vb[0]); +// ZeroGS::ResolveZ(&ZeroGS::vb[0]); + + gs.smask = data[0] & 0x3; +} + +void __fastcall GIFRegHandlerMIPTBP1_1(u32* data) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[0].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP1_2(u32* data) +{ + miptbpInfo& miptbp0 = ZeroGS::vb[1].miptbp0; + miptbp0.tbp[0] = (data[0] ) & 0x3fff; + miptbp0.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp0.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp0.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp0.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp0.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP2_1(u32* data) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[0].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerMIPTBP2_2(u32* data) +{ + miptbpInfo& miptbp1 = ZeroGS::vb[1].miptbp1; + miptbp1.tbp[0] = (data[0] ) & 0x3fff; + miptbp1.tbw[0] = (data[0] >> 14) & 0x3f; + miptbp1.tbp[1] = ((data[0] >> 20) & 0xfff) | ((data[1] & 0x3) << 12); + miptbp1.tbw[1] = (data[1] >> 2) & 0x3f; + miptbp1.tbp[2] = (data[1] >> 8) & 0x3fff; + miptbp1.tbw[2] = (data[1] >> 22) & 0x3f; +} + +void __fastcall GIFRegHandlerTEXA(u32* data) +{ + texaInfo newinfo; + newinfo.aem = (data[0] >> 15) & 0x1; + newinfo.ta[0] = data[0] & 0xff; + newinfo.ta[1] = data[1] & 0xff; + + if( *(u32*)&newinfo != *(u32*)&gs.texa ) { + ZeroGS::Flush(0); + ZeroGS::Flush(1); + *(u32*)&gs.texa = *(u32*)&newinfo; + gs.texa.fta[0] = newinfo.ta[0]/255.0f; + gs.texa.fta[1] = newinfo.ta[1]/255.0f; + + ZeroGS::vb[0].bTexConstsSync = FALSE; + ZeroGS::vb[1].bTexConstsSync = FALSE; + } +} + +void __fastcall GIFRegHandlerFOGCOL(u32* data) +{ + ZeroGS::SetFogColor(data[0]&0xffffff); +} + +void __fastcall GIFRegHandlerTEXFLUSH(u32* data) +{ + ZeroGS::SetTexFlush(); +} + +void __fastcall GIFRegHandlerSCISSOR_1(u32* data) +{ + Rect2& scissor = ZeroGS::vb[0].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(0); + scissor = newscissor; + + ZeroGS::vb[0].bNeedFrameCheck = 1; + } +} + +void __fastcall GIFRegHandlerSCISSOR_2(u32* data) +{ + Rect2& scissor = ZeroGS::vb[1].scissor; + + Rect2 newscissor; + + newscissor.x0 = ((data[0] ) & 0x7ff) << 3; + newscissor.x1 = ((data[0] >> 16) & 0x7ff) << 3; + newscissor.y0 = ((data[1] ) & 0x7ff) << 3; + newscissor.y1 = ((data[1] >> 16) & 0x7ff) << 3; + + if( newscissor.x1 != scissor.x1 || newscissor.y1 != scissor.y1 || + newscissor.x0 != scissor.x0 || newscissor.y0 != scissor.y0 ) { + + ZeroGS::Flush(1); + scissor = newscissor; + + // flush everything + ZeroGS::vb[1].bNeedFrameCheck = 1; + } +} + +void __fastcall GIFRegHandlerALPHA_1(u32* data) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(u16*)&newalpha != *(u16*)&ZeroGS::vb[0].alpha ) { + ZeroGS::Flush(0); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(u16*)&ZeroGS::vb[0].alpha = *(u16*)&newalpha; + } +} + +void __fastcall GIFRegHandlerALPHA_2(u32* data) +{ + alphaInfo newalpha; + newalpha.abcd = *(u8*)data; + newalpha.fix = *(u8*)(data+1); + + if( *(u16*)&newalpha != *(u16*)&ZeroGS::vb[1].alpha ) { + ZeroGS::Flush(1); + + if( newalpha.a == 3 ) newalpha.a = 0; + if( newalpha.b == 3 ) newalpha.b = 0; + if( newalpha.c == 3 ) newalpha.c = 0; + if( newalpha.d == 3 ) newalpha.d = 0; + + *(u16*)&ZeroGS::vb[1].alpha = *(u16*)&newalpha; + } +} + +void __fastcall GIFRegHandlerDIMX(u32* data) +{ +} + +void __fastcall GIFRegHandlerDTHE(u32* data) +{ + gs.dthe = data[0] & 0x1; +} + +void __fastcall GIFRegHandlerCOLCLAMP(u32* data) +{ + gs.colclamp = data[0] & 0x1; +} + +void __fastcall GIFRegHandlerTEST_1(u32* data) +{ + testWrite(0, data); +} + +void __fastcall GIFRegHandlerTEST_2(u32* data) +{ + testWrite(1, data); +} + +void __fastcall GIFRegHandlerPABE(u32* data) +{ + //ZeroGS::SetAlphaChanged(0, GPUREG_PABE); + //ZeroGS::SetAlphaChanged(1, GPUREG_PABE); + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + gs.pabe = *data & 0x1; +} + +void __fastcall GIFRegHandlerFBA_1(u32* data) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[0].fba.fba = *data & 0x1; +} + +void __fastcall GIFRegHandlerFBA_2(u32* data) +{ + ZeroGS::Flush(0); + ZeroGS::Flush(1); + ZeroGS::vb[1].fba.fba = *data & 0x1; +} + +void __fastcall GIFRegHandlerFRAME_1(u32* data) +{ + frameWrite(0, data); +} + +void __fastcall GIFRegHandlerFRAME_2(u32* data) +{ + frameWrite(1, data); +} + +void __fastcall GIFRegHandlerZBUF_1(u32* data) +{ + zbufInfo& zbuf = ZeroGS::vb[0].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[0].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[0].zprimmask = 0xffff; + + ZeroGS::vb[0].bNeedZCheck = 1; +} + +void __fastcall GIFRegHandlerZBUF_2(u32* data) +{ + zbufInfo& zbuf = ZeroGS::vb[1].zbuf; + + int psm = (0x30|((data[0] >> 24) & 0xf)); + if( zbuf.zbp == (data[0] & 0x1ff) * 32 && + zbuf.psm == psm && + zbuf.zmsk == (data[1] & 0x1) ) { + return; + } + + // error detection + if( m_Blocks[psm].bpp == 0 ) + return; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + zbuf.zbp = (data[0] & 0x1ff) * 32; + zbuf.psm = 0x30|((data[0] >> 24) & 0xf); + zbuf.zmsk = data[1] & 0x1; + + ZeroGS::vb[1].bNeedZCheck = 1; + + ZeroGS::vb[1].zprimmask = 0xffffffff; + if( zbuf.psm > 0x31 ) ZeroGS::vb[1].zprimmask = 0xffff; +} + +void __fastcall GIFRegHandlerBITBLTBUF(u32* data) +{ + gs.srcbufnew.bp = ((data[0] ) & 0x3fff);// * 64; + gs.srcbufnew.bw = ((data[0] >> 16) & 0x3f) * 64; + gs.srcbufnew.psm = (data[0] >> 24) & 0x3f; + gs.dstbufnew.bp = ((data[1] ) & 0x3fff);// * 64; + gs.dstbufnew.bw = ((data[1] >> 16) & 0x3f) * 64; + gs.dstbufnew.psm = (data[1] >> 24) & 0x3f; + + if (gs.dstbufnew.bw == 0) gs.dstbufnew.bw = 64; +} + +void __fastcall GIFRegHandlerTRXPOS(u32* data) +{ + gs.trxposnew.sx = (data[0] ) & 0x7ff; + gs.trxposnew.sy = (data[0] >> 16) & 0x7ff; + gs.trxposnew.dx = (data[1] ) & 0x7ff; + gs.trxposnew.dy = (data[1] >> 16) & 0x7ff; + gs.trxposnew.dir = (data[1] >> 27) & 0x3; +} + +void __fastcall GIFRegHandlerTRXREG(u32* data) +{ + gs.imageWtemp = data[0]&0xfff; + gs.imageHtemp = data[1]&0xfff; +} + +void __fastcall GIFRegHandlerTRXDIR(u32* data) +{ + // terminate any previous transfers + switch( gs.imageTransfer ) { + case 0: // host->loc + gs.imageTransfer = -1; + break; + case 1: // loc->host + ZeroGS::TerminateLocalHost(); + break; + } + + gs.srcbuf = gs.srcbufnew; + gs.dstbuf = gs.dstbufnew; + gs.trxpos = gs.trxposnew; + gs.imageTransfer = data[0] & 0x3; + gs.imageWnew = gs.imageWtemp; + gs.imageHnew = gs.imageHtemp; + + if( gs.imageWnew > 0 && gs.imageHnew > 0 ) { + switch(gs.imageTransfer) { + case 0: // host->loc + ZeroGS::InitTransferHostLocal(); + break; + + case 1: // loc->host + + ZeroGS::InitTransferLocalHost(); + break; + case 2: + + ZeroGS::TransferLocalLocal(); + break; + + case 3: + gs.imageTransfer = -1; + break; + + default: assert(0); + } + } + else { +#ifndef RELEASE_TO_PUBLIC + WARN_LOG("ZeroGS: dummy transfer\n"); +#endif + gs.imageTransfer = -1; + } +} + +static u32 oldhw[4]; +void __fastcall GIFRegHandlerHWREG(u32* data) +{ + if( gs.imageTransfer == 0 ) { + ZeroGS::TransferHostLocal(data, 2); + } + else { +#ifndef RELEASE_TO_PUBLIC + ERROR_LOG("ZeroGS: HWREG!? %8.8x_%8.8x\n", data[0], data[1]); + //assert(0); +#endif + } +} + +extern int g_GSMultiThreaded; + +void __fastcall GIFRegHandlerSIGNAL(u32* data) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->SIGID = (SIGLBLID->SIGID&~data[1])|(data[0]&data[1]); + +// if (gs.CSRw & 0x1) CSR->SIGNAL = 1; +// if (!IMR->SIGMSK && GSirq) +// GSirq(); + + if (gs.CSRw & 0x1) { + CSR->SIGNAL = 1; + //gs.CSRw &= ~1; + } + if (!IMR->SIGMSK && GSirq) + GSirq(); + } +} + +void __fastcall GIFRegHandlerFINISH(u32* data) +{ + if(!g_GSMultiThreaded) { + + if (gs.CSRw & 0x2) + CSR->FINISH = 1; + if (!IMR->FINISHMSK && GSirq) + GSirq(); + +// if( gs.CSRw & 2 ) { +// //gs.CSRw &= ~2; +// //CSR->FINISH = 0; +// +// +// } +// CSR->FINISH = 1; +// +// if( !IMR->FINISHMSK && GSirq ) +// GSirq(); + } +} + +void __fastcall GIFRegHandlerLABEL(u32* data) +{ + if(!g_GSMultiThreaded) { + SIGLBLID->LBLID = (SIGLBLID->LBLID&~data[1])|(data[0]&data[1]); + } +} diff --git a/plugins/zerogs/opengl/Regs.h b/plugins/zerogs/opengl/Regs.h new file mode 100644 index 0000000000..230ae2ac7d --- /dev/null +++ b/plugins/zerogs/opengl/Regs.h @@ -0,0 +1,101 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __GSREGS_H__ +#define __GSREGS_H__ + +#ifdef _MSC_VER +typedef void (__fastcall *GIFRegHandler)(u32* data); +#else + +#ifdef __x86_64__ +typedef void (*GIFRegHandler)(u32* data); +#else +typedef void (__fastcall *GIFRegHandler)(u32* data); +#endif + +#endif + +void __fastcall GIFPackedRegHandlerNull(u32* data); +void __fastcall GIFPackedRegHandlerRGBA(u32* data); +void __fastcall GIFPackedRegHandlerSTQ(u32* data); +void __fastcall GIFPackedRegHandlerUV(u32* data); +void __fastcall GIFPackedRegHandlerXYZF2(u32* data); +void __fastcall GIFPackedRegHandlerXYZ2(u32* data); +void __fastcall GIFPackedRegHandlerFOG(u32* data); +void __fastcall GIFPackedRegHandlerA_D(u32* data); +void __fastcall GIFPackedRegHandlerNOP(u32* data); + +void __fastcall GIFRegHandlerNull(u32* data); +void __fastcall GIFRegHandlerPRIM(u32* data); +void __fastcall GIFRegHandlerRGBAQ(u32* data); +void __fastcall GIFRegHandlerST(u32* data); +void __fastcall GIFRegHandlerUV(u32* data); +void __fastcall GIFRegHandlerXYZF2(u32* data); +void __fastcall GIFRegHandlerXYZ2(u32* data); +void __fastcall GIFRegHandlerTEX0_1(u32* data); +void __fastcall GIFRegHandlerTEX0_2(u32* data); +void __fastcall GIFRegHandlerCLAMP_1(u32* data); +void __fastcall GIFRegHandlerCLAMP_2(u32* data); +void __fastcall GIFRegHandlerFOG(u32* data); +void __fastcall GIFRegHandlerXYZF3(u32* data); +void __fastcall GIFRegHandlerXYZ3(u32* data); +void __fastcall GIFRegHandlerNOP(u32* data); +void __fastcall GIFRegHandlerTEX1_1(u32* data); +void __fastcall GIFRegHandlerTEX1_2(u32* data); +void __fastcall GIFRegHandlerTEX2_1(u32* data); +void __fastcall GIFRegHandlerTEX2_2(u32* data); +void __fastcall GIFRegHandlerXYOFFSET_1(u32* data); +void __fastcall GIFRegHandlerXYOFFSET_2(u32* data); +void __fastcall GIFRegHandlerPRMODECONT(u32* data); +void __fastcall GIFRegHandlerPRMODE(u32* data); +void __fastcall GIFRegHandlerTEXCLUT(u32* data); +void __fastcall GIFRegHandlerSCANMSK(u32* data); +void __fastcall GIFRegHandlerMIPTBP1_1(u32* data); +void __fastcall GIFRegHandlerMIPTBP1_2(u32* data); +void __fastcall GIFRegHandlerMIPTBP2_1(u32* data); +void __fastcall GIFRegHandlerMIPTBP2_2(u32* data); +void __fastcall GIFRegHandlerTEXA(u32* data); +void __fastcall GIFRegHandlerFOGCOL(u32* data); +void __fastcall GIFRegHandlerTEXFLUSH(u32* data); +void __fastcall GIFRegHandlerSCISSOR_1(u32* data); +void __fastcall GIFRegHandlerSCISSOR_2(u32* data); +void __fastcall GIFRegHandlerALPHA_1(u32* data); +void __fastcall GIFRegHandlerALPHA_2(u32* data); +void __fastcall GIFRegHandlerDIMX(u32* data); +void __fastcall GIFRegHandlerDTHE(u32* data); +void __fastcall GIFRegHandlerCOLCLAMP(u32* data); +void __fastcall GIFRegHandlerTEST_1(u32* data); +void __fastcall GIFRegHandlerTEST_2(u32* data); +void __fastcall GIFRegHandlerPABE(u32* data); +void __fastcall GIFRegHandlerFBA_1(u32* data); +void __fastcall GIFRegHandlerFBA_2(u32* data); +void __fastcall GIFRegHandlerFRAME_1(u32* data); +void __fastcall GIFRegHandlerFRAME_2(u32* data); +void __fastcall GIFRegHandlerZBUF_1(u32* data); +void __fastcall GIFRegHandlerZBUF_2(u32* data); +void __fastcall GIFRegHandlerBITBLTBUF(u32* data); +void __fastcall GIFRegHandlerTRXPOS(u32* data); +void __fastcall GIFRegHandlerTRXREG(u32* data); +void __fastcall GIFRegHandlerTRXDIR(u32* data); +void __fastcall GIFRegHandlerHWREG(u32* data); +void __fastcall GIFRegHandlerSIGNAL(u32* data); +void __fastcall GIFRegHandlerFINISH(u32* data); +void __fastcall GIFRegHandlerLABEL(u32* data); + +#endif diff --git a/plugins/zerogs/opengl/Win32/Conf.cpp b/plugins/zerogs/opengl/Win32/Conf.cpp new file mode 100644 index 0000000000..faec02584d --- /dev/null +++ b/plugins/zerogs/opengl/Win32/Conf.cpp @@ -0,0 +1,100 @@ +#include + +#include "GS.h" +#include "Win32.h" + +extern HINSTANCE hInst; + + +void SaveConfig() { + + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\zerogs.ini"); + + sprintf(szValue,"%u",conf.interlace); + WritePrivateProfileString("Settings", "Interlace",szValue,szIniFile); + sprintf(szValue,"%u",conf.aa); + WritePrivateProfileString("Settings", "Antialiasing",szValue,szIniFile); + sprintf(szValue,"%u",conf.bilinear); + WritePrivateProfileString("Settings", "Bilinear",szValue,szIniFile); + sprintf(szValue,"%u",conf.options); + WritePrivateProfileString("Settings", "Options",szValue,szIniFile); + sprintf(szValue,"%u",conf.gamesettings); + WritePrivateProfileString("Settings", "AdvancedOptions",szValue,szIniFile); +} + +void LoadConfig() { + + FILE *fp; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + memset(&conf, 0, sizeof(conf)); + conf.interlace = 0; // on, mode 1 + conf.mrtdepth = 1; + conf.options = 0; + conf.bilinear = 1; + conf.width = 640; + conf.height = 480; + + if(!szTemp) return ; + strcpy(szTemp, "\\inis\\zerogs.ini"); + fp=fopen("inis\\zerogs.ini","rt"); + if (!fp) + { + CreateDirectory("inis",NULL); + SaveConfig();//save and return + return ; + } + fclose(fp); + + GetPrivateProfileString("Settings", "Interlace", NULL, szValue, 20, szIniFile); + conf.interlace = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Antialiasing", NULL, szValue, 20, szIniFile); + conf.aa = (u8)strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Options", NULL, szValue, 20, szIniFile); + conf.options = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "AdvancedOptions", NULL, szValue, 20, szIniFile); + conf.gamesettings = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Settings", "Bilinear", NULL, szValue, 20, szIniFile); + conf.bilinear = strtoul(szValue, NULL, 10); + + if( conf.aa < 0 || conf.aa > 2 ) conf.aa = 0; + + switch(conf.options&GSOPTION_WINDIMS) { + case GSOPTION_WIN640: + conf.width = 640; + conf.height = 480; + break; + case GSOPTION_WIN800: + conf.width = 800; + conf.height = 600; + break; + case GSOPTION_WIN1024: + conf.width = 1024; + conf.height = 768; + break; + case GSOPTION_WIN1280: + conf.width = 1280; + conf.height = 960; + break; + } + + // turn off all hacks by defaultof + conf.options &= ~(GSOPTION_FULLSCREEN|GSOPTION_WIREFRAME|GSOPTION_CAPTUREAVI); + conf.options |= GSOPTION_LOADED; + + if( conf.width <= 0 || conf.height <= 0 ) { + conf.width = 640; + conf.height = 480; + } +} diff --git a/plugins/zerogs/opengl/Win32/Win32.cpp b/plugins/zerogs/opengl/Win32/Win32.cpp new file mode 100644 index 0000000000..a6d680fdfd --- /dev/null +++ b/plugins/zerogs/opengl/Win32/Win32.cpp @@ -0,0 +1,246 @@ +#include +#include +#include + +#include "resrc1.h" + +#include "GS.h" +#include "Win32.h" + +#include +using namespace std; + +extern int g_nPixelShaderVer; +static int prevbilinearfilter; +HINSTANCE hInst=NULL; + +void CALLBACK GSkeyEvent(keyEvent *ev) { +// switch (ev->event) { +// case KEYPRESS: +// switch (ev->key) { +// case VK_PRIOR: +// if (conf.fps) fpspos++; break; +// case VK_NEXT: +// if (conf.fps) fpspos--; break; +// case VK_END: +// if (conf.fps) fpspress = 1; break; +// case VK_DELETE: +// conf.fps = 1 - conf.fps; +// break; +// } +// break; +// } +} + +#include "Win32/resource.h" + +BOOL CALLBACK LoggingDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, FALSE); + return TRUE; + case IDOK: + if (IsDlgButtonChecked(hW, IDC_LOG)) + conf.log = 1; + else conf.log = 0; + + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +map mapConfOpts; +#define PUT_CONF(id) mapConfOpts[IDC_CONFOPT_##id] = 0x##id; + +void OnInitDialog(HWND hW) +{ + if( !(conf.options & GSOPTION_LOADED) ) + LoadConfig(); + + CheckDlgButton(hW, IDC_CONFIG_INTERLACE, conf.interlace); + CheckDlgButton(hW, IDC_CONFIG_BILINEAR, conf.bilinear); + CheckDlgButton(hW, IDC_CONFIG_DEPTHWRITE, conf.mrtdepth); + CheckRadioButton(hW,IDC_CONFIG_AANONE,IDC_CONFIG_AA4, IDC_CONFIG_AANONE+conf.aa); + CheckDlgButton(hW, IDC_CONFIG_WIREFRAME, (conf.options&GSOPTION_WIREFRAME)?1:0); + CheckDlgButton(hW, IDC_CONFIG_CAPTUREAVI, (conf.options&GSOPTION_CAPTUREAVI)?1:0); + //CheckDlgButton(hW, IDC_CONFIG_CACHEFBP, (conf.options&GSOPTION_ALPHACLAMP)?1:0); + CheckDlgButton(hW, IDC_CONFIG_FULLSCREEN, (conf.options&GSOPTION_FULLSCREEN)?1:0); + //CheckDlgButton(hW, IDC_CONFIG_FFX, (conf.options&GSOPTION_FFXHACK)?1:0); + CheckDlgButton(hW, IDC_CONFIG_BMPSS, (conf.options&GSOPTION_TGASNAP)?1:0); + CheckRadioButton(hW,IDC_CONF_WIN640, IDC_CONF_WIN1280, IDC_CONF_WIN640+((conf.options&GSOPTION_WINDIMS)>>4)); + + prevbilinearfilter = conf.bilinear; + + mapConfOpts.clear(); + PUT_CONF(00000001); + PUT_CONF(00000002); + PUT_CONF(00000004); + PUT_CONF(00000008); + PUT_CONF(00000010); + PUT_CONF(00000020); + PUT_CONF(00000040); + PUT_CONF(00000080); + PUT_CONF(00000200); + PUT_CONF(00000400); + PUT_CONF(00000800); + PUT_CONF(00001000); + PUT_CONF(00002000); + PUT_CONF(00004000); + PUT_CONF(00008000); + PUT_CONF(00010000); + PUT_CONF(00020000); + PUT_CONF(00040000); + PUT_CONF(00080000); + PUT_CONF(00100000); + PUT_CONF(00200000); + PUT_CONF(00800000); + PUT_CONF(01000000); + PUT_CONF(02000000); + PUT_CONF(04000000); + + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + CheckDlgButton(hW, it->first, (conf.gamesettings&it->second)?1:0); + } +} + +void OnOK(HWND hW) { + + u32 newinterlace = IsDlgButtonChecked(hW, IDC_CONFIG_INTERLACE); + + if( !conf.interlace ) conf.interlace = newinterlace; + else if( !newinterlace ) conf.interlace = 2; // off + + conf.bilinear = IsDlgButtonChecked(hW, IDC_CONFIG_BILINEAR); + // restore + if( conf.bilinear && prevbilinearfilter ) + conf.bilinear = prevbilinearfilter; + + //conf.mrtdepth = 1;//IsDlgButtonChecked(hW, IDC_CONFIG_DEPTHWRITE); + + if( SendDlgItemMessage(hW,IDC_CONFIG_AANONE,BM_GETCHECK,0,0) ) { + conf.aa = 0; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA2,BM_GETCHECK,0,0) ) { + conf.aa = 1; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA4,BM_GETCHECK,0,0) ) { + conf.aa = 2; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA8,BM_GETCHECK,0,0) ) { + conf.aa = 3; + } + else if( SendDlgItemMessage(hW,IDC_CONFIG_AA16,BM_GETCHECK,0,0) ) { + conf.aa = 4; + } + else conf.aa = 0; + + conf.options = 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_CAPTUREAVI) ? GSOPTION_CAPTUREAVI : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_WIREFRAME) ? GSOPTION_WIREFRAME : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FULLSCREEN) ? GSOPTION_FULLSCREEN : 0; + //conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_FFX) ? GSOPTION_FFXHACK : 0; + conf.options |= IsDlgButtonChecked(hW, IDC_CONFIG_BMPSS) ? GSOPTION_TGASNAP : 0; + + conf.gamesettings = 0; + for(map::iterator it = mapConfOpts.begin(); it != mapConfOpts.end(); ++it) { + if( IsDlgButtonChecked(hW, it->first) ) + conf.gamesettings |= it->second; + } + GSsetGameCRC(g_LastCRC, conf.gamesettings); + + if( SendDlgItemMessage(hW,IDC_CONF_WIN640,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN640; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN800,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN800; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1024,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1024; + else if( SendDlgItemMessage(hW,IDC_CONF_WIN1280,BM_GETCHECK,0,0) ) conf.options |= GSOPTION_WIN1280; + + SaveConfig(); + EndDialog(hW, FALSE); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + OnInitDialog(hW); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + OnOK(hW); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + + //ZeroGS uses floating point render targets because A8R8G8B8 format is not sufficient for ps2 blending and this requires alpha blending on floating point render targets + //There might be a problem with pixel shader precision with older geforce models (textures will look blocky). + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +s32 CALLBACK GStest() { + return 0; +} + +void CALLBACK GSabout() { + DialogBox(hInst, + MAKEINTRESOURCE(IDD_ABOUT), + GetActiveWindow(), + (DLGPROC)AboutDlgProc); +} + +BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT + DWORD dwReason, + LPVOID lpReserved) { + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + +static char *err = "Error Loading Symbol"; +static int errval; + +void *SysLoadLibrary(char *lib) { + return LoadLibrary(lib); +} + +void *SysLoadSym(void *lib, char *sym) { + void *tmp = GetProcAddress((HINSTANCE)lib, sym); + if (tmp == NULL) errval = 1; + else errval = 0; + return tmp; +} + +char *SysLibError() { + if (errval) { errval = 0; return err; } + return NULL; +} + +void SysCloseLibrary(void *lib) { + FreeLibrary((HINSTANCE)lib); +} diff --git a/plugins/zerogs/opengl/Win32/Win32.h b/plugins/zerogs/opengl/Win32/Win32.h new file mode 100644 index 0000000000..45322b3d01 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/Win32.h @@ -0,0 +1,9 @@ +#ifndef __WIN32_H__ +#define __WIN32_H__ + +#include "resrc1.h" +#include "Win32/resource.h" + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam); + +#endif /* __WIN32_H__ */ diff --git a/plugins/zerogs/opengl/Win32/aviUtil.h b/plugins/zerogs/opengl/Win32/aviUtil.h new file mode 100644 index 0000000000..bb7897fa2d --- /dev/null +++ b/plugins/zerogs/opengl/Win32/aviUtil.h @@ -0,0 +1,484 @@ +#define AVIIF_KEYFRAME 0x00000010L // this frame is a key frame. + +#include +using namespace std; + +#include +#include +#include + +BOOL AVI_Init() +{ + /* first let's make sure we are running on 1.1 */ + WORD wVer = HIWORD(VideoForWindowsVersion()); + if (wVer < 0x010a){ + /* oops, we are too old, blow out of here */ + //MessageBeep(MB_ICONHAND); + MessageBox(NULL, "Cant't init AVI File - Video for Windows version is to old", "Error", MB_OK|MB_ICONSTOP); + return FALSE; + } + + AVIFileInit(); + + return TRUE; +} + +BOOL AVI_FileOpenWrite(PAVIFILE * pfile, const char *filename) +{ + HRESULT hr = AVIFileOpen(pfile, // returned file pointer + filename, // file name + OF_WRITE | OF_CREATE, // mode to open file with + NULL); // use handler determined + // from file extension.... + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +DWORD getFOURCC(const char* value) +{ + if(_stricmp(value, "DIB") == 0) + { + return mmioFOURCC(value[0],value[1],value[2],' '); + } + else if((_stricmp(value, "CVID") == 0) + || (_stricmp(value, "IV32") == 0) + || (_stricmp(value, "MSVC") == 0) + || (_stricmp(value, "IV50") == 0)) + { + return mmioFOURCC(value[0],value[1],value[2],value[3]); + } + else + { + return NULL; + } +} + +// Fill in the header for the video stream.... +// The video stream will run in rate ths of a second.... +BOOL AVI_CreateStream(PAVIFILE pfile, PAVISTREAM * ps, int rate, // sample/second + unsigned long buffersize, int rectwidth, int rectheight, + const char* _compressor) +{ + AVISTREAMINFO strhdr; + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeVIDEO;// stream type + strhdr.fccHandler = getFOURCC(_compressor); + //strhdr.fccHandler = 0; // no compression! + //strhdr.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //strhdr.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //strhdr.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //strhdr.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //strhdr.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //strhdr.dwFlags = AVISTREAMINFO_DISABLED; + //strhdr.dwCaps = + //strhdr.wPriority = + //strhdr.wLanguage = + strhdr.dwScale = 1; + strhdr.dwRate = rate; // rate fps + //strhdr.dwStart = + //strhdr.dwLength = + //strhdr.dwInitialFrames = + strhdr.dwSuggestedBufferSize = buffersize; + strhdr.dwQuality = -1; // use the default + //strhdr.dwSampleSize = + SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream + (int) rectwidth, + (int) rectheight); + //strhdr.dwEditCount = + //strhdr.dwFormatChangeCount = + //strcpy(strhdr.szName, "Full Frames (Uncompressed)"); + + // And create the stream; + HRESULT hr = AVIFileCreateStream(pfile, // file pointer + ps, // returned stream pointer + &strhdr); // stream header + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +string getFOURCCVAsString(DWORD value) +{ + string returnValue = ""; + if( value == 0 ) + return returnValue; + + DWORD ch0 = value & 0x000000FF; + returnValue.push_back((char) ch0); + DWORD ch1 = (value & 0x0000FF00)>>8; + returnValue.push_back((char) ch1); + DWORD ch2 = (value & 0x00FF0000)>>16; + returnValue.push_back((char) ch2); + DWORD ch3 = (value & 0xFF000000)>>24; + returnValue.push_back((char) ch3); + + return returnValue; +} + +string dumpAVICOMPRESSOPTIONS(AVICOMPRESSOPTIONS opts) +{ + char tmp[255]; + string returnValue = "Dump of AVICOMPRESSOPTIONS\n"; + + returnValue += "DWORD fccType = streamtype("; returnValue += getFOURCCVAsString(opts.fccType); returnValue += ")\n"; + returnValue += "DWORD fccHandler = "; returnValue += getFOURCCVAsString(opts.fccHandler); returnValue += "\n"; + + _snprintf(tmp, 255, "DWORD dwKeyFrameEvery = %d\n", opts.dwKeyFrameEvery); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwQuality = %d\n", opts.dwQuality); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwBytesPerSecond = %d\n", opts.dwBytesPerSecond); + returnValue += tmp; + + if((opts.dwFlags & AVICOMPRESSF_DATARATE) == AVICOMPRESSF_DATARATE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_DATARATE\n");} + else if((opts.dwFlags & AVICOMPRESSF_INTERLEAVE) == AVICOMPRESSF_INTERLEAVE){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_INTERLEAVE\n");} + else if((opts.dwFlags & AVICOMPRESSF_KEYFRAMES) == AVICOMPRESSF_KEYFRAMES){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_KEYFRAMES\n");} + else if((opts.dwFlags & AVICOMPRESSF_VALID) == AVICOMPRESSF_VALID){strcpy(tmp, "DWORD fccType = AVICOMPRESSF_VALID\n");} + else {_snprintf(tmp, 255, "DWORD dwFlags = Unknown(%d)\n", opts.dwFlags);} + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpFormat = %d\n", (int)opts.lpFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbFormat = %d\n", opts.cbFormat); + returnValue += tmp; + + _snprintf(tmp, 255, "LPVOID lpParms = %d\n", (int)opts.lpParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD cbParms = %d\n", opts.cbParms); + returnValue += tmp; + + _snprintf(tmp, 255, "DWORD dwInterleaveEvery = %d\n", opts.dwInterleaveEvery); + returnValue += tmp; + + return returnValue; +} + +BOOL AVI_SetOptions(PAVISTREAM * ps, PAVISTREAM * psCompressed, LPBITMAPINFOHEADER lpbi, + const char* _compressor) +{ + + AVICOMPRESSOPTIONS opts; + AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts}; + + memset(&opts, 0, sizeof(opts)); + opts.fccType = streamtypeVIDEO; + opts.fccHandler = getFOURCC(_compressor); + //opts.fccHandler = 0; + //opts.fccHandler = mmioFOURCC('D','I','B',' '); // Uncompressed + //opts.fccHandler = mmioFOURCC('C','V','I','D'); // Cinpak + //opts.fccHandler = mmioFOURCC('I','V','3','2'); // Intel video 3.2 + //opts.fccHandler = mmioFOURCC('M','S','V','C'); // Microsoft video 1 + //opts.fccHandler = mmioFOURCC('I','V','5','0'); // Intel video 5.0 + //opts.dwKeyFrameEvery = 5; + //opts.dwQuality + //opts.dwBytesPerSecond + //opts.dwFlags = AVICOMPRESSF_KEYFRAMES; + //opts.lpFormat + //opts.cbFormat + //opts.lpParms + //opts.cbParms + //opts.dwInterleaveEvery + + /* display the compression options dialog box if specified compressor is unknown */ + if(getFOURCC(_compressor) == NULL) + { + if (!AVISaveOptions(NULL, 0, 1, ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts)) + { + return FALSE; + } + + //printf("%s", dumpAVICOMPRESSOPTIONS(opts)); + //MessageBox(NULL, dumpAVICOMPRESSOPTIONS(opts).c_str(), "AVICOMPRESSOPTIONS", MB_OK); + } + + HRESULT hr = AVIMakeCompressedStream(psCompressed, *ps, &opts, NULL); + if (hr != AVIERR_OK) { + return FALSE; + } + + hr = AVIStreamSetFormat(*psCompressed, 0, + lpbi, // stream format + lpbi->biSize // format size + + lpbi->biClrUsed * sizeof(RGBQUAD) + ); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_SetText(PAVIFILE pfile, PAVISTREAM psText, char *szText, int width, int height, int TextHeight) +{ + // Fill in the stream header for the text stream.... + AVISTREAMINFO strhdr; + DWORD dwTextFormat; + // The text stream is in 60ths of a second.... + + memset(&strhdr, 0, sizeof(strhdr)); + strhdr.fccType = streamtypeTEXT; + strhdr.fccHandler = mmioFOURCC('D', 'R', 'A', 'W'); + strhdr.dwScale = 1; + strhdr.dwRate = 60; + strhdr.dwSuggestedBufferSize = sizeof(szText); + SetRect(&strhdr.rcFrame, 0, (int) height, + (int) width, (int) height + TextHeight); // #define TEXT_HEIGHT 20 + + // ....and create the stream. + HRESULT hr = AVIFileCreateStream(pfile, &psText, &strhdr); + if (hr != AVIERR_OK) { + return FALSE; + } + + dwTextFormat = sizeof(dwTextFormat); + hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat)); + if (hr != AVIERR_OK) { + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddFrame(PAVISTREAM psCompressed, int time, LPBITMAPINFOHEADER lpbi) +{ + int ImageSize = lpbi->biSizeImage; + if (ImageSize == 0) + { + if (lpbi->biBitCount == 24) + { + ImageSize = lpbi->biWidth * lpbi->biHeight * 3; + } + } + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + time, // time of this frame + 1, // number to write + (LPBYTE) lpbi + // pointer to data + lpbi->biSize + + lpbi->biClrUsed * sizeof(RGBQUAD), + ImageSize, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + return TRUE; +} + +BOOL AVI_AddText(PAVISTREAM psText, int time, char *szText) +{ + int iLen = (int)strlen(szText); + + HRESULT hr = AVIStreamWrite(psText, + time, + 1, + szText, + iLen + 1, + AVIIF_KEYFRAME, + NULL, + NULL); + if (hr != AVIERR_OK) + return FALSE; + + return TRUE; +} + +BOOL AVI_CloseStream(PAVISTREAM ps, PAVISTREAM psCompressed, PAVISTREAM psText) +{ + if (ps) + AVIStreamClose(ps); + + if (psCompressed) + AVIStreamClose(psCompressed); + + if (psText) + AVIStreamClose(psText); + + + + return TRUE; +} + +BOOL AVI_CloseFile(PAVIFILE pfile) +{ + if (pfile) + AVIFileClose(pfile); + + return TRUE; +} + +BOOL AVI_Exit() +{ + AVIFileExit(); + + return TRUE; +} + + + + + + + + + + + + + + + + +/* Here are the additional functions we need! */ + + +static PAVIFILE pfile = NULL; +static PAVISTREAM ps = NULL; +static PAVISTREAM psCompressed = NULL; +static int count = 0; + + +// Initialization... +bool START_AVI(const char* file_name) +{ + if(! AVI_Init()) + { + //printf("Error - AVI_Init()\n"); + return false; + } + + if(! AVI_FileOpenWrite(&pfile, file_name)) + { + //printf("Error - AVI_FileOpenWrite()\n"); + return false; + } + + return true; +} + +bool ADD_FRAME_FROM_DIB_TO_AVI(const char* _compressor, int _frameRate, int width, int height, int bits, void* pdata) +{ + if(count == 0) + { + if(! AVI_CreateStream(pfile, &ps, _frameRate, + width*height/bits, + width, + height, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + return false; + } + + BITMAPINFOHEADER bi; + memset(&bi, 0, sizeof(bi)); + bi.biSize = sizeof(BITMAPINFOHEADER); + bi.biWidth = width; + bi.biHeight = height; + bi.biPlanes = 1; + bi.biBitCount = bits; + bi.biCompression = BI_RGB; + bi.biSizeImage = width * height * bits /8; + if(! AVI_SetOptions(&ps, &psCompressed, &bi, _compressor)) + { + return false; + } + } + + HRESULT hr = AVIStreamWrite(psCompressed, // stream pointer + count, // time of this frame + 1, // number to write + pdata, + width*height/8, // lpbi->biSizeImage, // size of this frame + AVIIF_KEYFRAME, // flags.... + NULL, + NULL); + if (hr != AVIERR_OK) + { + char strMsg[255]; + _snprintf(strMsg, 255, "Error: AVIStreamWrite, error %d",hr); + MessageBox(NULL, strMsg, "", MB_OK); + return FALSE; + } + + count++; + return true; +} + +//Now we can add frames +// ie. ADD_FRAME_FROM_DIB_TO_AVI(yourDIB, "CVID", 25); +bool ADD_FRAME_FROM_DIB_TO_AVI(HANDLE dib, const char* _compressor, int _frameRate) +{ + LPBITMAPINFOHEADER lpbi; + if(count == 0) + { + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_CreateStream(pfile, &ps, _frameRate, + (unsigned long) lpbi->biSizeImage, + (int) lpbi->biWidth, + (int) lpbi->biHeight, _compressor)) + { + //printf("Error - AVI_CreateStream()\n"); + GlobalUnlock(lpbi); + return false; + } + + if(! AVI_SetOptions(&ps, &psCompressed, lpbi, _compressor)) + { + //printf("Error - AVI_SetOptions()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + } + + lpbi = (LPBITMAPINFOHEADER)GlobalLock(dib); + if(! AVI_AddFrame(psCompressed, count * 1, lpbi)) + { + //printf("Error - AVI_AddFrame()\n"); + GlobalUnlock(lpbi); + return false; + } + + GlobalUnlock(lpbi); + count++; + return true; +} + +// The end... +bool STOP_AVI() +{ + if(! AVI_CloseStream(ps, psCompressed, NULL)) + { + //printf("Error - AVI_CloseStream()\n"); + return false; + } + + if(! AVI_CloseFile(pfile)) + { + //printf("Error - AVI_CloseFile()\n"); + return false; + } + + if(! AVI_Exit()) + { + //printf("Error - AVI_Exit()\n"); + return false; + } + + return true; +} + diff --git a/plugins/zerogs/opengl/Win32/jconfig.h b/plugins/zerogs/opengl/Win32/jconfig.h new file mode 100644 index 0000000000..1f43a6e119 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/jconfig.h @@ -0,0 +1,52 @@ +/* jconfig.mc6 --- jconfig.h for Microsoft C on MS-DOS, version 6.00A & up. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +//#define NEED_FAR_POINTERS /* for small or medium memory model */ +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +//#define USE_MSDOS_MEMMGR /* Define this if you use jmemdos.c */ + +#define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */ + +//#define USE_FMEM /* Microsoft has _fmemcpy() and _fmemset() */ + +#define NEED_FHEAPMIN /* far heap management routines are broken */ + +#define SHORTxLCONST_32 /* enable compiler-specific DCT optimization */ +/* Note: the above define is known to improve the code with Microsoft C 6.00A. + * I do not know whether it is good for later compiler versions. + * Please report any info on this point to jpeg-info@uunet.uu.net. + */ + +#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 */ + +#define TWO_FILE_COMMANDLINE +#define USE_SETMODE /* Microsoft has setmode() */ +#define NEED_SIGNAL_CATCHER /* Define this if you use jmemdos.c */ +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/plugins/zerogs/opengl/Win32/jmorecfg.h b/plugins/zerogs/opengl/Win32/jmorecfg.h new file mode 100644 index 0000000000..c856e2260c --- /dev/null +++ b/plugins/zerogs/opengl/Win32/jmorecfg.h @@ -0,0 +1,363 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, 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 */ + +/* 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 macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* 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! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* 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 +#define FAR far +#else +#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: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define 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? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define 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 3 /* 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/plugins/zerogs/opengl/Win32/jpeglib.h b/plugins/zerogs/opengl/Win32/jpeglib.h new file mode 100644 index 0000000000..a893130b38 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/jpeglib.h @@ -0,0 +1,1099 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, 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 + +/* + * 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 "jconfig.h" /* widely used configuration options */ +#endif +#include "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 62 /* Version 6b */ + + +/* 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 + + +/* 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. + */ + +#undef FAR +#define FAR + +typedef JSAMPLE *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 *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 array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array 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 currently used only for decompression. + */ + 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; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* 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 */\ + void * client_data; /* Available for use by application */\ + 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? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* 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; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* 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; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + 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 */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* 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; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* 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_CreateCompress jCreaCompress +#define jpeg_CreateDecompress 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_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#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_save_markers jSaveMarkers +#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 of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +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, FILE * 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)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* 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)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* 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 "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/plugins/zerogs/opengl/Win32/libjpeg.lib b/plugins/zerogs/opengl/Win32/libjpeg.lib new file mode 100644 index 0000000000000000000000000000000000000000..ae22f9c400f4473bd6e6e5038c4da14713f501f8 GIT binary patch literal 470518 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

H{y z>PSd+&<1D|iIym>Dk%-sR)mg(6q=vUTA0Y<3SU{Rzo@u0kgTz*8l8jcE$Y{6 z({i9HOZ;U;wNx8%@+Ll5jjybzy1b&Q#P370d38v&q(+FZFdJXdm7=~Dt+s#du)f+F zxYp+{DXk2YRmnt|u-|GZnK}gC(rn@Lnxekg607kQquqlweqSB8FBj(3qOWu3E_<;| z%TfcoP$2p$f3Tvos>s07PKcfRcHxD5r6vBN>L3(^g^g8Uk=yEx;$wYb-o;k&qf1;; z=_{!&uc@ppt1+@=k;OTq!n|w&$LTy4Uz|2FQt2zqHkF{H0#=~dUj<|5GtV2rHg%!? z=0<7a!>bu<*{r;(s-jR)ZJ7^;jihj*i{=mbYRao?tBU<0UlEcrY^+r%G`evdsSs^~ z{eNbe{OGqOq2kga^g`o&QdA4TO!O*~Z*GJ(vBfa^rRBvnMMy;LHOKBcs3-;&vkgTG zw&Irf{53VmFHjTwSEF#2jhLXwmE{#>l_7Xs2GTlgW@c)E(Z*)B z{%W7Us5BG|0BrdkJT7Lc1iN;*FniJ;N%vP+@Je6M9|{C&;DkoQErqhsV%!Iqqneoj z2kBr4en_y$r`#QJSk26RvO-3~OKN?kWmUB$)x{WdgZ4a)un0IPye8Pjb@o&6*b1!lx^)s4Xfg$I#ij7IG0M=P+@hicCO8mlnv<(ojWN zFj#K1Mx01UHw0UYu_@pSC=7>Nc~Wn3u2#1|w+zkMr3vOF6SC;BWT`f_z;slTGq-l8&F%wBk6MP`TDTG*P2mK6EQ zDqw-&aK%wr9B#3)tnrlxD=I3A0#S3=nANluHt4GfR@b0S*ztL=&+PT8bMb5wiit^( zX>hH4%YC7$>QI%x27dCCXmK*o2DiYqzF?@NxTv(WXbSKY*<$`?f}u<$6``uqDwI3= z=pefopy+nAwmd&*l$r)6S{*UUl+{!PN&+BiSnVcT`$8S$8AHQ0m3H4OfWOiQJ5gC) zT2pK|bZT%CX3}&u&}H**=8vweh4uT2D?`xAstTWMCF>NTv=>b{hDeBXb}V23z@nOf zA7wTNwV3&#PB{8vf-y1*@1Uv(smL>ntfOe&3EsF(PPM+`(qMT_O)a~vI?jk*FV8co z%Bd5L5TZ42giBQlGXdXF%GWTOIQdwZhog=5)_@loC@v0#AXjr0Morl5qYzKhM42+! z?3(i8lA7|WkWWmd^5iKtI#3v7ADlz1VBbitd;>*|2ck{)+ zJRHD^YV_hVUvW{DzY-@Up)HmSG2!DVFR?ZyF2+O_hBX9h&ZC=!^O2mK;lN@7^;c=Y$d*u^6FB5Q7zmE9uY0f!x>TP6%L7-hA(ObvAD!ni5UX)113lT zf=2|PI#uPhwH1MC6Hw&Gb#+h`O=ykoSS|J!*TQ$Isx$??2Qc~_mNlh!x-o!q| zv*{cl(D8VndrI{T!gZ>~!bYgnsHtU0)cI3eCD8=IaxD0UDq&CLOQ)h1h}T0y%}S$h zSQ820s%p^d%4%sqly_$?EKkHmd4)o^(I10TI(K5-AG1;QMw2L+LTPGCtIPeR0Zf97 z3=LO>=WRLe)7(l$jkaBI3xidqST@8I%Q%b+V=2!Pvqhjh;yf-QX)@c*hQvBfX;q*y zP+0{pALmRbDVecEf!3$unLyaQ+A?&GYOKB~Ghxg}YdFe&Fb|cZxHpa37*#w9CajEq$Ho#h*QC~Y%!~= ztqD~5OM+!qYnuj%3;aey!&HlThaHXu6VA_SDoydr7ag^_wRx?&;mgJI zaJ)RjOt}HQ3y-<1@2FF2Se0zus-CC^l%llS>~nK+`N}0D%$alUy!rFz=4a0}V&vzX z?Cf*T#SfXy$(c7_#_;#d@Eeq0y}q==Vg0(?RKI8DOwjCMir+Ki_KfTaeB$@aqP7h% zkzeAEFDCqod}59b0eB4W4mCzUR3@Jre;dKW->PI_(o?-h`8LFV13W<{gh0Mn=`8}! z$|ydj_etOHJ72xucTSw|_iYjG{yAMM*UZ>p?P|kI zmKL4qt?kB3TH3$LSH18N5Zrt09n!ZQK&=M%>ARLFY(~# z^=rwd7rSwSeHvm9PU9;gwS7fmAB4V(rO@k>T{rKKR3z(xGY%cu~OCEuIJQtuIB?Vqd`XIKCm0AANPmj|c1P z$K9x(Q6bWZ?HM?f7(NT-K*jzvaL5s!HgG7R@8R(xCs2COSrAO#e7Alr%byTRK6oqA z{yh@a1D^Bw8J>Rrqs-$tJ>WxXGxTkIai;Ebuh^>}yRXQ@jaT{!;Eoih>c`fP&qS^{ zdsgrVFwvr{BLg*(!FX}OaiC)y7FWvAEcl_{wBF~mw@gcE(8kBHNkQ{*27FGo=vXo) zx_?sC)`20F2tHI_!d5xCy~B~f-f0if+h^D%90|YV6@LW}ugaDEhzMiri$n8@yYjFe z?`VjTofCUvR4`&{jR?UL-M5*ZeOre^o4B2a-yI2*BWqap{7-jT}XiSVZEURM!B^O7h@^axUm|q*=Uep z8eqZPJt4BYbyWi=h9V91n#^8U=RDY4D}0=F&dtqHcAM7u1Yw;k(0vxL$_UY|&+qJK zS160d?;=cLow*I}mI-`QS!eEKJJV=#nOaP1>IYw);$=HcWu2cz{6%r5SAb@(WYZ(W zN{{wqiQ*BAxWuydjo>qm_8uv{ug00)Ao#9Pys^?_!M_Kd?@<{M$QP@8KLyY2QG8R$ zZ#nRL6%W&6h?U+KrsF6g{upAFk6TLf!E<92U##?Q1JC_Yd{dQ=ebhK2%X}GPrME2^ zzZ`-;hFImxz>Q(WBRONIxBn>o-a7smVx{*AZoB}Vhp0FRw9>K4myLcV2Qn+YPwE}y zEAL=#yxxJBdA5E^_n;)*sc*j*Rn@PYk85P%a@`k>6gBQ;m5n{C6cK|QXzP~LFV#1v zd-U%KoPT-2*9hHQua~9kUmpcu&TE5vB30?0EenQvQ?AtOm+2+xX|9{ycsWd}?)+)} z5F+s|n1zd$j@M@(G95^`6r}?riwEv^7Q964=KcHpRAEj352miyE!X{xnSU>MV|}9j zhTf5$p_giW*-YmCf;SQMCK5#M`@vd2SUbs04WlR~@M7?Qx7^Z7Z`jQ$4Y4MgG)*vO4ESQv9n4=s= zaLKff7@5*UrV|Czz^hEis~?3zd-TgG#z;y!qEhv8r(;Cl!5Y^sb=~&so#1!f)_*NN za-JG|AhJ2#9VtooMwX|ixOUx)Sb)-(KwepNf82WRcl9;hh|AWGa{O1pJH5e!4!pl- zM?%ryIGED5WbYW=@eln`{qd2P6ZMbuy(0(QZTen)dAjGVpX(1&h6B$#-ufAuHx;R* zIo>OHr)LC`$$&Gom~KwP4`hRJ2JpIc4b`qXYLj3&tXd zL}5LyofnOdkFU6>;X<_YUb<*sz@Kz_*aKIlT66BUzpZU5zU9arcb7wpD7mV~Cv*U!ocDE1z3r2e0LRq}JPM~jKpR-_ua@+hU ziy)d$=$6P;o(D{i$~BeAr|5$O*XO)DxMxc}8;25HsyqK(ukJ>jz5017*Uy(l0*K@+=x!JU4OV z{X_@{MNiciW%veONepM{uLuPJ^HA<0*KG^Oi@=xwMj~hW6bjX=?t2OmuG`AT!8lYk zCt>7p;`Ze2p#&rc6=sqA6!WNS=O)$CLd=Fo>(r!}&k^-u2Vg;yiH2BHq|)T<8GOLC z%Yn3DW1!C&OC#a*Y$!0^`UI0O_<(*+-!y&82L~Pc7N_gBK6H)GQ%&`ht-hh$^^U*0 zZd;mARtia^x^64ghMYdfJwu*faZng}-?@Ee*^sAuXz>Zt@ujqA`%Gk>0Z9}=68f|H z8{zZODsCl@Ql_mESU}dAxVP#!A-MB%;U`Ig;8pk!+ zJsd(Kau7FNg9N3Fyn4X7boDSIe+x!!2_`rCXym)JDLLc&9Ej5P(cOZHxg=TNmc`8O zO)1!iUYQo2Ddr|LO8N=)! zzcgiVyl;jq$DxvRmr>kY8MUj_A6X8%m-(RDfO2?8Z$dtU0G4RrW@M2C}g}7EgANqetaqC z&=LPA@^R}m>Ar!z&VlfZH`r?UNd#PJMw7JZ zs118plK9aPwn~!rWyDcmlC)}2v?WQ}CQvl7@@E|KK}j=Ae}{UKpdBmpY(D5%b5G@Z zG=l}(wx^m!MwgjJ!I5CN1qXLtvfoPi3?_mweNxJ_VD^-!i}`7E%5YVqQr>ajfwfl3 z=P_A?qb8+H&9bL_)TESIS{UU7nVxg|UFBBFAVruVQYN`nM&QaBeYE7^Bu~g|#-zNs z^5aM_2Is8l?=80STBA}vW>PJVos{x1lTv2SaU^hjMMbm=9)1yRMvB4EGuNb)*%j>a zaZO5jrrg>lTtoj@NfiRX#B;Q6;{gMk&*a86z>E* zWPi4&eEg)8d7{>lz&=k6C@4OAvz0Pea~M8{l;tXo7>GpN#5O$vvG%+^C-Qm(@eN{w zN&_DvHuQB%n}NvI?x=5VeH|Tq#t{|O+0_-zfg@K@H`g>{V_t(ytD&cBL$B7bdhYr; zQ5^U>*Zy@*Lt9g4^Co-b+)0sgamFYpS8IBBJO(hV#mvjMR${Oc{xK`%b91xR+6~uY zQp8%!4wwfl;fgTTTFl$3l@$vb#%=VTIwOvH>Xl7mL}^p4#ax2B-vC4NC>0J*VV~vGL$12~y zV~u6+$E?MC9r%aAvz#U!fuf9+UN?C96`xVQ&wTFR-PIdz4u9&oe;Q|4Y5EL0+bK)+ zyKX@RGDq}Ucfkne)Fb*Xx{;wFI6i!NYq~N2(#ujf3rrW0p+)tWW5Yqp(vR1-Jp=$> z0_z*{T&35hELw;s22R}pH0Fp|4UT(OL>zJgMjd6CuHIWhJ2YLZ6Ke}@{XbX~J&-!M zXJ|!g-^qH7Td()%Wq2yF5Nq^{7A_qRrC~B338d%&I8Z72bu8)k}0DT^5<%gP?dFkQ_nIYwY!S(TnV@G_^6c=PZrEV%26ui?(X%ZcH-^6+Uo zp2~RG_jGqiOb=ADc=&-x4bL|CyrggD6nvt`ep>e6VmytRhYAlqurDA|?90>Z-FO_c zCSegCBdyW++GeE)lQQe4N`N;~Zm5FMj(UR?4D};LfM<<&B=Tzv;LRE9G-kexJsdrwVc;`_lEV!v%*fi%_gS zKaDR>{ot6k>Km`WW2L-UrA%L5IuGkq3`Rf1#N*3v1fqc|)u1+#H_V~`Hz5u?kfw;8 zE90WPMxmU>W3v{SuI(9{<)O{9?^^gc4=pc0KU;cq^w4Gs5A8m<P1QA-tuP3p*0>6IY8FM_9y(@z8%z*yHZpooXnpU%-V>d&^MdQwL?EP3(g z!(TuCgn(i(;5HUT$3Mj1Vf?*`zvuBcg1@c!OW+??%o0Ap-y!_HfxiRz+k?M;EVJ(V zHN+41mcLP|m$|<+@WOP*J^I4bkwXs0W08fa`^v;9sc$16x42*-bZ}2!V#8j2R}fKL zm)>&9P;Khazp$wL5QT)UDIC`B)I4^?~gnfN+iU&z=6`od&<`1FM- zdbu0iL48*X^LhZWCGhq`%*C~fi-$wkuErJdZnfk)aEPn-A^0|n^^~hXG6AoCG_I-o z&Rtb3$U=|4`I@Xt&t8K`1RP!UzzB{i9$s8gMvjv7Y$mikJ?qlxwkp9FI z?{9qpE{dk_yzWYTzzs}s-FD}BS3-X>M-FD(PBXG_X=n(Ky6WW0s(uLbfx&Ut&esV; zf=qjGJiNGI-=$t~E=K;wuTO~l_eJq#?$aN=gV{gv0v4zbKJlTR@>_hb+Ir2!5h;6Vsi%G*R-NWYdcEh=~r zk_owX-V06D>-l&sJ#w@pG9ndD2yi~)e32y{kR_2)P7M}BN>lL>j8vyZmUtr3$ zC>l{YAaH!32~5C3rsSb0WQTeb<$^U%*Fj&?3Dd z1)W&$T7X+_*Vn_i1r?G?wixPQYveC6;ga-Rsbtx)lJxyG|jL&+Y2 zT%csxOk00%&pdDy8QG0|RGQy0@PA$W*!~3m%`Wa9*bV z#NYIkYmkP9FX?TO1r-O68u-Z7cXC2lJfsj$_oS-fLCs&GY6mOth6ptMkthB(_^$qX zcwWK%mwu_9b;^$Jj(ta8bYTNFq={xy^~$_oe?s5?#QU|U|H<)6HOvosGgb@2Fc@ey zy@ro`Ga_e_2&ZR7E_Oy5QX*yU$WlzyGcF2V7%9tW5IQPS%||JuX5I`+YT+~#O=>28 zzFo$x0VOqaBPgkv{IQ*rflAWGOg?5%@H3cWGa)Ivm;D?WTQ}j#Z@H51Yj;!3^@L~X3 zfKqGd=N{K!JMO>)q`AKS4k%*~8W$aZDXe>Ty{+Rv&)heoK=@uh7sS9}m+OkNLHq`P+7mBg%!c-a3knWj>RmWR;*S%o z3Y^L99Y*@@%G38c_S2R^DMX={!{VX|Fh+0N!Lmao3ZT-LZRW;;LB!Dbc-saRRA@tK z72%LsBiNMsD8+YOu{NTObi(N~P{?g%`Y-joRR$M1nwHmnFn{23RC#x@la zLR9(!lt*_;0}Aa%9sH<+KYW2%2Uu*?*2-eM3P-vA}! zUNTm~o^ca0f`gf-5#YVnz%85Dr9YI640&TBU<0>(}zL;GWB-4ZQE$JWaTV19#DG zC4}WSecNtw+!uE1*Io}QSn!y-GjJEbA9IT8)evkNZt)=w#KRN8fGTXjJ%la z7{k_v(+3K)OHUQM1A2Mm*ho9_jeIptPg*n1g>jez{Vs~6;4YTsvMRCrM0frs=K=J- z>qp8@AITS044*3MAW}(+ti~4d$fh*?1g5e`q$1`F5$A7YrOFBpZMhxFAzTJIhk>C= z^Zlk-~sO%y=i2?Za9k5b!34xVBVp6J-=DmLE~%a+TAD!Dhx zJ#>?B`o{;yu{SS#ioT0!VtM#n-RBuvJdm}BJ0HY=anOt3iW}NIkhL_lMpMTOrbCSB zC}l>ZXn{V4&L_l*I>_l3=2<>rq{NJD0GrF?j;?RyycSvOj;u|ItWA!r_2}1nkSUZu zQkQ`(G%0(3iLZ2GlZ2t9gOH@r+w=;GR*_1Yq#X-2&jjVsPBSTd)i~jYR%3qZ6)Jre zXg;QZNx-8A=Ng|_2aar`N^?d5#eOQXEGx1sJF+Y{vTVLypN^H=kr$H1+U?B9wqda7 zkKt$pR(K2cZt*T1YDw2H#Om+g?!&FE_i!qV-FSg?f5GVH|KvjlE>kjJ>7sXnVn{$Y zW5~u|tc@CS_TDV`w9jy(2A93;Ve&7^^(%(!2mYR8@p3`Hhd;`gf3mgsDPy7+#K`MN zFs9FYU!1dDt{afs%L{@Nlzm$Uy&(G|YUiZK;gqZ+fs-Fn+a5W)-%5E7Vi=M{%A^9k zh~QOiu*`@6kA0z(Q+#{wNt1F<7CdxjN%`t_VJ|^~O3`TTWHa{xb%!7Jyy&yo^GcqS z7aeLx0=+|O&!(@PT5aXU?Su?Ri@c(jd+B7`Q^qkQ#6`DGis0c8z&r{Xu3BZK{0qb| zq)bZr7{uCBPMMT4hb~6~dm>xs?$rmbvQplQ7=~j_`8*>daGlr|oY>m)I(AZC?BtFF zN<9I8S3b99la<%Ih+%L~N|~#H_LSWsrvk%xb7n(VTN}>fnP0;=Ac$pg`MMRH z{}9XGnmQ}eu&%kUp~Ta<}_UasQj3cXvq2B!^Epjla>38r45znVH79b&A|@0q|i)gB5e)_f>)bcnSw z`w#HVpmjo^+Dx@lP9y#~#X~-ZSm~V&zVkmOz25;}2A<>C4-uGetn|{rlNH4`Rr%%t zf3D(TdJM7BTL->NKPEjc?|m)K^d3RK=I%X)Sn|t6o4urXBxmgM9S=)*I;|l>tn~1J zQ9BzvH!40F>R9#tJ9rXl)ewyIKJ%6Lb*(+CKIQR_h2pHnA?%yb|AP<1S9ARxbI)_{LjhgIl>2HONh-2PJJt@wa=H%n|gUT63h|^ zb~Xlyl1rLEEKYY0yqb*VkB;=Tdi|Hg!q38LMR=|r$PnvtGdQt?qsomTJ3>P>UhLcu zJ}cZcv68kgATm4HqzAI@rX4BR*ULQ{Tr_jQXU)Zll*8D$aTrrde9h9cwqo+&UVpS+ zven7??7?I88ZTT~?9oVP`B0d2Y@f!ek(&z+=?g=P#_Lny04EgaHCZTM=A&5rugU6j zjF-~0gAbH>l<>UXNmg*72NuRbV57jo-EC8z>s6RCR0!-=gPO4WU7 zoL)eV>Gk?tPLxoqtfl&bZF-MWUzDt;U9K;|p^a^b&egTYUm5(pYuj#Q22_^owoKP; zCj|U>fZ>LV?bUN{f;Qwrx_qXQjVOO(c7OOq6Zs5dx-lq;Yg==ZhBmf)Mt=t7$^O8TybA@ItqKQMW#*WbDE7 z6qL-1Cs%qoWt;{r;=&@<(%8beL!Q4c)z8xxamCV&M?89YvhMjMCe`!x1^)(y1(@ls zcRqe_@F~|eE+#>;3tYFIL;)9<0pr2>iE+-ssV90C^~9?$_#UK_?pQ!M=R!gms3b@n zFgaPZ%>0pYw;%L;a!|^S?I#NIIg%Gp`nirj3p#NEa$v;q36MCGV&v&oNVk>esaBpV zqVin9JZ;GPMV?b4QR7_4``cGQDW-!?-Cj?nSTJzE(1``0u@d$Wer zZaYp$45C6`h5)%N2+3XN*!&%?_CsWp9z>Rj5236O5u`ShHd~5_%9^qLf<(@FUAG-2 zxW;hHad`WwJJO~*9u!4NKyjoJr3oeCkjP=nsriKx(J*0;61zDTj-6|=g{j8@6=D2g zyv6Vt!Fl#tY&fdzj?`r6U!M;}z(g4bQ~J(=5e%t~R{H|<=kb(Aj0ap~NQnfz`o4x0 zFEd`!c3ycW4R`5iCuzmF(h?)GG~XVLF1DPG_kp7RCux`9D(`~OI6^ZR z6WudG$C~KM!LnKK!~gnUJq<6~1|>->%id)TK~7b+PqT~37}oZm_1@pDluuMCf0|uP z96_K6Sesk*V=Lu6mGX4Wt0w1cNf{+n6jL*MyDL> zL;|&(ojCC9-Z3lX>s87;kzk+XGfn$cQ=Uk;74et|ws*8NY-(<9=vlQ={r*JsHhj@d zxTW3Ljjtl+u8)eFVvoIIn-k3@_T5iPP;9@S6f5`EPl)c(X3xu=`W*)`=7hQPbMmZR zTgQnx;rG#qJ|(TGc5VGdwVYysfth+=z1v}O2x6)^VL$FfCh*0YGaQ8uf1>L2RLiO6 zTEJ0-^BUUCSm`|jp4Sv#tn@Yj|DNIjDMGCDI-zu1sCWpm(z_owwu7hUD9J~y zj+Ne@!SjmZiNZ%x!`G6d{muS<@*|VuA7kFC!J${;&%wh_nCaU?Ol3t6`lpJ*DudP zGlA;RD>8n~nilNuYs@cB@4Il|t67PCOY)01_J#BvqqsA$DLHXzU!lHf`LEfuII)?N zzx5VSeVGHBQW7tlm0#4@=gr?ro7R`Ae`5i-@)xG}9h1LsV_$OqRSzLPoS3txVQv znq+mv9n-+%g^@tFnhCli;)LwMz9G+`#B9hQyVGKKMzinR#v0HN9V{O5APdQ!Xt5_w zW~c2qc)VVprU$%{`fiy9M_GLrWf%#B#oV=SDdyy?mA0j6U<4Z#n3aAHx5S*Q-<69m zuAASN8x`~mK5*SU`uK|l&s}!1ey09ix_+*kaYXmekN>sc;APVtdw|+J7AfLmRu7(B zV0YVMoJ+=+%|8)RL5})e%$?`Yw^R=7OV^kF#dY)Nv3(ueEtuKJ^Nxk`LA+l3Ql!l3 zy1B;dy4fW+zmFVnnCD>K*xiogaB6%po^$*fv+3Z#A!oyd8%`Zh7ebA6ZakQ}FR+oS zbkGGt2qX!`iqvn!=6Y-#xUbKl2R7d}^}v>mj_^{+8o6sb?nF9U^0%~vk5i8h zuYCvwK*o_ePyUvUKBT_dyeCd1@t!{wsrMDDNQe@& z4-spNqSZcyrnWv>3#~Q(?_2wvc_bMhm+QU1|Asl)XP>p#ey#mjYwxx8d6Gedc3xO2 z2qS&WHOo8iFKwI``KGyMRp-|Qz%CI?o~@dZc(D@Q{5moM6rqmUF!yz)xzeX{y1bpf z(!Ht8{xY|!oGrMp72mzzPtKiQls1OTsmoJtG zpQ51RW}QIFGj*>PV>_70P1e^x-oN1%=3YCg0(ehFP{Fy2!%64KcMc~pb6BCHpdy?1 zdyXDm2vrm$j2R8-F=SLJju57Ypyl?ahLjee!a1kvSj0Gr4{_buWfF2ayR1$7rPc6kMKJUEyQ1azSBzaX>6i@58ozgpnImwGD% zkg{0B2-73vTRlP^=@Ig?9wD#y2szm!q`#f9MCupx2nqEFnVA-nT0fjR((5OaX$gDS zS#kFTV1R6dJn%_(DqSw6r41*q!PFRc?J(sip~VK!pRl`ZmjToe-Ptm{3J;G)r( z8f@1Q3^3a@s#O_j^LzdB^f0OXHA`Cvr4R zahc>D?*h&t^Q5X1OBesr1eJ%DeISTF*JN2dHO@nhwQA6+JV z_4v>Tn76Ez21zy(zJjx08y7#iO!z*F@>T+74>z^o@R||dPXKe&g3E;OUc~={1p}|R zO!;fUKEoIBqsxTPfe-gsFd8y*{=R|r>JPbQh0BERZhU*ff)PMGGUaa$Ca2|O*x)kZ z8;kx?515C~*KjO)CVW4=z%X9Hk1i8FE{FaIn9o}CI^iU>-_=>kZ%K!11^RBM9-xgzq@uPJRTwEr{>9$S}6yNB3d$d;l=NwBRz; z-yz_59WXz*SkQgw`0{hW{Mv%cgl{^~9J63F#?0j%jd^GSesngz{{{IrZ#F+g`F2h< z1X9b8Z8cErZ#dOXimlaHchOM_ZQ3oF)l~ulMjiZVeDmM%_9z8+KkT!0&RYkJtgThv z@`=%Rb!2mw4=Bt9dFHMHdUpBo+`8)=@dw49hv$LKxp-zB*nBqsEbG`D;9mot^TpFK z){VagvtwxEG@OF9L*IkrDx4}9JoN;NGxMD-M{CtB)MxOTV*1}~eH|dtGhlRtj5RfL ze}QohFaRz(ylwR42`xu)IK-U>@=yZAv%4>jMYtV@dWADn;5-7+`it(#Elt2AlA9e! zOO4tnIzvotcEC!k8`RkesG?`KT_K50%T2@cFVvHbX9xuLj{O2vnGW@03RGX{bnq1= zG$H%WiS6^7uGpWbHtmLJ-h@gU4s(Ses|%V{ZV_EBLHS52lV?w$VI+%IAo`=cMoTxr zUnZoRknXqayKx|LgFk&mq`y&%m;!{dMNGJ0!ChVoQ>j2f`4d+$iI1C);0@9pKe7RB zgBuRd(%J?*v?1RFt+wHb-2&NV^0fX0ku1HamZOmPL%Y}s6gVw2yQ|u!g@a5dq^^a% zRo#A5xg(Pf^Q|OIUv&u9PbbHI>xsSYA>q`x%<=B1FD*voMhjzKoO`3Dv#wSJSk&iK z2((t%;9OX|!yPD>XI5!&mh z5=9R_8eCg~VBoa9ONuMlQE=0R^zJZB_Egu@sz$#$SFNQ&cL0Wtc$dS~fV8!PTHcJF z1#6ymZJk3B#A(ZOv1j5|$3TbqQ^&QuNyU{kxc5j?wS*%b{mHYN7P7pKLjnw68t^j& zo=#v|$~{hCQo!}h#z1b?oVhYM^jf??Z+RVV&tH#q35IhVZ6Bk*I76l&qya7 zfWmeXy1cnLj5I(QvNrLwegM>QQQ_w~#cpN1vPa$}*QocjT%VqvYqXi(Iieylboukg ziB$!tt_8iJA(0F59d?>w0kz>xC}ANGV{RW^!jz3Vl~BdRC2H zWuE5WrE~?adaG#PwhN|>Yk7~GiP3XX;2tL&sT-|B>j7T%wrBV0j{VbO$Fj%8PSD;t z)FtNwN^fGeyqA_tLwYi-%Bi?+##e>>sv7F)1$gDkcpQ74Rx?iP+#LWNklKZtkVCyd zdJgs$a%<$|txSR!5b-ppI!EVe+v!_pl?6S!_k)1^(;SD!O^9`Qc}f*D<8OSD*68H` z<&@xsu|EwWEz0Yx;66R&X>3f*~cK2fmkLJAm(3VgrEhAu|lb zR4c7Qr^scUd=7@01*dcgbOG;GT#{|ffts%m+N4r}E?t2&V)qSg<1gyMmT$=pRMq+2 zs_FzmD_K=M?E4mhw+)y!ZtIk?5@;f_k{X_2?c^WAr@(!zGGD|UJLZi)-0~FScJ_tm zVR)cI%W@L9VL^SJt1?Nx=_&S$b_B6U00eVO>W99_;xPPjj4y(c$Y}ZuALbkmu|DIngb%Nx zXEGUovkXyF6`O7{7g2BaCO=HYwY-ViMP{Qu+?im{HU%WnbMTd&%Nm5;QGW_Ve;Wcd z0IC?^Xq(Dzg%O|ctsTfYM!Hm-M-U`9J-dt45H!LJ;fhm601wOp3ND2%}O3Oa?7_IE{Fuo5c{Ema20hDqmhJ0^ra+UiR=5xNG zR-^l11DB*ZHFm%`uIU4I22Om-Om`J?x&_=&n?exSRP;JcOdsQQ z?0`3n`t?V@iR`;s7qR1G&|X~m^;2!JW94i*gu}8R>&J6j2*;6SWy#hO;X8SXR~Ob5URNYmIzG#xWXsCOg_DpriNN<1mrM3y<);oY7AYPbl1WdYRl1T!ui*wvHk%ms;Bl6mmA ztN=Ldf=b!*;74yfF|a0H;CiUibL&#j$EIs0d0Mz}Q8GQt)56W`O&hZ(dRit*ki*kb z4$rn)XY*lC%Sd=THv93!e+2f~x|3|(wh1{~g|XWDXFz|O-k$&i+J575JX@Bv%xonSh)W!DKuX-b^6YLUUK~c4gbNS^H5Z6!isCsI zkS5yQJIPoI-L^6jq1~NCE7Ox?3KT5Mi&~^$ucWq3cW;|;8mh7X!N^7O^)r$_43=<3 zid>$iK=V+o*Bmn-Q7Vi;wWoO=+#h>$VBA?AI_7D9mpHkmo}xlbS0ZYx^*RRHR>l`q5hS^V_8=*8qUwSXifpua@wYS@OkFytksP%KT|+ub&WT zP@1ZpzGmh!ynxP5x;?kD0Gmq2L>o74$XXKJuxUf~+Gzcz4UR?8Rhu?AmqtMcRee3X z!>(%2?l}W$JiC|o!F4ekglwKicz@6C@|?CeT#l1a?P>G3{lVopW?n*D88^Gkxo9NR z!xW@J*1;-C-TbY)IJtFfruYH>AyAN&xD(Vhjj%Zm92G!~C7M)v3uU-;h#|dY1pJ)4 z0$*onbq)F-&51w(XoDYo6h`%Pu~zg&16B4~G3vz$6n0B%atO2w$7N4yv(;PCi}AU5 zMk2!L3uGDHGY(gd?@W#T1uMr71~v?MWFWG@0ibgrxQ+KbyY_`IIKX$>SKzwt#uA$W zeltq8AelzwZpj2k6NG!Woj!Hk)>-b{F)*=<*ZSwM$|zRb?nSBd-)cJkI@7^u92pfm zJ`lzlvQcLh2vhylt%TtcrvFTl40YzsRtKT%6;SWklOc|j{5(#T8y$j$2`vD5u~_CZ zz0reA6hpCUc2(C*iV={X0#txrk|gTPiRAQpgPY-cm9aA6y9k+J%lHhgR!C_+tcYzm zyc(39yYM&5vJgBPezs%co)OJnSNhdgWHvvF+gp}9Yq|WDAr{LpPs_g$2~%w@xGj5; zvJrTt7732J3l<&SRyuVIpw3BwnrlOO2?fOxlF|khGm=c73QLbleEAVU6 zdRLK0jh=?O@T;4z14VgJi^z*=zV-L81BfiaIB)2+^*M;>RsX_DK3?n7_H#J}LHXj#AJwbv0l%#ni-R!waE%}6Vd43PICr*v6{O9sd> z@Y_o%HQzs5t#{U{5ZEd#r7W>qWFrJ*>yfFx($%kpov2uU5AU$4>wXVIaic6w1{4IwgWtuyRAoofK*FfXe z&&t6f3pE3lvP%|N`m1ymh#!Q>Hd};ZLUqWsy&{#$;SLs^z1FIP->w{4XP$$$b;6cT z$~yCGEbw{%(}3yY@+rMp<@=($>;SUSf&JK9$| zL-LYctlMGllVI_1SJTOV1CM75kJNZ}n@pf980Q}ys|Y5O_I2hJJ=1xv*g`7Wr@Iyw zJY)1f`hHzL6L_CEC_MGiH)>&~WoF)E9&(bGIL33G%nGP7VX(85Sh^N8g4 zNBEuV+j-1%%E*&kCR(Yr0x~7vp5{Lz!1`8CEL`(c5DP3nNzs!x@mgS$0cKZe^Y`#l zr$1;*n^+F9_G+Z|5{uLX2p4mD3kIJ5zVrNl?Xt469Zm;apBzVD{ITo7)vy16zHX1_ zv~DiFumiar%D&_iD<2#Sd}2>*5qvoY{HUo)tFjQDsgkHS%(;Y8!HU2_ZR2YSU$RBl;`o5tfg%0d$zSUARmbX*HdsSYZL3e=&*S^rz`XJ9r7eTaOM#0 zQkuJi%e8j=1Av znV}rf5~va%7j`5G^Z`7_h>z8xee5UXKQ!fUfsZcBx*_*Q_)$qP=Ap(qRe2$*%RM`G z%ojRXs~%&mHD;@WI0=sha%AFFuLD}-i_u}RlLObUc~p49hqrJ(GPiFbvw%Ea^%sCe zi@DLhx;Trr`{S|*U4(fqM^|z;?{$vWX zXNs5^@mM2e_~jTZpRR{y_>%Q-2yb)_(a|tOTV9C8)pU~F5DM&6J6Hix7yNE4%G#Sw zzK$;qzNV9s9}ygy&D&V`cCk)c!H8b2e_T~vgS5Ss=?J51z%AtK$So}6V)9a;9-hi^^06GcEh7b^!kB>|LG+Axvr=avDz0Po`7eJlx1?Truo* z&^c>dT4%{;B|rL9?jh)@m@6YN$Y;eGDlj$^x@ha6q9o?05-{Cc@GOayig{=c%-PAMubDuvoR z5|&uduqi4YUV>{=(nCfW#?xsbMVNJNO%DN`%t;S{n5HBxWCSpCQze1aI$VajI9k6Vax;`c*50sUsZpL9w0!B}8>|oI#TJroc05IyL?ae864t@? zSFBlDw{YFMLRuV6yrFB!tczP!m(u3wiZ$00XbtXVU3eo@g%)x(hnE{xtgE|mVf_l7 z(KQ$`6W_!pY2vMZ>B1$}3zUcC&9Y^h0Fg{0@a8p(>mqBDrcM!r)tOFGVkT8=x(Cw! zX-WpErX)eh_?98nwe{4RDIF0=aUZ2MQ#`zAxCW=zj8C*??i^qk81cmQrZrPcs!Mel zv}UgB2G^U`3@68zy1`{SHQwZe-6Z_zNQ=FlLZ5;UU$tNa5RXjw-oT9b5B%sd;XBN4 z?7t~46TTM!_d5$V6TW+a$F^i+qs)Xa-q$d`h96xfe4Nbx(}EE|JTl=MhV^qkesr1e zQJ6XsFzfnhILrkZ@ihbHP75v*J`Pp8EEtV3Grp$*_u@z3yAeoU156Fq-f(Q{Oy#`= zFmVemQ~sVq{4W7!8EBsF!^-4aR~vBpjJ9@hDD6GKo|W! zlz{e1Ak4)kUI4<83AEQ9ckVDJlo49aPD54#YbVb%E{HwtHLbCSQd9a!fiz7T{xFL zj>njfG(3nsaD=rpG6w`b9t`FpGjWDLAiG@!O03E7sCO$%z{_Zm6wWOl0W5X`1IVSz z(>fU6;#KbI_!w7Wm$uW5eB@!9f|eZpYAni-Z5M&oHfNOJ78_)cdtu7`9d%{wKsI&< zgPsT9YI(15g!*g#@%)$6^9U-yc6YAIy%e|#%(KkgGvUd_{Q}b%9{nTEdk1;m3f69L zRn9fQ7f^3`9(*UZ{{zp1htzBF;)n8If+^Dc=i+77!A@0hj#)5BU20wqG&qPgJ^H4N z1qTm@#jUGHo>xD~f0j1$)#>ISNTtHj_mDI%&Emo2OiO+(M+7- z%BEoMTHcoykXq(2$&nz-y6VaUzuxdhvVIj~yVj`tS*f_ymo+W5JT6$vlaRpc=gzOE z^-ci9o^~TKU#AmU!C_O2G#(eymX-R1 zP9XV|?alwWDkx=5Twz|S3Wl2nL)GPGKJFCL)e>t*kzYmK^7t~1SO(R&-~_%VKyU=A1X1m4{9J9U-QC%bWzrW@ zOh&;5s5XmYiVpLt;=n)NR_|c1FYC z5&~?*LBJOg z$&x>8Q!qDhc12$RzsP)POc+*;StYbz?9~t4nv8$?h9zwqm6I-=y$;HQUkgi#0G3Qh zI_Syy&qXfab=STgcUYsz>pJwU)7bCW`V`irH9b zHWnkA4(ve;@adM~2)~BiD1O)d@*im87#krD~ zsKCh05flUGMR5w$+{L13LWOb=w>ep8ds|m+X3kX@7j;K2jmd14eTxRWA_YuJqi2@b zzUD8&d|o}hG?v%KHw0ttE*uG-0Lx+aSO8l^o(FNHph`_Rfl$fhOjw8U zqUkHyt({cvIM#5GJ-a=KgfGJ{$5@OfmnXW_xe}qvwr*Aj*N;Z){oZQY7{H={2;ly2 z1<&{COc-q!=7X3~-QsN0I~Bn*Cn>radq;mKiJ1Z@x>FH6b4s9F^2(I2CNYyF=uSoO ze6L`@J*WTS0$tm+LDHw|X9T(l64?IfOnD{|azrp7cdr=lB{9#pLQlm|2*(=^N?&=Y z5`uR-&o^0^PenXz4@9Te+>btHWB!7L`BcQi94bg-FCST7k;KedfR2Vj(giky5t?4l z+E7TUK=gEhVLxPT)E{&GEs2?9H66vn=>i+}-gL~Ti}2$`gx6{D#Iop`H8cwj9t04N} ztW3Dx_{{o`1zJqe=Q>cCwK7N5^QnfS#Y;bZ$p$OG;HzMlbRmBn*2 ztC{d^0?ZBz4$*p*S8(+FiUk9&xJ>xQx-jqKN0$j-2;b%b=1Ugbhvn~nz&!pD_}YN) zX~1l@`0@|K_Z7f=*MiHGKXg{(VZfY7fy-20-a0av10-A~e1q^U7ciHlz-7WW8ZZ-5 z;ChoEO#;3dfcdHg$1x@ozIMR8V8Pk>`=s)KPkbl&iZ$z^kyBLapB8xJl`gC^4{q#J zTAAB;rmUMTK}m7c69>aAwd>g4Um(bZYZ|$%^2leknPCJPsCE4zDR_ic5IWeXuj%9T zOdGR79;(p_7-H2Ay5d1@&l}YgD43gz;WsyP4@EDoY8#itH@G#cHQ{|QU|#6RY#gBa z!Ylf_T6>)1cp_~cPG+?YW(X~dwY6`VePQ!8pjwHWG8Eh9>z}pFS6ubTD3-NXxyTmm ze`P@JWCRNhIC0z;+%dt2Afsb~<{0dJdbV!>6RQ(|%7024qWx`dE=MdSip!z4x@#LC z|9AyxzzPo31`j*N2#eOP&170S;qBC3ru+)_UK2k1%3+_;lnC3C@B!H15Sr@P+~6i8 zb=p>VoZmz3wb5#&Z$2NBYi^#0Ks6&^?!1nkF+p{++Z~K6Kde@njPe~pwV!%3x)AK z*r8VF^5n8S>Q&E!ubDR&n=4o-T_P0KoKbmb%sYM(JK4Wc8!|YJIk&o7 z%hAU3Gz5}zn|HRd9(2H%$)-e&z6Qp}Ejf{!AQN|5@>D+Vw44K?nO`UM_8-8koBGLw z4<3W_m!4j=c#UL2!H-MDSfwqzYvBfX=E^6gnCW zUZ_6ew(jO1eG9+{K2x2JW1_`)Q4Ss@8&EBJAFA59ycvNjv#N2x_+f#5^gKeHc=y|2 zVd<5r6KNR*8FvhIc!a88hFv?GQH2z3b@LgQy3%szj7i~#D_`j1>oDK=3l z9H9--o%E>95A!*RN81*du4~&l`x28+>=Y6mmvkU$d2;H}$&vJ|b7hd93X%yhD;jat zJwgER$#T35C;NGP`tBh?URY{oZO@I=k(z7ETtaxNGaaS{0jIgiMsY&uZw6u4-e zbzFdoFO8L^{I$LiS7fj*WBauo6Z`<-Q8R69Rdcr&5TSLpIdLvh$2akbUD#(lj3*1F zi`xbtoo)Y=o4NKeI;pY_`P@-1wT^>}eC;UrqcSD$Fu7`-cZLlZ7Y?E0ub=Scma+OEMCtc{=%qznrY>%t0=YE5>h4$tK9j&Z(18 zEQ6*U<-~}$Ub3(4oa)rh0}!*6BT@@iPmV#xkSXc{OoETjE&%tAGcoFVwq7jopz2TU zgcz5@=`NMAap039i{m&~w+H(z!MO;#CZ&$}-3VB6cd|j+b!T-5o6hQFIx}VuGiNQh zdt)-K^DVrm!n)sQ;W)Xt@bgK`BdpLmYiFt*E`BYeU_Bdjm{a;sL>1XG;$-;aptULP;De3;O@n#b9 zofhVgZ{w3E#Oi46as}@81d|-4HOX!UJeStjtzW!wjs1Dm!pP#~+IpovEdXX*^S;ti zg#$KdymNhYwS6E!cJ|4GYmii1o0f^o)VP{)?g0wExoGq!;hRSml@=!Vu&^pI-Q8N_CEPgOh#vdP)+KQ8&R`$8jUYl^f;dsly6Cy#ZXW0q%ev z8>Itf;+I|q%%3bc5>#*eR}dfmX2IA=XTnD_1bO(;Wy1FwzKsCPpnd}Oq4~QIFe5Fv zO!!)W<{Aq|V>B}Ihfe|S7axJ|9Q1@=1Ll2Bl5k|RGL`oW0}bOF_|av`-wb?s05Jb1 zA~-g6CVaGXbDm6xnelOe$p_3@3+}`4#Q<|hH+-LzA0BO;b1z(cSWP4E|H>GiU5A)_-(@P zLjmv^3-2x%Qt3L0-`n{82ER7^n()iw4+>RTICq|P0>8KLdmX=h_-z8rpM#i|zs^*k zMfY&91aHuDY!2qZQ~Nl3JS@Y&#KKOMbspa8IH&ya*umW*uWoEFN?p(eDFLFOB7w9lHBYYmW zfzA82169#`)Go#rCpTSp7v#6R*)SmPyS(Y2tSj(0wDG~JR32QhiuG{In~}n8|Jv5B zex{ypJDweXqPPIHt=ijO_byZI*vs|e{*7m2zj3_#T@;3;aQuB-4EL$xOXF7#Gz++~ ztvSeOMMsOenz;`h^z1zrSrONv+DMXTuYn!8VKA)otsv4jJbSm7@ls)P-V=Ef#)W?MOs(3Ur%vYo+ibWs?Acvb=y*;wY!8}cw|4gJaNdg6?<$A&oyKPg&AUc+AoY&1 z6gG@xBoyIu~6ei44mU654UKP6+A6xc8 zAr@CC+~V}Kd;vf)93&X(iBsrdS;p!D?>Ww2ZR_4g7U4}5stwSU&6!>)ip0??pi6tE znhYpg+q|qNRODswvH6d50W}*8#z+RxbW?6@pDT7^D5{Gp|G5pVor}PfQq#$l91^4y z+melwm3jg>R%56fcAoIVQQ~r}>_YCG`YSo4F)lVW(x863|55G)=RftMih>1R(P zQf9)u1!}laV*$(w!lF=+y z_r1Y>Msw-j&ztllj{R%TVrOu-hJtnq{q{ZB9ao3Ubl$Qtl>wdyYCxX|A>KEvKz>w-Y6@e(!N zs|G<-zD2mEvIO6hW0o7S+)Am5ax6oo6_VO?Q7lAA>&1zv{j4F9iHs$n!Tm$rHuRA z6>2k4;67%ZQAnY3BWJ1!LFB}9jNsB-3t~@|fztRx{$|Npe4U5-U}hn+#>+sVJqJ)m*Mci%=oNeg%*Qi-hf8k!De{nKWlkD*?9`hTFPwmV6GE?iXrt!B@~#r zY-xI~SsOqXpC7)~oDi&&p+Y)1jt4=jm|gusq<$`bKI5l&>Y?s@)T5T$Q8uf?Zi0{U z-WeMhre3<97ITj9u_C#T+O{*>EG#k#*eb;nQ&eVvuv; ze4cGt%nZVxdaP~-QcsL#(X(TF??k{gu!g(&%km}KUx~3#2s3ee7#5440|FRW>VhE= z%4W5UUj))JJ~b|e5gUwM-uU-fY-@1`%Nr`}Q*-?Birez4c$!tl%J`IfN@i3;DkyJk z1k`zn9=UOD5}PmO9NhHyj8u1k!?I=HjSh(vknB}>r-Sl^!X3HdxAlMS? zk43^*pM{=p_zrZPYcV&vF+HlCGL_T@^*O*8z{&IZjN21FcnmUnOd`vw{!8IcN<^2l z+;UjT6ft zmV4@uR6z$}9a$80;J=ac1=mhp_ly?c1I`H_zv7^rJoQ6|Oi6?gCRMAd55A;JRGlKD zO--G(@5r(jdTM`JIGOtO7G@Y==!Tg~jC9O7JutfjhN~v#bI;v}4kt0+f)F}a56qmL z(=oexVCHb*$Z8=1xVP`RJ0;Jz=|BuQ0n~nKZE!eB$K1aMX1BoDgHQNhlb0m(e6NMs zEtvW8fEB_&=`~MzOL|)F9%-@PIkMQ(SU=U9zYCJbi@1H(-+?_!!9g({^S~aMx!`nU zu}2Z}kdDw(Nz5-Hgw6}h>3OD1HXXB9Fhh(=MW@KpHB0K&E?Wj+W#TmgJts?HNKPFs z!5u*LD{jPQw*9$FyZkK%o$x?@=6V-(?pW`04RSX>lm&#NhBFxYLB+LzeV&7~+ZKE@ePNkcg+AWbaOK` z!aesf;ePco;a>ZgaBuVmw`A#}==H%$yLjv>e+68Z1&L8~wdkJeAB`Dv+2A2#Coft)YfmGmNh$qMY zXv}$`i6d^kc=WK>Py6Qi0}97n_E_FG&mTSP$-%At?i8Ye=y zx32l?!tg^?!{58+*|k$||Na|)yXL!tR{eF+p?9vazlWau&wVR`$FF%j(DC`t&G^kV z^Y5?!b6jZqIgJ#J~=rT3&3Yx(RX}1Jn2E54c*>x31}Ev2a&RHSxOBeZ zY5paPJ|T}`KcV+0vEzox5BKA3qNmx`&z`THLRq9eQ_+Yhn*u9xN>LyY&5F`E8aj+BV{l}RTw zSPD$H@INE&3C6X;Uz+E%#T|2LHu&OO6dd9P-AZ!+F8xuQO-taCO+z$pa z7bnedONSi&7v=(m0;?FpEk(#Wx8w!xdSM@fG;a6W_y$ur~O#4#rFHaoWi-9Hn}WT(IKfNs9T@WFS9`26s3g#_ba@LepvKq4%d@Z}|Z1@LL6 z)E-6bQN5bgPm!_W>L%T#t}jrhScvYk0IoaS z6;Hx)j@X2sz(_C~o=%6PvNnWuWU+}zb|XhWwp7pCgbwooN5)F7$1N$sK=`tR5Laq` z*uah~>D2Ij=A!u@=!G?2j9GlZ5eCcYlvNUIKN+j)jo}NDvDnGz2$LR*V|+5!{%se1 zGa0LyQQ!!Z9*cQP#=5`um6TX_GYTAG(qm~>%P!ZA&wmL-gWe^MdwX<*NspzOFFV$i zBOXmj>!%V&4+k34@2wC6^{hkw-XkOjq^=!da8+^12(-m!1W60Zry)IHhJzEf^)%4L zaFhUQXXBwkmSqS^;-SI#ZZI&&Qk{T7>ZLSX!oejOt0FDdhclHuS!_43JF?ghiDt^S z-M>lF;WP^~nM%}i%IcJJW;#2jS;&Qmam~VoYjE;p)zW1P7f06CmtQlb{F-Z$Y)*N3 zX?bZ9XnpxLB|Sfa^#Ywqem=UG;&EYeChC!!$&V1y=d|1 z5rvBurG%G`C>~Y1xDcO~6{UnP8?mHt)QF|aMlBvbeBr_*{IcSuqZckM9bUX-)Uw5? z;iHO%k1Sj?ytri4@TJQvHf{xmqq-IASFOD%EnpdLb4?9cwrcIdw1DCb#i`#%Y#5RH zI()-$VB@aO z-97&A=q4Y=1O88Hp|pcisD+a1GVvypLDbihu;EC0z41D{FJY+#BY=2h!WYB9cLxVQ zxJ>vq;M>eX5uZ0plt^(V`@-F9S&hsW-@tKt_972)vC)T@L)yn%| z>)nf}0v~&-(5&jqp9N?PiOHQMbpW%e)5Yha;LZaNXzEgH0;`} zc1-$gC0S>4Q#XiBhdec7ooZs?OkYsl&N&LY$XH0aRhV0{xeC{dl>4ytz%8MYupBPH zGSjp5m%ya;o=doaU*7gcb~(Vp(5%VzsA(?c_JGHzzyek|`vOx5_9d{$1dma{%_|s8 zz{PtF!9vgGMqpC!a$73@Em*s!MF^Y=0ANXHf3PsToX`(Ga(98lv%5G4Z!m0ezh`%e zukEI=2ivd0}CY|9-2TqRrQf(><)(+oyQ z^c&m(L*5I!rUY>eek`~*)>`bTAgj#a5XPlTA4}btJOQ?kP!FyewLFL$GuFW$2vZwl z!#pI6lNj0M)u;sD?4tKt-fX-~RCRbj0_GGdu=!>vcYnu$maZEIZX3GQKgRL&bXdn| z2zo0+e{c8|T7x%n___JB-x)@g1-auBeR#pOb@R35PY!}?$v!+c3CH6p*1`1fI%L3y z_+D5bu=MV+>#ee9=-ufU?iD%@;Ci2okvRg=*@Nm(_%$-CWd87msXU_LNsg;jFE$*gnVD(68#>MD6;b&!A%U z83T@#bTGLog*X>}k|WOw6=WhuuO`Ppf*e`YGLj>Y0QfyyX<|*2V|m*jv&)4fk=rRy zgwGwQrh^;@q7-5FWoHhel&R@%gu%xf+%#c^g)k40Fkynlv-w`+49(*c;w&R^=JUEV zKgcr|jqU@9mUZ&f0rymKWGO+QfqWkcH2;^|zR(36LZd+?G@7Srv;Z`!{*>RD|CeoF zBM4G1B)PtvKkvr|C?NmW+rBE{p#QCNLA^Po)va^8gmlZI+t}q0RE)}<;%PZELArTD zx;8s)lWq`6^wqYANk4SY{-y1|6Ep4RvN^!-Do5gzWCvz1gBUV!(lHdXDi8JULS2VA`=|Fi*k9Ht-oQ z%9CGRNI=UyPJ>T>kxt3`%H*i;o8bnDrckN0_v4AADCx*i#7~ zUJcR}ooz7sa`-a|6Z9;;Sm3eH{6E!BX}5Cmvx%$gll?~s6JJinj09_$?u?hRz~5Rg zQpXHE6dpIvt_1Crgn?X(6~tNIX(QFhsBi+b~6igkitdA*sTI z!GKF|FKwXWL4;$gb;YVBbvG|wTvvbnBHPZT{R)i~u*Tr8*F>>1n|Q;~`I|)okqlb7 zcH#tfS&mlxUH6-ev`Ur}0E zl*)rA>_cSW%tsfFwm5lm=4T3Lel{xp8WfwZx82!hhyIp$X4swmK{q(rolP--%=lCB zyTl%4EQFajts4Qi*@7hj_Qt955DAa)eKQ3v6Ta^O=Eo^;z2Un9j1Pwcj6oFY!DYhN3Ms@ezcbpHd;Pl#!Z&uq%C7R zw7uRpb|7Gxl~8wZEjYVc?r4z{&#VZo#b5Lc7ReAV;8*Bry%6DAjUUMbR2Nv;fEuAK z2f7{8$_RP1ECdD{F3p~AH_GiJ~1nuRmB*p34?iVai8KWYCF$n&B{5mX>t8l@=nf?>zB zVgSZheG$w1lJd}gDL!BtngCe{UM`^SAhm!MEGE}k9y@@8`@mI*HVAmOzkx%{v z2z}64SZA)wT~PGQd`*szu)jklQrwQTXr>XD$M_&70i{9-g5i@w&#F5}%xH&6u#ci9 z!BR%JcNBMUX#t9W1xUHKn}d@eSp*LU1SyKaIfcVqwrKY0(7r~|zIKGk0K~t{FCBRv z(sY5`e_WzkSSASWe#}xq5VH>r9%!5qZ($x$pI+UDJY1Uvv4Z*Ww>;B03{eB|$Xx;Gy-hD32U_W~38=^7s4nlY^sCwu?(GW!`5W3nROLXB z3j(6p&!;msmZdqwjG;uZODcEJp|aE$*>mF)0#&F4o^-}#*2rCCjf!)mu*vM!vmthX z%?PB6!sk|^Vptj5-zD|MrB=Ua6P&!RU#@;E1lN*EaCyBGTtT~eli!>`S`$Jm5JHPv zgf@eO29qp8sP@ol(`rGxY9XQFzQb;WRv;9_B>`t#`(!dXTvAY=hH|34>FVN z%=XEiEjw7y+rErvsI9>p4XQ0HWM~UJ+D&Jw+nA=MO1Lk2sBV4?wrp{Dp7w;G9k%BP zz$iQNv{Ex8_H-Bmq(G<3Iw!tE#yd~*F94+~-Rd^!zO^9BgB0YAH)d4fx+{`o3G!5? zBvlY+sBL{eHCybf;Cjz#Fb_)$Hg98`!$=n8ovvQBWgiPP<;zr`f|=K^0D;H~@ezkZ zK%0=EH7-yvB}5|2-B#2^3$r&~f>tMu7S~o)&z^yyuH4ZGBh9!7(AU(y3Hcl!I#z!a z0DcZw9Nm0hLaJ0E@N$&FhlcOrQ!(XZAVF#pz@RcttH7qRNYN1H+3o-tsXbC$F??F7 z4w&+~AhiG5Vf*SJ*_NtAf(BP#+?vR?q=!NH*>o81$TQWRRP-gt%t=1z zAS42q|LMWlet%_b-z*$RLY;)(W~n^egKUe6p!?eSQ0{QGUyHsc9_tTsVQ|5U4g{xl z*e-#uuhH~p7s9{J;A*ou$QP;#`|ww7W{ap+b|0j2of6|vVL)v{NT`(^s&?aS%j^yF z8J(zh5<0Y#-*89gF6wHiy;5B}+37&FM?H78Ii3qWe-rLA#=WjiHb@+wQlmD07Xm~y zw)#FB5=1czf2eSbRmZMAfSnRt9v>q!_9Ks===p7cnI|yKLFOQ-Rx!Si2@GeXCxW@m zj?if6;ow%lsj2Su`RXMQbs+8>1|;i1dngdGPHjYTy;C96bh1b;o^M(bFOw%|X@%T_=@i3vhkr zbZ6B{14fNu+o~b~L6m6M235Y!ffVoslgSj%9+ziNmE7R$*#o+{Q_75>fVn-m9Z?WE z7@=$hggW&=f_}Zh(H#61QBEnO1?lC0*~Hg7gY004d@tYJw_>C~0WpH0SW^%LqfLLs zf`V(v2nb;omTTLCn-Go*;hZ~>D}N-X<*+&!fm+he_c3&=g9cqc{0&SG{R)8O>KN)rmw&+h(0g8cm;J*>tt(C8ZYA1FSP)5Yg_w}LtN z56Qs-gqG*G=R>*C(IIJqik8HEn^Z^J8>!Xam8shKp+~i|%9#KL4wRfjs#G~Uh_3Qn zB(q8v`G6F7PNKl4oG?>Cu}U~4S3$u&fW9^(erJ%w;>?<=t~+(Nn*w6PNQaD+VB#f7 z7J@Vxs{lQ${EVZ|;6)_`6kPVsE_X%OaS9{PM9h6ouvCt-`D!;f`q47Txk z{B#yN?mVF9ap6MG_U-=!>g^i#Ar??G&sZDG5AClrbGP{sKIuYp^}7@BUmB^fj)CPY%aAxS#J=J72+f46%JN z$U5Tgi3&QOYn(HxYzvXRAsuGI-?xT9zOBq+>NQ*m7MfXT^cz(w?C$rNrPU^?3_CkNZ630<7cM?;TGrn~bzMGSS@f}=znALd*p=WXd zLeNfTbs<9NnOuwzOc`c%i8+oY)e+7aWCsspn3K!Q>heCD=p9$Fz`ViRE$wUDFG50; zdgvW7R&0*37SA&Le8#4P?+N(yP8V5(Abz;^7g-{AnPXf7pHF;v7!+aA*@n`>YT&@QQIv1_F7TV%SEleI(_ zKlibeQjFJur(_zP94B31w;xhEmWOVx{sUgLd;PHEq~|%)&6#9~=>EFH^;Qz|^*ZpB zcCfh4r(0O$!iJ%p=M6gWlyP;VR*;2unbu=mmJ zPlR-D_e}d$sr`a<>&T*rn{7YxGxuXyuuDqjj_y?M+vG?=`uldtnhTPc(NN-e-=;1_ zKRZzgNu}O10hvw-`UXxiR<>ohspD$uuvwOPrvYZmQrwcI+%t!o)R7V6EF*3IhFk{pz)ABg=U+-P#+p-lTesGXCEA_Z96gNd^}nKY1kTbX-AC>1 z4aX*_hUVU$TlV(u1ZASF#Pznf_qRk-SwI=~_5!+PEg-|_ZEw$muXlBW%d{7AAK=7{ zE8;KA=>kZ%4h+hYoucg3c!uOwm*^>g-8$RZz&4Phf zTqb<`0eAQ#@T~%dR{#^X<}fTUGM4vqfZ1lj+4c9S?7sEEl{QX7u5 zLU^J)IH$z1T@6{;1v#S=V#EVR7tmk@cwkJ{OG0|E^letc(9@Y6l|iPi30tbm2dxg$Gd^ytU7d)a?|+RfS+TYbN~xhqEt%n?ic>5l^q2X%4@io`16^(0EuT3S@ zb`WXpP&c^V=Ie_9H&Ius9W~>8vleh0Em)%NZ9bfWa1$^urod&I4{7h{uPJc7;adTG zCjqmFofD4Wneg2Rn9UYkru_%42PMPmR2YO3&vQIAvRJCv0 zSZZ5&n;5E*vuGe*Tls zVz#%(7*2z9r!qm3I*9KpcSXOO#LQ-*vnR-#aDn+!9c29XCrCCq2b1cPZGTLrm2ctI z6J*`8Wvim=muEW4dHqkTOwDf zFN~~Mi`&PRu3m>5-7VJAp3P+PN&`!o!5B{7a&+(amS>o&MwHm+Ovzggl(}jb|MO!z`r=uF0sE)%{*_*Mg$Jt=UR@U;Qv`4qU`%KIhYJ8Ho& zUAj#8s2zGMesr1g_cFe12h1|i03EA46TW7^+-bqt_&)u)blr;ektL_dt5*7|YoGin ziWcgK3{{)C_|m)c9h_^&ZV&HINDNHpr`UsAK=3x5d(Ck|;I!k5moui_tMlhhy-bEc~F zrCwK;a`0v2#W)MAFN2a(F@F1?3vRsIyaRYb`u3%xz|Kmr7LlYXycrz9=xlSCk zAbvjMdwA-G`$fVBkJx76U%N&wfIs6RQV)lV36B}^Q&T3t#51Doy1(A5u?_-WB&LHM0P~x^p31^CL}SJ zTbMuo0x?yZH2|?4S$2>4O7k7)EOu?!VgfBwNtH0UB^K$Q+RZX?^BF#hvK0_L+RaJ}K%4kG+KVEU%4GX-CY{V7&0 z`{f`DhVOJ@%`?T$5X0CDh63)A6nwp~ZLxw2^Dm`mk*|JC%Q z-QSC&`d3kmYe78QI zTlDX`Po59R^9S;LSe{SG^AUNnoy}c5Mr7{#sXX_|^AMi1&0U2+EtvI+3vw~&^!peI zmND9I!Qa#H^BKRwlST9yuj0vRiK|3dG?gbO5nhUA%N~!@%S`hig9fy^y@c{Bk3sa+ zx?u$5sL~OwqAp(tmr{K>qtH4}otNfiyfu230qq2a1I@jyFo0TheGD}s> zQjgq+(CFaUKeMB`u`Wk+h}oED&MxSj96LEP+CTQs3DG{WuCb9vRZeW5-*lN(PIH4x zY(1=H+By3Cnl1)s2s@ntvi3GB^UTVESEUIgpzhTLCFYuPb4`W0CTy;mWqyAvBAIKJ zm}{1sYgU<+unSadR!%W1t2!!q^MPSj&g-bWj;%Mpou^06LzpF5fK^+(7#z5@%MnVz zN(Jp^iC=xSeM)eSy{Id8qW?`xJi9j$(z4m1nI2wVpk{-Wn2B3t&>FsH0HN3QU@sJI zF>%JavZ7;-F(z0rKs*cIf_Cfn2V6OmT;uanSDKY2MZv7>G%7IKx4H`Zwu4xDxU6i4 zIH!X|cR7AJa`^5t@y*1Oh4LBX#R??sZankFcQ2loijRHs67jK7^TdaT!5N0mHZXB9 z{K*Qs>L6Yl`d)Pyf1u6ME9Y*phhu!G43uyu3#`UMPK`K;1&Pf>6d^1HJuB;DqUXkY z61}%~^d;%&Q`yW>!e&OVP$FBQ&+X&#!j>lZQP?9Dm@z(ZeZSM><+n#VR|;PWRv={vVpGuBRY@UlN>%bR7<&@v zhcNaQ3k&&&b7G`mV)Sx|6~O6ZQ-eGoJ3~%6%&?%{%GYp!kVbsQwRk26$aQ$5 zvl;%e@P7!m$VqRpMEF1E7T-c9I5u^aoUGBa19QdEnvPoz9B8yfQ}HB1SXt>IVLL!z zQh6WZOXo*2?c{SfLr5ES#zCy z;mD$0cRtI7;PkXIZB%d|X1Vgt-+=0-kB*}f9r@678?ao6B`vIO`svHx(5p8>@8tuI zFuHYqDeruA&!Og3IriIW_B5QrC4?i3BO%LkXyTEtCZS(P2%TFni>*`~NT3`-VrlEC z#W*^Y9s=T6lpcbP!$nw1tU`TuE*Vma;fr;h5;96(dZ9y7DT)iA^qS9f;l+4B(z&Mo zK_$!eHysGO#ocSngD>frGhKLLW3G5<1Oym~`n5dX9+(I9z^pI4NR=%N78nj@L^I>3 zkDp9pKHtJTxCiFbdte?c{C+BCPP>jQj#H$W@4onDV6zY!S6Uul56oN_r`Lv0Fi$}Y zEg={Oxj|%UMdIwJ&F1&GH8{ck*WUp4pV9_7k*Q?@OINS0zqt-K3RqaVk5<3-=2R(x zPR{yZfh}CLwm#AmNP>CbblJk_s?_f|=~}-UvJKn*?6SgCmu9Dxk`DW@tCYn`(k>Ux z&S1Ax=W6-F^>wR})CvTO48@k8Sb~u>DM&)DvRv1}6~haMr(Oc`(bA8?l#?x9k$zl{ zj*f09t~cq&oqC|KAn>Ob>Bj~H@9PHFoAiUHT1qgAHE{ri|n50?qwYJ9sGFn3yTtjbLFcK|TI{0Mw=5&w0-lydTbBS~b! zHx)4REjT-WpHyn_N$s^Rj?}{(^{ELBVt;niRHZ+5i*HFSwn)Ys_O2YRM5~c)x$&?G zAje&KO(ZV2o0_X?17-~s)2q$#&;-w$U1LtoJH{$fwRtmZv~SBV@NSMTQMVPKLgITk z$Ma-MT-bdWJ&4Z_V^_}0H4$zn#=b|$hz`(^u`D$mYLp5+8o<|gzpYM(DjaongB`bS zLI@oSjVDb2A+)fguBGNm4IL^g=hsmW8Iy{myEQ}Pe0Bh(8+%E59(Sf+eK zmxWG`oUOB8KpayI^RrOhMUDsKSP;w!P=`1eYtN=4b};%=92KSwfq?7}PAw~swa<#} z*E(jr&yaRqU^YPRLEPd;gS6~haBZYw)00#z%!;0VpoPtqwQbAUc;DLcB3`!LMjLxu z<6KlNQ(p?;WtsU!R?;%Hg>&#SQ*Ml;%?5Y-WQ21u;xn**mZgi&_yT=;^|)ILTx6D&dWbHUZi$PUN*QU zh5o5_GCS)%YNor+tV$%UX2N_+@)aP)IzHgCr3SEx0Y8l{T*pJ*%T>&UB-nHT6(jmE zEDA|QAgDmam<^g?sfA*vuW@YraVAR*@V>OZvf3r4SB|S{=SpJ+`)@!^^($vn70kro z@HvgIlxQTCu?`#$Z|G3ty`k|4r$wTBkhD$CQFrJ^%nFrAJ+aTgXC-bK8}hUcMOafi z(+3#^RY*-J2AvhCW1a{95_$*uD^^G99jdMZ=2OH}5X$6fRSIKGb96y z%m5<<9qXW@rh;uCQIjSu69`E_gg_v{0*O2g$g40x&=8=LL=Kxly;WOVO50o8+S*&~ zU&})*Bt!{leIQk_wDn!VXp7ZKP$d8F+xwiEGszqtm)m>yFXzn8K5MW2TKl#3+G|15 z;BfswD3d*?;_F2lOAC9f1@iH=ALm!*to|xu`J&l&%*;Sx^9l&+u%#nQ9z(+m`uYQE~BIJi(SgXL9DZq4NB!0?)?d zRMvuq5q}bqg{Yn=bRkcq8E7zvu!;VPYF(w8 zkDwZ02ijewPw^_XEjPDjztlO}B_5O1C`cFE@o4$S>ibfSP$9-;w?5GeEkHN7ipL~* zu5yjfKP4WMKXV=)rNWbzaJ0y36%?qq#AFjiyI?O zhB&5gV@~9i)Hb;cpd2Qg4!fvIi8q8tI^=g{KRSBnT6~V)#Ti>K4(Q{9(eJK>KYAxp zL-<;}^?JWvK@OlkJ}dfNuAvZ%@4LABUe`vEsK`?Ry*^Z}SAgx8tB)_JY8?!`>``fw zg~cqZs{@z8=fk6ETwKtl;0qmNr1L5*u3;bximwb79=x*ED#9K)Ch(i+)7cm8()14e zXwP&xp|$r=^V;Mfc!17HVz2zyV5Af~!Kuv}F?q!o-z>BCFoDu#|3p|fz}BK5vGr(x>E45Rh|ztU^)D@o0!I%{8B(;E^e zd9c1);H_$9!er+7q;f{Z(jg2NKXfJ|CkuWXMvk!#nJwY9e?)1|4|M-%Qtz#{PWPzk`q%vdMi4U+N zaSPBf_JLDzXn9J5P^G699_=t+(wUTS%nXRphSN+e7Q$&!xvn|16FRWcs$#CNkFlzI zt^5l{0~6se!$Wek{#NbG#bHwet&-xM8^*4G;gV&`m(HAR?(QKaVe%3XU&%Gh?{bk=ic|2u zsfPIGEn0aeRjZc!mAQ*&FPSqJAG=;jjo+}f!WmK$%jYhfJ6j1Oo6-}KeIiA*6HSV$ z1Y%)JrJd0(fwN8N3*%C(QCSk3%-X#9v**uU95$Z#ALi= zyo#v^FEU`@mCkN&ycux6J_EkHfMM%d;v0=#O{rx%yZmv_Sq&JWW`7B1m%sY}^D_%v zvho%qtw#X!F9VJp(+*$HbS2esy8QhZA1?=7D;_$Q!w%nbfcc9BE?NE#BK~`Td4i)n z-0AQ=1(-it;F96H69xP$VCHh%J_EibfLUXKONQ@uWJm{$xDws0(tUHyFm7$-+uIMxgCohxtVTs7j(R{FTlk2%w7=Ggkn$rjsYTn*yJ&o|^K ztfrJ;mFK1bmFD{V@=C*micb_g>Zl9)H8xP8#- z=K)h7>Tcve@CLcz4n&@I<4W>4@E@?_Y4442uetTCbW_RfP~ps?9;5*i9oQ#Msx0rE z!q`K_4Nwm2r9#&Tlph+}a{P6>s;X&i#w9b#L4zH!hjyXNC|CZ>XaKbnWM+qoQT~=U z97x+K)*Zpu2aez2qJg3vAK)J`#xIVEHiWsko81erp$`n%bD#sBOrg|{l})62%Tn&c zbBI6#+b4TJawZi(Vx!BI3bZigSaecC=c90L0Fn$Amx?S`EWm$$qu|+{Xt8Ut>&xNh z9@5IGP-6Hgu5~}J_PCy{nT{_)V``71d8s7VCr#VnxAtX}D>Lf!JaC*EH?b!xbo`Zk zqxFTIuxaA2{Tadn$SybNxl!kTF~5!uG16U_zmItYEO_|@Sa#^2);0LKeg5Hpn@QY2XI95qU*+hApz|euj8Y}gS3J6&fqUBA;#7Sjp7Z`ae z6Cw`*gkFlrC$$L0)8xQP=QQ*#e+m8=u_-e;pfZ2Udyc4cL>a0B=9T>7ZYDBu(iD`+ zZ#Ii;lo&NuAltzqFN68utw0^SuLds-9i(%`m)Si$Tgy^BTQeN5IR13t^Yw!YBcG=$BePq1_;b$4VN*pUF zs{B$(YRlUw#KkOxtSqAtmDIMU3Q_FN{!q~tD8sXfT}iykA~4U5RF9k`avlTe(7ffj1b1b>OXIQXDOwtv4`Uz%dRLBI7TD-ZxZBM)ZzU$5B)u za7{{a9AR5Hj>wRJXKPOh6ZC9FA?72VS7J($SYV3FalrAk=aC|))jP;BuOQms)z+eI zF$T1Bc-N-^nZFp?XTu;q44UEvkYUgxFDkH&JX@>KvX!!BZ|Y?GPL=OV>AfkH?=Q(v z>8*y{ubPyouN=`NSd|Kv@0(JXfg;CWP$PV0;`IpCnj_EAdoN`jfdfm#3}bJMsGBM1^^I(W)bi0G@1_f=L0INDWyS9CgF7Vj&n>?yyZqAF34HJy%j z$NP@YqXkQlY`}4xrFHz%v(@W)B#gYh;5fi~cD!uV)c~WeLaZz5Qd4HHmboL%uEPB1 z+5VuAp`MMO(hRe-MwZ!{1%ir`Dwi{yIGtKQ*+WUlB-IR(YLKKlv_dRby%cJh#a#xe zR+L3rQYS{IoHT|xNvAtdN!pNoEpMc?yx9|}2Y3`PE*OlHDAX1AL;nPcMn^l*syv-g zI@)uEdxKcnAu>H%2YR+vryyRAC_U-fI?S_mwC33BcoDxTqf1biLmjQCP}L!Zt|-UI073`aYE=2?l){qH#5c%_YpCNz zkWEr-2a!}p@eL+ABCGu^>AZOe)NZ45IFxowB%2l8=#p7M8CyzV&z?F2C-|2K>W zit^Wbkzq-03a)(?Ag&Sp54>gI9vs8%NxlT^ka%MfT>mZRAeVxqk4;a#1u`@9Jl?<@ zXAT-ff$#v}t?V#2!V=kGcFe&a1Cl9hzbb^W$V_VmLg*B8(2BVaLK88on?&82dIteX zd?){U6*6jK<`6+gre302M-C8)m=z1pidjiaaS|iGM<=)bFpl|qL<^@>09y0R!_P#_ z%J`HObAJiL0hpLQzvyM5!$%Q9cRtGe*ymlqvFaB8>Uf_2An{UFMb{P_fG>%8R;v46 zN4UjucJ-Vkw=Gs<1hf;ZTsm{{oa$xsZ>b4a&z*A%*pTL5B8=t$~+j=T0Z~w zxe0+u3~AL2Uok8J1_8sn2bgO7ESZX>kmQ@8mM;dqO!5=2vzpjC6F)H<48=GJroQ8~qAWq?)oaov#_RjqzR=FqJ;CnR4wsP|!@+lK>j{% zGcsUfhZ*-o-om@Qf;(lbp$qc*dm_&x1i(XOlq~T(=2=wc3~3qi&-`P{Qo*Z&=*4|E z1FE7dS^|yJ&>|jnucy@=3Il~wvH&e6WI0}e2*{Abq4FDe4?>` zM@}M7NjBme_)gIYub>dp9;eiD9YjQL-H&Bq?_)lgw~`!{CoHl1vnV3U75yX_VqoE> z;L1%~iEKpSKzTwC2rJ3Ls?{ZW=ff5;1gcn7*nZ@BJ>UKv_7=4H4CV>UL{OSb%5kXz zE|2Wtq8Y}ldI^WzSwGSuzUdVoaaUDNu8>D2jR+6z>Nhg7K*A?+brtPy8Dp10^MO|>0K0A5eu)?#mR=F6nkpA z!N8=HF}I~Y5C-`Ga@jAokYJ)tX`ne*c$hcVfG2VU;Zx9T6sqaRD$IY;6QSsqxFJW} zS}^43kUjZFxNTpSCL8#OXd?AYp<;}j=pC-gsPCRhT=$DnSyF4IFTbU>Run7h$OIyC zb!8^7Tk@GgJd*X4-&U6ud9G9Pn!)uWyCh}Of|My}J|%9T;(;nkZp`nfKMdOU0xA>r z534r?g_KL8wVO<0uKP7|pC!EbSm1bB_cH&ZvK-G1c^bOR^-)xFaXOgWO2|`(=ZMy`bSrlZKfY(l9KN83K!nhD-80>PW+x zs8zL-GH5sx4eP7>DYGcbp+X%wWF~5F5(5FAD>g~$73H~QlcJ+sP|krXW0X!p$MB8T zzp6N=_zdR8GhoM-=hmgSjgq5N-l!b<6|Ku%r=vVaFE2pkP+q#{+kO!D3@8@^qSieq zy`rCG36#Y7iBnj*Hi(~N2EP2#z*naDp&U#`7l<2S9I4e9gkaeL@>y)P&c5ib=rhW4U?`l879Hz~I=>fbb4lg~Dw*_!mJGDJWtD^F zLCT0aremLkq zOFRpHpyTfe4 zA`}(Q1tAQKo&EGC_S!bY0p&{C5ECIdhzIsqFmRV4Qn=WXJaSW!&w1;+Ntv2 z|0QCnn4tXV2^cg>IQ6L zZP@M9NsDa3H`gC}JC6BwgwQE1AXdzFJN54X+PZ@z-NyEgvzCOzOBNZM$0Yke09P+v zwq!PS!YkFS)({Gj%v}jv&9mhlAPA7i|6$;H-n{tTp4q^FZK)w~LN)A^BFVKXUq92X z@A~VqE&4tJ^2SRsw#=2XE|TlV^Kn|Rx+GF0EAc(l1ump{M_M@rL~$LS?OovPb{T&M z+$jT=^pI?qmWvNAHRKSzbawbc7>mpB(AnYRqMSCBS6JZe@T~>R-4?iH`2!nD`#xYO zfkDS~?eM({nD;Dj$?%cw{SjckWbFJ-hc6Q_xfZx&_%;LINWf51gU*4+E`KKh<37VK z(t!*O0L&m`cgV5A4&OC^`MLpT*B)VfC;`k)NPf_rE`P59=BNQ@hwlVFd<>WmE>QSb z-FEpKj)7n#2Lm`ed~NtP4lw;a5=@SbcKEIW%=HGG9lrlSg%twkAQ^UWERG$%La^s1 zl0^q+hi?MDO#{rY47k&^$1cD;e+GPi2fjmq*-N$`-09lm9l(5Iz}e;RPJB28m_}nF zJY9P{3z)+OoE^TeBTw%F<}$JY;Rt6}e?tLNV1Z-*I9D#lIp4UF!i481)FX-mm11Q^ zS!bmiOFwLA2O>nca94;6Zu-4to&9)}ldc!T=A=^}@2hTQZE*BePOWIz`O>wC<>FA| z;VELVKaMFAU#yslaopo+Oha{Ykz6UBm0P%j?>X9cFwr5;O}M<{;CsF6Ga_HOxF7Ru zJV*>rw;ZADjQjYZ=)$LCS4O!1AMb5Bf`jm89LJ7_=3*brL5}z8#lG5XCOZ|SE02|~ zA|O)1qcKb8lA5BOqQ71NSt2JQdA1e>2YkH~DZ+;3c<Sut z`9?YRBo)f|AHk+9wEcNRQPXtczB}r?yHI!G#?rW^ah_cbeYu_y?t4sz0@nXmBXS&V zwnWC4LOTdPSc9k#{}hK{<`&n2#EIHLjfYoU=-HKCww)!AIYmB8Zm4bVZv27sj&h1} zcy=etDT;GJ8B!HS<$(@JCN+mIKhRMEsyq?t?1P&(25ELBs0x_O%@HqPdxrfCq`I1> zN1f|CwRV_*kVWjJint+GM3|(6n$O%xqRq@HwkS}=Azm?9bTYWDSgvv*E;JW8R26bt z%(n?X=3Lc1=RW0BC0&kxP)QqTGNV!$<}n~p)0yAqY5XsIw6>`z_L3Cp{nB0si4AoZ zBjRgW?8GiQJ|Ox+XG>Qi9!MfCArWW8?uU16d)E3vU5GacGMgTeh%At|gStR#uN3!u zg4|~}=f7GXh>j0p^NaZ3XIKau+x*tL582>)eXd?#Kp%$%R)$Z$<5b1Toz7J8!Zszd zNy!n4(HR1^Mt;ZpOkfX`;s;$?Ovw-NRdzn;b_ZdOBVq24 zgo(Z*vETx(w^*0#Q*qGV)eBwHQ^Dc8)Kqu9E#!-jy7I+_Lt4+6lZ>3%QY0ysfx! zB3Y*zj6rr_wiRj+d=MzD7ZJ9Q=vyHkQ!TbLg#ST}9P7lW3|d1T?-LQ#YGjbaTdtzi zyuHMhBfIuHq%`3I<01c5RC9(b>0KoVZ0~I_A0(sCc^~pY*;81PEhud4tW6tz^j|8( zySmTu*AI4zw&O1%3z_X{2Ro5!rh+*@7!EZn(oLHA!c#vgI^$SNyK|H{c>GT-Z#f>(GGKt&w)TDlR!3{Zsa06X_9C?f;2Q#KKX(fsJCpIjQ8VS zp{%P-Z-Pe$vCe^Fd~Ts=`FiIXcAwl@v$$*#Opq>74nspwUF#G-kS%j~Mx0>Amlj6e zOxLT5^zjyg0oTvldLzDE7DmU^YPqOg>8jT!2wv~3Yv33 zs&=uQ@rJ{XnSkPnZZRQ4+^NV)Y$H{f`3WO_7`cny*^JKc91@(kueb}gi;y4G%)YUi|gRT+J&-t1elYgM(z z`_(EGE8d&9%%@A$Qe~lY;ivU&4o$F^n!%rS>_1{+25utDqT{GZq(V?w4un{T;o`U& z2-g{P;8z{}Ld!r1TtQ%Auew+IAgOr|yB2zcFQ3MdFtRWsYw~!P*R6UJzIk>#OBTg|K!omci1w}{c68h9!})tSz@n7J4=*-bA*cm$npSw1+sYZe;a@LYQwRv(cMA^U8uJ_b(ew)$Z1kS6j? zHH2Sy)@*_rxqA27H&fQTFCBF>isHu;M`uTG935XPJrs35gtZbD5^AmVWwns_WvtJm z=JHXx}07_gZt?s`x(nf*|vC+;Vy!-V}yFkz3>(0c4ucrx%% z#1M+>xhRr?`EJi9h{!;)Pu|y`f{rw_(wNAwG~ij2hH3x)BA|pwU748bYjSO=x;LX+}(bV7f@3RA$@&hWuybDL14Mfl}_W zcmyHtSIabAQ~uWefL3+$1Ng?^@yW}NrP7C&#yvatBIX{Y zME=j)7*aYiLu_F^aR3kK%L6*@GRT?|n^?H)W=!cXd+u${e-1U|tsRj6bhxKsYPkJc z(=*f>dTHLRA>%`Be~4bz9C6Sho>W`s)<=c%zaRz|a-p^3)Jl5te#3I&q!B{v`{9e; z5X89SkN$>BI(2M;!(`MvdMuV{ZRBIH0c0K<_t$<)ti7}ni7k4PRBSz;m{fPT!Fti~sS%?NYEkI&SBW3G+Dsj)Fq3Ig{{?55G;Jo{>``gjI=tC%Y1#(7N$6=BS?25lK0KO6Rtl>n)zDSS zv4C4NX@t+YV4*CZF8f6Gel?+i-t^LOdg*k%v`jC(SudTem(I~kr|P9OdTB_R7$h3S zU}Z+=Oud1V;kP~0;hjlSG2g%OOlPIck@aQeID_tRMqqM1{&nl$pJ(os;~IwUe9m-o z4P@*8@hmWzm<`sQai(KESvdO>9P$N-@5OhYSr*4^atqGq1cw7VG4FifvXA4KGZ8{} zJ|{RNV`A?6z~c|ZF<(oxa7y~pS{rA7g2SCU+j7aj`fQ71=2%B}KC+hF(z4S`K7RMR zam*DGFK3zn(zWK9i?75}Cp%e7a|1R#@AgG;%ySIP=Ob&$6*$N9`ZvC~AdZ;}RyrkX zN#7>E43{Y7$^j#>6#YT1IQ@}_P%6rW5{Bah>nHs`di^$@)_*DxocDIEAF@*uF)Qgy zE9QX`h6@Ms!XnilPKsmRZeSkR4Rb~}%mcgSd60zRkjOlb>zw#h95cGUbc4EK=1F#9 zo(FZqOo?ho%HR3MQ-AplUyWma6CrdLOU(3r&X;rnnG>{1iZ#SaQS8%+sbAbJ^-ClS z2Y9yor1YJ5n+UHqJeOzznK$sX%})qPY@Ns)AqwlK8U9^#lU=N zH_QPUi@n1D!Bss{)B^lVd)G^2N11aM!E(W@`Mek}EteU78N7VeqFGB8(pnf{D-_3yOg}H+6boJ*0Owayj@-@^5XNNBfORJEvys|6r6-aBWxdf9b+vjfy;MSZ09|n3&KTCYu0k`iA_+|p% zOJ|8MyPu|w!b4|Q-dU)>8v*l(+6A1Jo?ivbdj^~xzDI%YBf$KG(=;5nXLjxJ5nxg{ zF~iy6>x~b+0W*M;GaT2zcK9X%W|jeG;`{fX$Wo)t`JKp;blI&r^w7^L;fk7TZO)|Z zBYfBuxL@ar<7;>d@LZ3F;p|SWXUt;;qC}hUXi2NFw}3+9!Mw zo<(?W!E+-X=I3%eOe=(EBAyyN-@-E;&oDe8Jmc{YFXOGkvl7o-Jf(ODSB+;Do~3x^ z;33>>Jj@&Oz;xJO7-oI=jq6F4dt{eygkwB@%T4l)--$C>JZl>Nmwr%xj}+;UQPaWP zg0n|jx~pd|kcLBj#@qa?C45g!aX3<)jvhV8iAY&(00BgE_U+Mc@UX(P{u5`WU-m8E z@OAh6#C7?|-?m&h>AGl`U2)}AnP0v-=UUkE&imS^qS3`ArDMjH zPlm3FsW*LdHWWDDQZs+S@^I~n+g7f+J<`zFbmw|~!+(6|-uv$V?)M(}{(t`T!Jqy7 z7Z3gNSO4#^$A7nV+x8t#>}h@K>Ah|H_CNE|!9TwI%BzQ7`_r3mz5UL+e|zu9(f2?4 z=f|J?>(k>MCq83FQ&Uo%PKPs{c~42bjX}tGUuTcO!_xW{PE4Qqt^St{U+40Tyyqvs zZRvS=_M~GM&RTY$*MMNon^%0qtjnCAUB$x=W9q(RRG6e zRao*~R0VJ@iB|w;9Xba%Npx4@NyinFg;J)Xqnn22-l9$L6dV?RaND8GrB8%~N@yl^ zZwPtU7kaZljg~leIDy2obtN@LoN~MhUkcy3j#H4{9}~?PSo>DwR7#y|-6_@*4)mo8 zY8N8K^)u(=ngCi|UKNP6^)>DaeEgt*;nTLYJUgMA(MnnwiboL<*UogQS`SG?L*NGy z$x4h?O|96@k4N}2f@-=4P46DG&=M4RDln}z6&RR6nj{;}rfKqjrstD0Csz+?Qg(&w zgfuyutFM{(pX-A(Ig5Lw?>fBI*L?W6DoK-Tg5J`{wo_l>(I)XFovH+`1*E7@IOwLj zP!5l2=J43n&@Oo3v=r7uFAnKjUPMfN%b)S~+&LFTG7KO|Niltw{EE}B6-D|t^m>|j&C7%)^sC#18|tFQFwI9_mdNkgxP9FPy9K-Fz&%zZ2k z67A`VG78_3guZgRzVc>$>KuJ)jXrf@TWB&DY$zbU^^isBS_d~VA`5yFp6&&`0im{; zuq&vMiCjV7lwSbT`l$k!#oi^p$>nDNz*WKU4R%(zV95F<( z5X$k^52%PPbsA@wdLOE`29{5&NY$Y28h^DumAGfLLQd?Gc*=_IYy9e~Ou1SmJyRyk zxk(L=<7Co?1wlD>;Q0GA!v{^lx%28nwf%Rp1u=DXI_uM;{xt{QZpY8>S;L}fDaIw7 zK|URJj1-jemn@7ouQ-`m1>L2t1merPnz1rM|XMMi2g5<2QzcfW9=SmuBiqbM=~#zO-of z2!38!pf4@emyXky%5GdUM_*c_FI}kDELBSr(u%&lf$xXb^Syo}-;drcL++LS2loUe*5RgP_fWcyd%CjQh7wTTG$Ubb;c`P^bptnmzT^8BQ4b}g&K7qWD z)_htS8c+Ft9P@nz>8LP(Xk?Gjr5Ni#E?3OyO%!Kh?yB_MxdcGQY;^_=*>auE*{(@W z92~6lO`NJQ9#-pVda+9{c2klWf=A;yuStB@%W;ou3XXd*!{hCKBQ;xNeicP3L7AGF z)J~2WdR0iTD$rAR%UZqNrQhz>$9na#KH7a8U!<>^tQSs?wBYU53%ykMUYHS|y1ry& z6w)TeKHO=K<@7XjeMJ#7z+xMDVzGD1Az$XDEtON6KGFrF7V)f96t#_%Q<^?hs4A%<{KQM7Ikr?|FM&S_m^no}GmR?cZQReKtn?nt^=a+odoHH#pt&B%O# zuBtE9nrr>`$wrPx&e2EK=p(!2Shj&G>qxIYQnsm?V{=mel9dol-RkJ0a*AS`bB!zv zBkm03sF2igfjt9Hnsyu7n^O(UG{Q$_O`5hDzUk8UWB8^?--GadQ~Dl)kM*0T{TjZh z(ubEuMjsuNDaqdoyv?3*hF*Y~8S-MSwf%5uw5AkQQ7&~yx%J|r1t|-L*AQPh^yJIi zM{)p*1w#r!21K4x_Fke*>jAvOi`W0_0hzY-Q;+S{Qr4Gwp}+FuNPVtL-y+9E!y4?P zfYY~dWYo8C^%#8zF&&kiMunUqXmH(@Y4dVeR6Hr~aT(-zvmNn>Qpge@$cvA4E>S-G zqy5#0<I8!!@!Xsfr6VN=Z>H-1?N9c^({if>&=tF4 zPM5LR3(UmRx?y%nm|VQ+F3X+T9*4fd!0hUVnPW_1o?YEAb0OtO;ohBjUc74I=W)#W z2IgMfF!%0;xmP#LZVB@%yjia6zW)aLpjpBj4a{y}W}9J%GeWx8Jcp>nQrKB3;+~BL5>@qd+l{NwLvIb z)1g8j1k-|ITS7n}q-je?Hg47-h9zXU;?P?{(B(K6#zOM)fVnxAmX%ifGW7&A2X;0R zuK*<7a~s#Z886rOjdJxvxe{xPV`3s^I~$4S-sI_F(=ZpIxYGT?!0hXWnP&uvn3au0 zYhUI#>`0lZP-#0>eeFOT^J50)0o^c@F_?&XKsQ>=kT6^@vKNdv{yG>XW}f#Lm@|Mm zaZDK04Rb~}%oj-*PPpvDKfd^VES*fuhYidZNzA05Y_#cegvwZwezHL=Pa}dQ1k~b7 z3<0&Q2X+e#sAWN7NS69;!ekH60z_Gd3a8BTv%dx zD3lk<(?(E?r7F7qTjV_-tTVnU)GRjd#piD62YV zy<;H+VP-Dl*M;-LtBfjV+*lgt5>puynK@^U8Hsi<5`^7%_3up~d2R#dH+W3_F3l$Jq;nMxW0bZ3&}8J1%jJ*6a1FDc108hweqlP;Mg zkGWP-5O~{2^1NtvegiO+M5hB+B&9}gH}Tn>@UI2j-3BaCCzA-d6yfIVb0&Ob&g?%6 zdyWsn`OEfH5G;`_v^OI;W#l|5=e>DZi%YwL> zf~_n5?+?pg`%vz-rYwUvpna&=HwQsgt*j4og=)%)b9EUPM6cw1+Hg8hX7aGK9)CVu z*JVUDJe_&JluI+k6UAl3ng;v_)nJmn7eDvw5|Po>{wp3a1KEs6L%!j>l9TDMO9e@gHN#8m7<&Q(cm{q*&UwNOzr(7;u=qS>jxJcob#3|R#+L+k}&;Iq-e~)A4GJuY1iV`ua z?T&SsV5gMG#Qc!6AJ(QuE65`)Vx~xYB4)MSv0}EfHfCa;amD*!h?tnMvXPD=?TMJx zcE^fYSsUZYi!n{n8g^{dmIk!VFE-|`y2*1w9`oAaa{N}WGmYZcW?i4BAUTTnm81Au z=mF*$+Dc3;7fI>KE~8qqQG6BPj&y-bHj4iN^)?gKbqzPPaQv|w#c3C5i2=vzPBw~f z1FlsD4Dr!Pd=?pVhG7${WpR^gadzomjFub1)`PQ4m+Rzf0rMHRr*JH~9lk!;D4KGX zcKGhahfKgdskmfvrE7=pY~&q>AU~9Mv^qO{UkBWc2CQBF!a!7cmiV3p+~G6e`z`Rj z3z+*k`of)#4)y`&kO61r?_6iMbGD15?75xa^ak||xJnL91b+PV!I2{D9;J)oAVhJL zM*ILuZk{MYvE}wZV~Ee+x28v4vA=$R)O!DA2|=#9adJs!rE%EBDiPFHK~W-uzYCrE z^1v#8U;US?$Drd2$gv-wkMvt0!C)<)!fTi~0BYP{ssH8(yt=dtP+uKg=@um?kz;S9 z!?~unNQW23s-5+HC0?>8%{(b{1dtZWZ&{NnTJ$F3F_eOO%&-p_R$MTOy8aH;J&24- z{%+%b&!)Bb6kQp-TTFOIuYRK~onx}+k@2|6Mnq5?Sf(z_>Lneb1Qw8r14^f0%Ug~~ zh7!-pck~hnD?yXyCdQd)*uj`^L@$Am5VT@Q?Vtu8NJHq*CA$QN?`D1)6h^dI94UF| zGxVloz&EXR9IAl+5Y8JA68-saa!1Ap>d+~`nfI=D09^l7u`jzh3N;4p zm&@QbX%d!c*Zai2b#LO1AWR*lMfP<9s0=2xHZjrd1b~XqqM*yOkxUKYz@=2&<5ul_ zsfB)chMtDQHO}xcf(0b?T+~k!(|6(~a$S%7s)D+UaP|bTAsjo%Vx;kK+92J=&ic!F zn>pXVea%H6T%-$8Hwgy9%&_967!fs`{wyL3sEIqEEfxAC{GvR7%c;CZo5367xC0sV zG)zN5a1ApM=?tyD7z$qpMmj>P`!(*b>k~QAYfaC_mmpgASub=5Giz8G;6%jC8ZtsV zSK1U_AkLaw>u>q&$;~GHRn)MvuO5EjKdigMwaU zSzO%mwyUu-I^ACuz7!HltK&75m>pz=IgC=b>=@?_udQvQ|#&zbZLgZDMWOT z-jKJwfwx+3qEZJQ?iM)fZG>86hm035`z4GC@_KpwCE5FhCnv5#~(#V_28i6#u zNoGzJS3W#be093t!$lO!zMxXMEo??|t6#ApSFBo6Uhv;C4#S$<|^}4<) zN1xBKsS=^Y`oto9{g?dzWt31f5x=7~($UM9J-Ny=sS=jsVPJ<4l;Y7h%8C%17*KeF zE`MuZM=x+=Sn|g2flGzu(#VcyV}b4n#0=t(*aS@If=H<+e)yY#x<;8GIR1qy1bk& zHknu;!s9i88USQTwCPd&5A;}R+$=F7@j23iCYa1zAQi?J_tzNTH*JrlGm$xjCAs^V z67;g2NbziGE{$Lz!%}Q2GvllBX1@dt3z#?V-J@4Rxs4xnG6o&FMFx1qc#OMYh*!8p zg-ew9^^smMGQhl-r^Y@hKgM?QX|=Ji+u>7T@5jRa5etJyKPkJ?$x)vLm0VSV>a{T|6z+{K;HDA zFWg_;&vIcBI0ywGh57_cfqJ!1uMX(d8F^BgfEqm>0?dK8^h&>!(vV2?68TR6U)UOH z(nboaG)>y8VsX->PzF|wXzfvWb6ob}!CgN2=022P)xO=1#bj)4W~(UwJ{A*s0*S6W zi|G%jO78tq?)`lUn@%~|9Plcw2@K=pqg+=u3t`WW=|o-u-M1ca9*(EQ8m1%D2`7*i zzJX#owX4tCiI;bejmOG1LV3oXcy39GO3aVl89R9hr0Kf%=AVjVzQMrk>V~;zH_Uct z?Cjml{q{*MAQAi{9YuENc*dTXXU+wQdA2)aH@o~(9~PksOw5ZUUY>||#mtE=5wqQi zy4ihS+dIV~7jTDx`Fu{)**8dI7e4a_W+T-r8F&zmOVp{;w^_1B&QPcZlT zYmM96c+1GRe#8lAP?Y|F7)=my9P!7V3#EaCW?^ucCX6U>Ad9 zOD5w9GT&ni7{bxn;rlJ%TF!uP9^yZHmiUIbuxi6YXP3Vwe7FHH2iT$EID*;b?*w3a zsv+GLUls862h6wFjo~<^*x_pg%zXx&UH%yUBLjx`=+Xk361I`X# z1`r$o%ux;`XUJb)@X-d7mj-8tkJ>GU0Omep5_zK*os1k9Jz(&4o9 zG8`}?4LCb|1;97XfMGf4?Amud;J$YTe8q_WpMW`Hz@3g>(jd$;01usA{@%v70AL&g zB-m-`We8yM4LCb|$AD%uV6LUO4;;I@U3nV;bDsfchmXbl5nvv(z}eyZJz$=*z$F|1 zUI)Hc0kf4`0JzijkG}%u?*^P*{w4xP2VllvPN3sZXqUgc0P`aQ&cye>z^h+&>)d7M z%d3YL!3~px&h>p^->K9&a*Xc99f4Xuj*tyCjfy|S$^v&b9CUULZe?{`#}^!nOUKa~ ze3D||+nds9kBp+(5}C=mXN><=4r*k&@f>h`QaSL#G|>sy`d;?A09RM#BF6H{5Z?6{ zB}BL=UI!kz-B)#h4X{#A&I!`$NYGS}=z=QnW8^A|=}o1LhiO0_s{JHeIR_v-j))yx zK;@_$_M@YmPjFiUWylbm&MQ4BZ+ES5f;;2Jzo$%}%k-3{Dj$q&kF9-PMAjl6Hq(tA z_?=RNg}&O>gOy0#*~brGd^qxUDAGFW2)?kDpw!vBVLJG;-sU%*sm~_X)$du-+KhPl zF96%P#%HoR$UV_wm#xSMc$YWC)I0?U*#`KS{h@gQ7qa=u?%;kQ@8Ax_9o*=Q{$|U`-jZ>4{Z(0=mb9c=1*Eva zeQ9EACwBI({j(&}>8;-bR`ZATUnAX2&hIN+=aPC!{ugz7XS79F5%|-lRaf2AIvpO> zKK}t9dk!B6xfnnxT5om-DYcTW#7P*}>Vo)3GCGdc`~_aKQsuo9RaaZ~nc=u_!0}0? z$azGicv;K`kHt6?rw;W$5`Yo|@sV-fR$PE)i%t)@R024=B!@A6cG(9fJ6!iA^l{c& zMQ+zhJ3}86RRNVom0$e=3C<3^U79YTmkiJs_+sarR78x6Bp|&_KWB~*e_+=<*mv;_ zu>Xb_6Wq;jIa3duK3-z785=6Sr-!!=B{;rNN28vN-vl>T-avC9yIos~8)DUFk(du2 zjf-OC(j>in1^S{ zak>r!2~pB46}Leh?;x=)JarK+($&E(!$?Bx0eU<^atpbOQdB`Up`rzNG;U**Q}<-E z@sCLXZ@@3x8*RUn^kFtW*C=DHlfA5q)0UV~img%32tDSUpwA6An#;0Uv#mJx;rsuH zf}ed$G0LWw8RZOPO}u$zDzBVVDxPgy4w>x%f4r-5?XWlXG{v)06%sxN=tL@F&sJ3Q z5GY9b9*_C(QR9YIIc`0b=%qjZ`W2A#9D~U3Ds(Y zVm@R^D#hflVty)x1Z*{ED8X6|x?0wCet|iAh1%9|R51s4t|nuKN21lKvP8_t)c{gM z&$aNWMB$OT4*2W9fI~MDPr8P^jMRdoO5A0LOPC6}4$;ljw;DD_&*nqPYdBq-U!R3 zY2-rCnI~l9;79dIW#%}Pqx4cG3>tJc?#E&ORIj1&Ksd?_s{xK9n9`Axl1S@h$PoN3 zHgQchC%W3P6y~ahrhO=J2f8OvB29c&?~62N1qd@=ixg%baXQi#bC7!Z}dNii@S zr78;^F$kART}}UW0{y^;lXI3Ye}X?e!ecq_smADy`JDTV$?D8tP3h*6%1I$^;ULi2T;94 z@VqhFCGbJcZYFr`><36PcvZ!I89qh4Q{Yogu^{GyM|+(wIBas|@6C9dC*Q@+1p#?T ztT&Nlc|a^-pbCS(Z6TNXk(`RQkZc(6PgEf1QGm#CsH&B_Y7QA`+F-odFVeJ3yxERv zQrwy?qYiX$mOc(W95|H{B@T9JcvM{enk_mPe*2?c$qAcHcX)92Vt`wK`MM#-8^7>JS|cbU2mC|^%5q@IT5p+kz*j1uGe=KAp!G0Qa9cCsK{qc zum<|&S9})7%sxVQJ}UCLGiJ?iKmPl}am?&RbmyZYpF1wr^Jkwu^>!Td5{Z{03xO^a z&VeGap6wLkbH&X(Z~9lpFXNcaUUxnU@p+iU<_g2hjui732AzN_dsVVE@m|rn4U)rrU0{D`cXQkTS+Peo!7_JOB4=ukiWltRQ z`v{>M+zs<(2u;L1SW(ev`slt;KTrl3=t9pyd`ZN7c{j{gNElAK zr04kuUcl^ZVx|HPx+}V2z7nB{n6K!D`6>ycR-CwKms*BqH!%kd&sD&jIEr!(PQ-kb z#7v<@!y>?{Fg5ejIKZNroKB5@hR?zW2xiDHb1*-sOI%&`{4?I18kz=>zL~R4-?I6J zZ~2mWF`tQV!MyqNs%I`;nq_>MIcLeNxeOSVqgCIwY(7LvRA#Dc=FXG`1rh?8H4_e( zh39sGng`v}UBjgGNg^^CGrVjj5TMX10ckd1dG(UT3s;#ECq_o(_hlNSP4aTjLE2HZPEoUnY78zf#5_JIJ?u#A7MOugku^U zqa-_R9glF{4^BrJ=m=+ruP9==L}XB-TCZHI2e$8E;{n-tK*otYM?uxoeArjnD1=M z2a|w4y05Aqxid+e=eR;hoafZN=2C=HX~b;kjHrgFBGgSNMG}i<&W8pGi+LCo5En9> zzqr~EG34|BDZ}Bzhn>r~pFJ!)KJGi^xW553e!6l0aie&#pCse{ZTR>`3_y93jr+gD zr%KeDsU3?Q&Td>?ihQj#`X8(Mzca30Z|J7Zn*FuuQc1_mMbHRy%k*K_UXyd(@afdZ zam{tJrcau?aPG|IbEhwuO=-^a996;Eb(tCfg}lNb$HLlyN*kVfn*iwJDnRjgz{zQB zu7GTM8ipwrTJ-7c+m5rhci<;G^$32o_8#&_-C88`rz2%epV+kxXLfUY56KBK%uSkU z83|Q5!LYDJzp+;D$?+L72c>1I!5s0P1cNyLkit}mcMbhqrPqM~1jQga02o6HH ziivk0>Dz=ixj;Vce!RJ%^=X^&=7yNqHI400XR=Y){&s_vYzkwjLhJwA1}oBTqU%0b zG2hH<)8sK0#({OPQiO^ zTgaOUA=YgbOOrTQDb~*kgqvc{P=rA}H-@yc8JxHlHDLjiI9kO%%w95go^=>AK1f|X z$`}_`zR3(<8G(?`zHR2RIZ(#K^}iv2P2ue%NarlMZSnG%)Y22fDRuG?bj93dVN0-4 zDietuU31Pwufz4%U2hp(m7T4046S8GohOswJ{vn*q|l^xwk-D~n8fuUxe?$itVmZ0 zk^=2U*A0OAz5$1UAnB@_+r|eC7=_Uu-+sWob_RU!0?FHFiEkg~&O>dGuoi2aWIq`D?&Mtp10LP<%S;Hv@?sWOn0rP+bE?NGl^ZloQxs?+fTr7WG`jHC> ztpUuPYSNNS6T5n$Ew0@LoLxD{{M-*1Q>Hl$Y1`qu4Gh6M@zB}fn}l!o0OoBAoE^Ro z0rQ0g?tf(!#gY8{R#EFdpicImuoigQ`*<)5|2BTAHv|LlRPLl`BNPgpa@Jieo(v8} zm`I1^2;tGcl_3UJ%B@{{y7{R=MaM=|6m6R-)d9G~xNS9%ne<_E>%+FQpBSir(+4C= zGlZv-w@RHzH5Z5@-_Y>2(pf_m)q)g>+pVXGGJ_amZ+Pd4R^GOUZir_h zZ#q8ym63nP-$zA0_cD$8@9%Ap;MxY%1fpekW`Eky3}f0}&#pt^xlt7=Iz78IC~dwN zy7eCnvJySJHs%Zlyk7UXzqlm-+3?@hLHDx<-^%~2E<-e^I;1WLnOAR_tilZ&bC^oB zLH-BafS)+6rYVq-9f=AeY$5hSFo zdy4eZ%E^U;ZJIU|om;Iy`I$3gF`C1vT`I>2weH0I^WuPsOU=GFRQ_Y7I^ zX|2^WvYV9>f_ITUI#VQ>!wH!o#}=&F&Kj33Ah#~HsKM-JrN7;%KQ;#=s4Dp53`aXvL^)mE-uK2^1O)Uw)ut6gugN$mhN52SQ1Y=nL^?4x_T( zrJ^{enEXSKdBYHrWlV4eB9RUK(eRCj!~H8oYdoi(hLecCo$Z-@SkkGB5;vaR1u!OG zn>Om`f8k5yb5H#>kcLLr4tRF0I|gW>HzVgt6^<;jr{OU|wtE4*=9R`yw5We|Z?vWV z`0J%W>_5=i*eUhf&4_|i(V*2ML?utXy{rBB-Qe^)A1MKdjO^B-K8|)F~nRZ zo{pC!d>w)^aFe>(`E?FCER1L4HRyvrh-_|H&KqaYN-V= z-|g@X#*?P8l$IJNMEnAs#L}C%~HjS`z-#WOOb0w(L zP5Xcu%7MlOGZ8ctw_ma#pgTHTGFl(QezuZeCVTLCBv z+It#P0|uVS!2*#gHY!ae&;~R4z5+4E2R3hXC`i93TGWsUs`3eK5~#9l5)uj;3E_%` zr{Qko3p5xK?(cba_l1vhVS(;dDUV|99b%Go_lxmB9`wNq807C*RumM%y@(RPzd?N< z0y3d33IRj)37DgUSy0EImw0i7Uu>1-|1>;MmH7fOC39rtt#rLMs87l4yfFv{vTUCj zEH(bgZkE1<$laBAeA>%+2c!=#jjL(S1F2euB+Vi4^TJG!mg9yB!6u@xhZGfsr9#d4o+hkxFp_0v0%mf|dP>|p@uy84#iolAwTqI;U`m{;MOa> zdI@xE;CsB*{fS_dO|68HHjRo>!V0?0NlS7p;vvoSRWp~Qk4Tg3h=G(K|S%_$klJ;97ogV0Vx{rfpbi%Qg zqs~I{(eb~w{LSe&<#MqFTwK~^*&QZ^^aTQ0r&Z=qk4xBc?Y*7ht4#tzFJs0!AqrJ@+oWoG5b1nR) zaF*G}ATGz|59f&zcCW80jV~A>_Sat&o!~rwsb! zM=&7plqA-@e02}ch>cL+2UZqL&AQx3(WM%4Y+r*vt^uvUWvsNZx~3TqOyCVcE(7tC zp?>`8C!l_U_$e1Ny!bv8-ik^iB7TT#M+&k99cNg_u5Sp2%n&L*doq}TiRj~p+ajEh z0Hz^ym-fu}^RxHgEqnrstz7x9tZ|Beik8B4CkRo0B=St>ZUrK81Xj=P{Nrm}`TN37 zaY`I8q26hH$+MBnM&bUB$cc!$2Cw5I9iGPi5ccV&lCMON0C=Zrrcqn`h$)kX*aV7)S3GnwSh^Dy5Nt!GF;P8GrTL zNBaX-%mB%X@RMGYA~SL-fZaiVkT@4brWsPMcTr}LzSE7V2o%Iu;r%UcbWd5_8^H5{8J=PZu z>suI7wopGD8Tl+w|1OsMMTi~OPjv*ffYra$9!4&QTJ+P5m|FB>%EbWt66LJ3l-eOo zKyr}A(Ck#=r*bOg*eo^J;kyq{h8(MLis;$26L`y&8mcLXm0OAaSpbT`1sojN6+M~J z*c@H>WJYbaDB3j@qr?TOuVV1l5r7U3wP{a`6XSMGEt_b5a<`3^WG{*~L)%%jZgXbs za8b0Src3lKH7fe|F(z!Ou|`j4r;#HvCvBeELd4=lPKYDnPiI;#b&E8N5o-&FMd(G^6ZW=^Lccw~tF~x5qB3#trrIj+^lrhI-9gyhS_5p++0=;yoUOHVb9jBLu^wKQ7^k%)ZOfN0cOLO$nIj|I|mzL_Kxq4}hUOKg^6+%QB zadU=_8y7W?c5XzN-O-NZ56za*@cO?!+97LzwKbtB6i`zV^Cd|ezdVQLSEUY0dhk*q zYz5^Ab2djQ)`KOmD{$Omau()X-F#g<^&1Sl=W|wVZrblH9RErj^Hc+KI?9!(e#j;B z!;TMPlFm*CH>WGYtR4SRAP#Ldr;?(z)&|Fv#DgU}nOW`@nU5Kl??J_w`B;JwIwdnp z-#Wewmss;0{S(u&lcIeVkWAq_v)2D0p4NQ^*7K2~<;H>(0{ae&;+TJGU_Kuy+E(CT zo@b34j9m?VbdRf_^OB-{8#tKf&hR_i)xL>l9` zmq=rFW`M}}=jhns4rj;Hy2ijvGeC)bkle6D%yx!&CIOOY{&rh6gf9(*+BXc3AD9#K zd`UOV$`H>a#84uXi)P+B7kaE9);NE~+&R_ZSqru5YG}rqT?@g-RX7w~a_juLTF4qy zGk5l_#)l9jB)Vnagm(Ys6VJyH;9xNz}u|sYI);flz4Jiq#V5mYLxidCCi6kLp|IF0Nj(G(3M1 zw1-Kl%0z4lu-)|hTLp7ey6W(mej}GkCg-~BK-`_l8o+hA*BYXml*NRx$J;lL{t@3!Ie6u~-3Q)Mh-db%P6qtX+q29q4Nhpy%9^&i@pP zL7qBw!N&o75nmP;@&aEHxZ1OXTYZ*rjb{lLJxjRz&Jym2X9@SSWN?;CGORLA!T$xg z-y5*()5%UVDMi`V1)tq1;3mwATR1nu+2MN^Bh^EIiS}1;99omLF9*+`7%&Qw`O6Af zr+kL996tlx?+jSGbT8U>| zA9;fo8Z-Q-mp#8XS7IJtaQ&C^qNkM5mSpYfyelgkSiO`i3m^2Z7bujw~%L#-@fYli{H55r#I^vlnH{SD`_dXf%tG)~WG3&*D za$^X0Y()O~h%6k2UVu~D)nHU^E5%N0fbd|$mIH8{w=T;N>6M+Z zH3Y>pPa!CBL=y|Qm3kVk1S0%=3yGA5Rg^3lMIG!O9f9wn=&^v@x|QH$7JxjN1uE?E z9>ZqrvA`3Epoymq=8R`s7Wn13)SHTp*eo6$4`sZE>P(i(R(+Bw2VfXPEK7MBR@e_PJY4@=MA5YnRJZTgtNqz<)UMdQ~ zs4T)BSG>IIJ`15>e;(VBSb~$DjfYQlb{>5XA5pJvS+5h~^{V#HkGVzoF?SSV+y8ok zgF|$*^Y~xQ`rWl~QT0ZZs-_+sReKkT)C59sJnV#L7xiEr-2@Cun zh7z-9TTN=hmz!9ONQ*bp>{|EPw*gVN2~7Ho_Pkhbc|LDYf!e^U+~S-Xt9xP`HyYL# z9J;$H1j7V%|B!oiup2ann~@LeRsC@`+zZh=qXTNDdxfN!9L+Yk%;F?<~H(zKt) z!uG?ba`h5?JdIA%4#mEDQH6>hHaX^75c6$}`BdLd38}u`H>CRhppY69E(@tKA{bI* z#+4x?19!|AD*_?@$3+3=AymE6cR~rFbPduQ$PHM2e*UbLgGH%i58{7tMciU6cw_6` zVC(S+5#~plbYKCua47yQ7n^0UlKVhFbn^W?5(`Aj_~VV@9AwCg@cAksAdxEpfF{LaFp0r+4>kpSoR z|CkiQAC*bE#MqOT9Mm{f766b0XQ7!WGllQx@&A|uPUU7{C$EV;0&ha_1tb9DaI zV9kK6`dCeLP2)U@-L={hngYd(?D3BGH2w|!9JG`y3O7@@yQy6A7>^Bdsn9DnK#B(}AIfVIuRsHXYVxwz`at zg}!cvW_q@I6|@z0Xj0g$q_8v?eL+!lbZE zlfs6R!mdn!H8NdiWZK;=)0=~={)9Lxhns^9@!FH2F0gyICW zIe2&1C}tw}+9mS6t}%>6csgm6#*#Io2{s3R+%=k+(1Y@WC5rjsA-fpAwu|woU5v-= zVt^Z%SjR?To|NH|o_tA~ra4)(&}*B6PstBS3bU_k46~Gfu#54cU5r24#W>V8hEbS5 z%Wzqkj3kA5qiZxXYwySpNeXksF2)CTF}SEqO3R;gjbY@uLxz{8gyJKi@#UoaB1_{> zQW`Fklcwa9ACi=YEYqYh+;%azFiskS(?*iczgbQs2{DYqa6)0Hi5CRxx?mZ;`an&b zQaF2K3yFhuh(^5T+;M2!lfgqgUD4PIIFk?huF*o!W2-xFhx*V^-K(5(*X>!0kCDBY z`T)QQ$J3~vFsDCev-LkQJLLcGO0@n-JQr2ZRjY}2%F z;$0wpv+>TCz6E#>l|H<*4Sd0+$kn|%kF-0@Gx#G!1^4ee%_BoI(OFrFSf_w@{{P8) z6ZopCt8e&(8!wSY6E#&-T8|nO1tcK}BnHh*?vUK%Cb5`# z*Z!}y=Y96xXYaLlXuw%d>>GEm%&v|26O6E#;dF}QUg{(^ki~fo_fWOnzYoEp1jQ}a z|7IH|B;BF2zTw+~_J8?`XMd)?O^~rhbBV#KylWYhwZf4KtzL+1=ZuAJv-$_6HBpM| zua49cQ_XdbluUNvPmDJ##?6sB{QVWrJ5rqG(h=j8;?6Ng>Y??YY<8sh1&xjvuhcYf z9I35etaOF-XNtfP!)va!g_}yaKw0}a=~$==69Wj0IWRZ#sfNH6mPaw zlqf;yaV@=a?Z^A=CEH+$x$6d7R3M8(V!Hc&aao~LH_Ei;k8?>1dlkm>ud}zG>u9dg zn)4B7Z>{6ZKaj;5OZU{F?|;KeCq~*@ikK<*l+!&j(8rAubQ9BlFnHdytIJm0Y3C|# zAdCG1Yvf-V8e5$hcImMAolxcTdd*Q`LBJSGt z7S3;9S=Q?TMxf{ z-C!-4dsA0OkZcXAh^M5nG67KGJRK|pZN;=8o0^y z-2%T`HAaAVOr~!!T4+04DcofGJ_C<68l#Yt>-#z0Ccoty1#U8Z?eKe6V+4rDWbq5( zJ(J|S25vHa+u-*ZjS(Oolj(a2xPO0$K8B->0a)rL)t7}g+ChA)!A%xFo-aBQm|DJ( z;691J$>Mi7>hTGD2f0C4b~0G#N!>jRs$XX6(Cgqwy1CBW-Pd(r% zt944=U8kmQyhRd=b+Xje+nM6PlYxS}@ztYX=iB*P3qFCUOi$goojDf(7OB|$a3FBw z-OS#d@8oYioMM6o;wsJ zzX~M3*qyQW+0O__e&y->QWa#YDx2iU2d;I^&10Tn<-X(>Tb{u2se*H=t*=UV^&mfz$dB^W)z>l;Qa65&*^-)b zKeW!#DcQUuu(g1ufAXswC^_!J-&Ge$qJcEPF=zXg$DiSK6|Dk(r_NQv_t%8ZmM zah$5D*ToLoLU~*Hae}3<3=S9Vd~Qn3awIKZ^6IeEik#Gp!}-O5S$Aq`PDSd1?9`$P zlqoLy&4nMRMJzF-cgr6kI0p$W%)5kJqM&xs>__oi4t&gh5A^xih|CSh5W>+_ps|NL z@2>fIcb$t&_{@~cmIUNJmf8Pt|2`;~{pQc)pLYza}RvbhL`TTo zye+45{dlCX6ud&@H`b3|z(+(?Yo<%B;Y)_^7^~KB=M?TTK{d%)o?4IQRfswvM_KCD z*RuS??v%On#VMgyPRZ>Z!X|bIm(Icm4BXrNa~L?;vhSP&FFSnejG_R-4OQ+MdIJ%d zKKfhK*tXLp=yn8!&=Is+x8}Ba+02}sN-mPXp}%hZdPKee<=PVBS8L{fzMKhcRY8lH zCT!3~fwHF0NM+xG6c?mQgDMVzM=v`(@JqylarkGn@-OE#tV?j^2V1$XFn}t97m`W^r`RZKR$D6`Us%(Ag64g{} z7JB45IhRxU;JTCd6>g#I<_ik5Mk22iDFu8~N zl>&3F0&(`%&A1IU=(+3-_$=oicim z=aN^NG2gs5khkSFz;~&OUxjzUq5u?ePq!%2fo{HF)|9-9-=b=Uail8@mlP8qQr0GL z20vNI7k^unARy7E1ERKy6^k;YrDDabk@F;v1h0c|@Drnqg24IfOsU>)q$Fc1Dr2)o zb6_2;vb9i$?@p&HleQz~z8vLQYk~&neG7%U63-H$?!}YY6*L~elf7Zkz(!$%4JBxB zHmiIWfnskTG`?^1?gquS95mhm#Y!7AveCIN5Gn^0SIdH8=1EcfCS58#-XN?f+E-=F zg2oI`#X^~&ii9czHBYEnpiUAB4>{P)f3qZhFxUZlvXv<{2I?Rj?tgA&ijxelbI+Uu z@Csycfny)$d4>Jex6u5>hWzE1aX_K@?PN!RtvnK_Q;Ld8U` zn_Q1@t)T!kVctI39&)}J=vodv?HNZi>kr+>*+bs0R2UsChhFSxj%)76vAb+_*1yU# zhaJslXw4sI$GFZ6!)wubwbuM`c8qhH!l}uv?I*h8j0Hn+w7WdTC``<+C_|(BJfgwX zqJVHp(MVT%I3*|^E{r>v5=i|oNI0DN;9TS4loZW}6kEE3DF$Y#3p2l>2%XcZUJgQM zZLp-E2OSCf7{zhdy7bkngHY>Xw;6wJL#tM{ZRqGwOFYg`ZT(3xRt>dtgR|I!GTJ)U zZdgMRZf({q0%Xm}VfByp^-cJ-wriwk0P8KZR4$ys&zQ=&st#OvVkGkSep;sK{ z`(JVB>i)PkX;Yg{Lws9P-~T64cn_mq`NoCEr>=Y*RBA9MHMSQ-edQa&`KiUZCBJ}8 z*ReVrUCW2zmc@0R-@wVYFaFCB0v$_?v-~+~LWlE{{Ir?6M6`dIA*Wgj;@k{VlnUop zKETZ=CVu6gU%4-wlaeEismqDu2*{{>Ebnr5Z7?pCHpFOVahir@AC7&-1IOLh8aRpYF}j^=Ew_%_e=Gcz7k0F zM^dp+-tG9_iHMYA5|Y1jcL3z{RID5)So;bKx#R+2Y{1E;tk73H# zTB?t?zl>#!!aWxNiAaP}TlrlR${D5U%U~|j(PUXv7|M=X@@q&5dk*i<<_1}flv$uW>lh8katOg(ufnU(xg%i1tGOx zG;do0y!PzIMlyty-?n0GP41aE(+R^MQVFh=inSr9zVhwVwJhM_LsLs|Dd^bZ0@fH; zby-rEfg3=)@*!1VY_%!;G}x1}vzTJcrnfduEY%vxEKhA=g7GQ(r>vAv%sLj&>GA_Ug>Z|9V!a&`u@i{-(jvStqiW-3ja0lTpE;tgh z=J?1Lro$3fb7>eQyWd7g)nKRIYpju}<>etP6;wXJrgHv+$d?cl%s{2!dLAqdFpp}O z9_}QafixB5ZR_KT2J$L(jZ_KTTZC-TrmPXYk!7iICeSMVi)H}7t5#Kt+5*_7lI+;_ z1}eoq*ygxKD&DxOzqsJo41LAeIvDRjt)Mv`sW#V0wK*Hr=8e=fAHCWjVFq80s)`&W zRfJG_a1MX9<)Evf4n2+UtamZ$D!3>#pu01I_ks9=XOhf0u|{JhKm08eCDXnZ-= zND?qXf<;1HpoXpss~odZO}Sk9OrrkmS)GN-1J?e_7AIMK9!b?=fw-XZL5NKs-apmK z1NiwcXL~^|>^7A=@#dRY?*nI)D`@$t6*E%(IVDe|9(?m(=niJ2-rlnBg6!FUOTC9U z=ks>U3)ZGeZ^aMY`LwJy#tU9!MA_*Sr4DZ8zq6Jkr5VqF^c>hz`wgnl&gZ5EUe{;v zyHiaY*~s@@aA0az_t=4(9^MEIb))}eD2V=aH2d?flf@f$B2ZY7%*oqw9YBF+C3Yi- z8*kD`ODBCU8i(0=Tw6`0}*3u zvELM^iCdoNPK_MCk+Iv}Jys;Ox_Q>4V{iMzOA$g5`YWK2&4nn`g46?f+bU5>VK0O=4uI@Ej2*{DtS$v&97j={ zo3r*5(BI%7N!2U0ih2ZiYFQ0;+TFo=r1z+#u9wQcl`QohfBM21sqL(Esnb!jpH6L; zn!O)7M7-se)S*w@RV__vS2aUsoy*_6#~3+l^PVXq74Z>egNA9dtgB(QCe;*z!FAjL zjFlX>m)=6-AAvQO$#rl>!;}V%ALGf~2+EydYFz|Bjoo~}O@R;HQTXF(oxLBZN9_mt z0}9D3`8O8nDjy#EisTo^amGkz#kxf)9H@~d$F-U9!Q9OchL)v*siuO|Kz1^zUzn}$ zqW<7bo4-We0?c2l<@C$40+@?uoo&XIchhmbb~XxM8HPCjZWi@}_#|OlF89vU3WcC2U&xW6Wrqm-4=&_jug?UR zzK~O|5%GmDt#+0HSo!Ea&O#2~>-gVD-Sx|FIGR<%vlem~#<6^eGl6$cg<1K$8z&~a zWQ#8dx(EOCJq#XE>f*S}M)z@+c1&nS^)Rv*fAT^{bCu}*cuPCGp@W()`t&1MleXf# zRBQe?OFOKK)cnUE9{pEGbC=f4r5%-B9Q`UcG3O5i+ne(T$RflT_FYGwsN5Z_|K3_JAx{0ABF|?;SBW;9PPN)tn2zbeYy4mRg0P zAQ^XLu#K^sal1_G52FC^j+lO3Q~A$i^YM$|`FV|_>P$N_9svJFjR7fcGJPvh8Twfv z;3m^|Km68fi~#YNOy2_Jo7&Xr==&d^kGBu@4v%zxye$AUpp>)uf`U$5ddhDv?2K?` zr4@5sm$e<-cCusS6OJ{U9DV{?oS$mNRnSXvvAV%it`Cah<+~wK*<=nC z$VZ&>@GBKuy${!{aCnc~Z;*f^Q-Y#B!d9@%v6>v*RwI^!U@?lZ$7BiDx=dA4*$NKe z?42B|R6cUf6byN&U12*! z;Q#Pjo^_3##TB;(7CCPO_gh|dC01{Uwy)n2ti8%jd`D2)`;M6Ga!so?ynRTd+X+3U z_41R>fA_s_mB->&va9h)gYU2F zksNM;r_1#II%7hAKAByOi8}=|y}uqo7~Grt3teegU*!GZ+5paYFo&P9Di#@VVlTt> zVU0Xaie3cnUmA<1m+?Kv<@J5QWRrj+ZnF2%fxvv)h0FBbr1va5=DKi`>01a)tqYe) zA1bu5SYtqnn@r!2f!p;V`hrN{#R>*DS$%1Q-|@hVxNwuD_X1!p zcj1`c{~hBPT-x;U#xa-|=cq;he4M}8d+PGB71<+4$@`Kc4Gs#XpGxAuvFaHqYqJX$ z)=ycFeA7ry`~^v#7kMa5!NaQH3L@VB$G2O@4uvIkoXmL{3}b9X&NEVp<#CIBjf2&)AAH##Z!=tvG9J#o*YA&ao9EZO^PI8vF7fg4z`;=!6>V z8hVg}XHGQ=jEnF*0Do3ZRp;^_0f#PNsC7RzMA}0Z%bzJwV=3LJgiBv?r>eW>2|QA> zIPFx9TsmjPCskJmQy{SLI1(JYawEJ_bqNfQ>>o+@kEPC!*3CP5?q?^Ks(W2=`BgcU z0k0^>~3_KvYjcH`HU9m{c*MND$-SmxTNnQI>~ zvd3;w6flffG7ig^AQrGXOd1wY5rZxJMh;z;`WqG>XXM?Lx43oRlNe0bHjcg_t4#>d zU}s8~tt}6q2-+$=9i@*JBP#CKXA5_X=HG2k}h?4;rAWQ|D~9?6LF&EL*V1p zd~jNv*$V`+SO*!?Lyvf8m!tV@aOes|GpPdz5;rj{zQMg=6-ZdeKtj!%!Z^4#(iPV8 zFY9<$`oS@^O=)e{+JT`BZ7^`=J~Ac~uuj-i92(%xD79Lt^=r2N)xL6IXk;Qpm>Q6I z%GZrs`(PAuf@(G8vo8F0%>vijcWHZ=>c(vs%br%srGVah39iB3-8W*5W$U^bxF2XNqnc@6gX1^GeZV~B!c8`B_%ks7aN#oPy9xol z2h4UoqUCB+rt~r$)(wXs#Z6{^a0AL~41aW1IzH-rRKMZ#Oi;%E@l)GH*2$Jwp?Au{-tFT}R6qn-DeK}Sz7ctlIZwUI82AK9?U^ohf zXqf8bB%}&gXStOn3KQd{Az*V6-^~x1l{<&a#&MyN1d@0A!-1U$BxiM&td%l7`YY$f zg?kYYR#D3_x~tqd^dF3-Qmj6tL!dxq1q=vrPdRXHDil$^os!<`i<>2QdsTa?DaD2<309S=LK7JPVBVhN@*p{0>>=G}A zptbV@!@Tip=%;EyO2SgYm~>>)-}4yqV|<)4XeFX3^(Dqo>1k1l#w9>hV*x0*2H(m3 zJ$bj^$@}b5TfR;`S*=PKwVboH@j3L`o7z%Xo=RQbs8ob9O15>ef%Qd3)%ZjIL1 zg33pRe(O$=iim=?sMt0RBJ1u(DpWQ&S;v~8>Ne{pXBiyTTJ^XDl&Z(&pj16R1(d4C z^`KNOIt$d%_$x5DtS}3ILE{2ED}{F@o(qNg5}v9q-Udp^V)!B(vcI6JdJac&9U@+FO74r&7q#QuJyemUQYMmP;dW;j(}j=dIwZ_ zDjjC6LALknWu$vtP8rHjG~@CU=`i{;=EAEXfVG9`;*-tbq1@ecdPq6Dlw8 zFjTH_*Ro_1Zx&;3kHi1D-eZ$xh#}MX@v3wEgiroY04L=sbO+ z@@KQ=IQ8d?X`COXaUMzIJe$V(dm1OpDkj4Uom;Dwla#t@%QUc^QaI(d;g-^a--MnIZ{^HZ>WkPeyCox_kS&ytAK)GnWsV&$vEp!S4JjSiaXb@@3+Z z_W6v4G={rI+Rh$r?}O!iYZ?VkCv2XK_R*xi($mw`yQ&9!MAWZ!y`3XH7J8(!cK~=; z=BTP_3y0c@lA*??aJ;#$ITFI)p{jhOs*LTZs;sIo924*}`*ZPpCa@egyA}-h-gz9{qlw2Dg>d?8UX3`N?;38rBx^%M zR;IBS(OOI7+hs+?N0@ugFURR0!E^4pQRbe%Mpy7n-E1<=J!Nl(YA@=U;q1>j@Cg;T zLHKRt*POHx+lpL{W7UanqfxZO-PO_`y@zoZ^mXfZ*opWZGD4w=IF7WZvBz<_OmkF@ zJWlX|<7m0l2ae;CAs;x7Rlel|_i5ms_JQMkVy_RJ%qKWNbGc0Uavc0m^np7DxTH_q zkPjS-^=cnD)|Xp-;HXb7LB_w9%amT~`wt)bI3E08K5#6Lzx%)y0(ZdSc(`1q_^}BU z`@kIuT+|1SWAC$k;0W331IO|6SAF0(tbE7^t_Zl-ec)Ig<`H&P z1IKbZ(+7_2ZIcfitIBmgaBP>i`@k_Bzx9D*`+eO9j$O;aRO)h>@|pGO1RuB)fLrVX z$9z852afN7FZ;kz-y=S7vw?fn2hIfUFgA9VlYE(A?dvCak1ho6b&jp!mf z&Cx_SE>k|wgLl6VTq$s0@`2;()Z;#I)R)If<8qneR{{U94_p;+=lj4d0PbENxRZeU zyAK>!2##W><#LmyW3dk$>&s<6aD1QN=>x~|ebNW661XX>)Gn7P9h`Wa;sbXwaCJU# zbAh|a2ksQ$Zuf!90`Ao`Tz=ZPj`j4lG#u^%a!u9%G1$M%o=M7anev7CywnG-9JtLs zaO|J&^?~Di;W?kUH#6Zfd_y?^fq#k-fMb4U`sVSC{jm26m|wHP!kvk~O#KkwtNqLz zm&=rY0r+q7fg|K%A2^P~e&_?ortzQ;ToAaIeBxg9iF?BbE*s(Q^@)4eCr*|yq1SSm z%7aTX*&IB%TqYdjm+J#Zefd6c`vW)K2ae@&v=1B?Q;zq6WBsFf54W2vy`?^I47c1T zuEqzB`JC{9V?HN+;Fy1>`M^=%3LiLh2S&FK9P@dN4;+^b`+eY;j!_>t#_v2IIOg+4 zpSX*C;8>rx`ovx71IO~X!3U1{ce4*1(|c))+Da8rQ$jt?B?)8F%f<9qsn zOt=jB{0HD(*4WANr2q+e1DN1KD2C(sH&ebaz2|cf?Q)s&h2yXbec+hS-^ql_kd7Y! z_khM)>G-I77#3(-F7y1^a_Qtc=f~T@;L51~D@eBB6#jy89%HLexp;07Dj&~_gknv- zP$;euoG%n7oEwBP@jOSULOh3snuX_}P@GM!6^c!JwNRYFtrCi3+D@Ss;n^-!2+tKl zMezKrP<42oCR74X&Rl~=63-<% z#FulApfQ3c8%NMsk0)arlvK0B2^t&mfw2TywB%sHc5!*xWEMYW8;lHWyb6uWC0&`&V_1 zbeP@kP}gZR%h_9xFus}e4~&>S?fsnyaAv0|rUlow51L*5BSXD7v=pYjFOwXJQ|~aM za1OrUAgV*=K({&SioA~S%+d8TM{P}mh|W^R#+2_lhVr#dk7e*%Qd{HUDrucFYe$Di z%#~fHqX6-Mgb{b5<&KjQmM>lId{%5bwVs%BQN>Iq8$A)8_*;Q$CxGnVO~}=DDw&rA zPl9h6=|NDAfKS=0P{2b&qk|)MoGgeDZXX@#9q2#V z>>ubK##cK8GT6JmtB*AR|MM7kTq_a1$hEHiVMv&A1vXVVC!@x6 ztsm^_U~Oku=X4E;5b|ba*N}Pq%ntr{ys9VbQ6&jdNm7|=M{w!DfZ5%(PI*eKY%dZY zmY*tvi0l}^w=Xm=GyuaTxe8?nLwDVB-GHjL<#Unko~qs4GT*FeOnU0d{8E8s@=8}Q ziLk>~spfB%oH^I*9OxQGp^TXF1<+jAJJN$F7%eEs4Ra7VwXGG|3mFC6&;_v7#~4)g zVVPsKCM(#JQQwk%?Ks9LA$RdBt~oMb7TfL4g>3IM)dxtkud9C*zTP(X_iZrC=bGqd zOr1FveAr~gaw6w$q{K{YqF+UqX(ZXX8$BUBUKUCo|8qaR>Nh`Br^5HLKR$0l0=()s zKNR_BAxzNr-}|}wp^ysozbkI)Et#@~_yr^>D4Rb1EL1L@yM;Ok&u8&hAn(clB|I*S z?-t6$Q~C0}`$yrOi05vhxUivo`5ym+@HnvCEfm-ClrP5xzZG5`p1Xx=#8dflobiP4 zmgBiwD2_0cFUKvv5neZ*yMEoIF2D67T+uJ z+%43#cq-f%K`Go#pdQ3u(D(+PyM?+9PldZ3)DGeO2+yAi^%FdI3w1x93P%k}-y@*z z5#LAg+$|JSt#H2w^<&}v3D4a^J%^|AeF@YK;k|+*eOr7_w0-B~| zb1rDq*}jdo?-Ecqi|=yVmuH?-{Mtc%MSQz$-!--`w-s@OhY_Uh`#Ib9B2Zrt-%D-Z zZMN@~pjg^L<67I7TaZ+^H-WlJe7|A)-e&v$2o%SiI8|ZJ#mjRgcGa02jG1#~mWAyV z(Y1I;A`90t3woK6I3>~ukT$u zy4KVz^!#`$nzJwxSi{o_!zZX9`nzb!1$eq;Korjv23{BaBfaOgb3kFv;?+8HOkB8Q z>din(x_@AJ?Z5zDX5u0P+zZT5daxa6u11=pgTvg2j**0p<)9ghC!$KG5yMnOP2L&9 zl;wa~k_du(l;jmEf}MD4Vz@CdgncrANo1`b+Hcm{uFhVhd3X>*>N(!HY6yl#$V=0S ztKuVe4A`A&cc9%WhnPRHxh%w^ zd*?ar{T;|WWc1MR$r6JR8R=_1W=mHe26}ohuZJ9JsI9{t>|bkP@vnv_@!n4?YcXf( z;qwW0-INKDh}t=2ux1a>PuIf1gC|IHR&&d|`4}{9=(E$ks<%5`(lrG1M0Vxc!E|tj zV3zmxcMhx@c7?=9V*3_GZ;kWVnvhiarQ@fn=E@Cb_Yf}sViN&uj@h+pj#)gfT=LbK z?oc{5Fx26h0?EuyfKKrX&}wOR`xzV>=s*py+K+B3DpKZ>uFg>?R`EeY>K`z1jH=5V z!2}WAfC5i5>{>93y~i+ShZ{I0YhSr?sOy|wRIAPtP#a{5AU%#srs`QnhtUjA#`b>m zv%|VFooS*w!v-33Y;Jcse$cjK&N5iJ%uh8MB|BP|k5%{J^u&yx5nK5iWkVqV`fHTD z@L<|!ITQQlA1v9S?^;Qf-n;SCxg+_Nuzz{sZh`GNct0NSh{?c49T>oVbnL{>vurZJ zLiAs=iJ1t=+j7$+{H>Gl2Pfg5M*ftE`bW;iv4$BqJe@cGAd;0TxL3zPZR%Ii%-t2O zV{-S@Lq{t6UadxLv3DTMqCLkGl50WK0RVyIUAz(jK+_b$j1P-VnU0N$@r2l%COYmT zWU|7GN7^}g6HrL!*eCI?v1bwC8CvYk z@XW-&EF<44do&1R&z{VXA{~Rz9m8CXmL|s=i_-EKSG#baP8At~ANeoU*Ptgd_FROA z)0Mq)&aUVjq{Vn;?N{-Hb%W94BokbZ5cn_C6UC_{DF8FV`$9dhEU==t8Ep-fAYVzf}p|7Ry-bohzhUS=B)))BRr1y6^`TgD&bvc z^EfVN6%2}9ScUsNesfk5G@ijz@!kQ&!xuq=M*|e^5Ktw;JKW~Y2BqT1t^W$w1*%AJ zYi!J#F-(Dsdk$`M|(&1(m>pYT@Myb(|;jEg~Wo*FbRvwd#^wGXu? zXxsrxrD!K84oM1(M?k$RzW)JA#p;isl)k^%)cc^O32rKy`CCHeg8H{m2Z8#BP=|ur zE!2^qSbqzQLQqOJ28y%nppgKj;<5$Q3&Pt5>NTOR1hreJYe6Y3H-S=f#hJq=n-fk~ zVzD#c-`R!J5}jD=H+e?Etc6|8!Q+R`2!GA7*Jd%~=BRtYO4FRbaBgG!(A?sRigGL+ z4{jLZSq*bm_ym)zIp)%y0hmTJYfmy0SS>VUK48r3oQKe41Z)i9%*o*3S_4CW0|P^j z3Jnb44a}s(3aB*;G-md7&g?MkX{do?bNCEltQzW4mzIFi*OwR=#v6JnY{VkimhU?V%zaJSso-Tfp|N1zT|1Qp zpat+&4z&-i3;*C2Ihb>zb>-=)si|a-QVye%Z)fFwY3G(5meIx39&d1m!T65^H+A_w z+So}kxcFF8wgjoQz*_xfZ+Yc-NxR7DOWNIXxYv=99Ulq2KXP*F(wh*yQ{G2BTSp7j zn<#`I`c07g%JltAyiq1D%;NRbl(%&!fH9hYzV`r7nKSIeWAgWrp~`<`2s`JM*3Iuv z8_lV}U34Q2uROc?{WCJ6imYK2N@yfs-eVRg=aoZR)6;|)PgfTJ#*wtP6O(U;geF-nn@46&5ru#8b&$3`)t~3`&LjE!+1y zw(l7;i%JHJGtNLyRGm!D#2ScN&o|LDF~JKDtX+$qV*(dxk~bi<7&vg9&)=)@W2&*~ z)w9rkzDh<*>c+x8{8$Dn0G;?Z6=>y!4$Hqr&yoE$mK&qf)VPL>@rw&zh6XjkQOBPX zg{CqQFiUEn6bjDL&*@cw;XrN#$x$uHi$NZOZrLRSd-pxB0;sfOxE#{Q zq`y| z%*Rk_Ji4!P@5tS1$dx|g%9Y`y#GX1OE~w3mB>mO|Pz9JjIxi&yV*xG6&@%Pt&CC06HAl0U2^5G+R*E7Th?R40g%N0#P&1hY` z@6goMg=}xBiwm#EKbYlKJ~mtovtX&F{N!S$Mk!As4zpTeHy}H;t?)i2@O2TGje-q6|3t(@mGQIZ9G3O)Q|Dxn7+Vx7*CZizXGL3 zbWelYj=!Ms5}udiuRtt#D{2~wIwd?F>}7}r#&Mvy?q6WAB3vRA=kr^Hx)T)R2>ThJ zHVgF#C>7_&KpiE#r)=JHHg7K|m5z5oT>)HB#_8LH%0@3YE)*9wE)yyj)Fz>LU;I{~ zU|53#LfK0p9{{+Ft+tl%6D@yPOQ-TVKsHXHOc7`3VC$M<9GlPI8=)_=(E_#Es)HbL zA%2)Xskd{#+%{w1K1Mp!4U0}E6>&nNIqvhHqvUSo!@l3WaqHLryxEbuRZ9`$l|og36k8D8ZTGzSf+O{;mLkS0WrE|B*Pq*K`W&eo zcDisT{=8C0gX7ewFFf&`nT}LQOA+IhI!2_dKI)J?y8y9r<2)@zj8}>!706YZ7sEuxR*VWHCQi1&yml&_qN#F#sOg!n9U-GL;M=GSHh=G*rd@)Bo zfh>MYTLvn(!Rko8b@k_mLkS0RVGpuc+y>YbF-@^+^eOC@k%WKCy-S| z5xAlY;&3S=>F>3&_d0JYi*>mDsdj92PpZ~|FYZXC8}??aB%+ggekuM{dYq-NtuchAe$ z?RKOpbA>6^;Ji|c;Ngr{uQ>PgcO0qDX(?j7Qm2TNRS$DtdhrBD>c?7&7_SuTk~8Li za^+XP=19G*rHJuLv3vut*{a;G0TT=>534v(g(Jo*6#^%a#at5C*wg7q^=PROyu4D? z-~_VRd(eIQcQ<_1k@~KdBE~CK15O}|>7~1+b3ww9dP7SQ{9NBE~Bf11FGWmGaLI+2ks( zN3|3&Ua4A1L-C}0xAiJC zH7i}0Ybj!AitnQtv8#tvz@A%~H}LB5j?|-CiWsld5^!J*og#1-ynpLMj#S=3ic5@Fss$WJ>XFB; zdDoGet)+W#dWr{hyzGy(6_+OA+IhY6ZuUI_{Y- z{mqfOSW6M(m0IqRI-_OgTaMJ1wG=U4snbM?HJk48Yf4UXr0&*I#CWAn2gixw+^&oM z;7I*WOA+Ih`iw|fVLf@>wKqFbf74RLc%?8XL0J3aN%z+D^M)L$1JI7>h(Ql9Ok;B0 z!r}bJtLF^xopOKUiSPf$(KAQuA;v4k_8Q32Lk;7l{Wl{bR{ztarHGl#6llN3sQ9#X ze~>xM6%v-!PQ8W_*<;WVt6fs_@vqZ{DSM$ccEsoT8wG=U4 zsdkUlotGbnF3-x1N3|3&Ua6HLWwnCRe zUMaj(T%~->GoN<72Me_nFQmk}^v=lL3Db_S~e+3BR`^zsr%8^>3 zrHJuLVd4ZStCYX>rMfytYJ-*{#w*n$Qd9AyEC1>5|L#bAUP}?-)1K zb-R`##w)d2r0@a~H@H4`t0VO*Ek%r1Y7IC}JzV^JDP9g%9=@cdi1AAGd8D4b^^!Xs zDSS#0M~qi$tw>pY!pQFqo$g2-p{0oNO7(lB-g#};VUAR}mLkS0H6T(sc+w??+~w7( zrHJuL4T2NMvdZg4W5zrutPw3mjLM-aH7C8-I$QKuZRdbbAN9T^gKu71iWsHmPH>22 z?NT-D0gX`{_qb(9H1p+(Ml3FoHf|XP-WDBIVXRoThnH zF!vznPlEc9`Pa>k=09o8qe`>OI?*{IWxetD-gjWkO1WYDO-m7j-WUftJ3uLClG8gZ z14M`8o~^F~+i8{Cetrv*Zq?oc8AUi^yrsMzoB%hxiM#COzrF29ouH+N@k(s~$614I zy6>Gk9jO{EMT}PpLn25WiYMJ2w;$u`4>xEjVj$(ROK=`IUNgg^X=QP~VE7FT14Co< zTUTD7%A##;doSAq-T5esDO>|7FPV>1!@^05mxj)n4&ZcO*Ql40V@^r%bAM5qdqDQ<6NCCwGb98Z4A?1 zg7|pTzQiL%J)LQs5f8^*4?hRIQxCl+u`kk6#31T$H%zJrMF>4}1%>aycO8RHRLQ_D zt(GE2@m})iq0oD2oayK-m19kyo9E%UQ*j}Do%hal=d5?V3#zmfF-p&8Y&{ldt<7Or z?)tn@G`stj^QAs-g+!IK@2<`^efT<5RZ|_Rsv2w`8t!Vdj%9>G6`=~;)GZ%!+i=c< zCpX&UDjLh6a!oRnh$SP9we^vZ>)sD%A!XhGSg~*5)gKGh)h4114bb15DKcfs^g&gb zvVCByk3>ST#z;dAL_=ZPKBy|gu0tz6y~B*4*grrb;WyA-Rc6c9G>4+`>UeWJQ4^y5 z>CyG_tSXa(Gf)Ft2vucbdH`y89?cWyn#NE~Z8Th8+Ys}L+Z!D}NVql>YpAJB)FdZ_ z4ciDGAQr9-)y12WvF4__kdByDcHA9MRkjl4=L&zoPHZ?FO4K&RYhu;mkUlN0vczS5 z!44Spz%AGik45Vms#)~*$!{BLWtOftwp>jt)EupiC7T-RyxGG=>Z&pv7R#8a)uC`a zRv&GwpO7z;;bWn2V`H=_jJoY9Lmf)(WT7-yC*!q|aJ^Rw)*mv)DiVs+RW~QfO|hoxSam}pBcz1lkg3rwTdANcdj^6 z?%WKci8t3F?_=mol#z?7lBzP>%tck1vU8zAMt@`n7j6tCqcsiT>gwi@W&5J4OhU1( zUm$P#20GTLRNIn~>QEE*R>7_XXhk+oem*W)k;)1$Lf=b zNJun)gsO!;r?#f1p{^Po9<7wCSm%O}M(QzNWd>o%2;?^Gme`M<~4n&_6cT zR7WDUk!G)S#^5DnDzR$}UR+I0@#^N9WP?}U4&9dVzDCfJ5)F}PeUz{GvA(`O7S{@p)v9#4n~zfZ zct5gB7~Rf$I}!~wM#G7wSQzzEg0hcTRFyTU5cO$)41MGpMOXDeWlq#LHbk0hQ7c7S zpW9G^))Pn1tICS2DtMx!s*EQq?2JSBbu~?iM6$6-Yp_mySi<}lC+g)g4;(E=;o*#l zYXpdnFdDC|iAUvdy^{DnuwTvVJceyP72U&>YCA5>pTj8a?5KC+KvE9G`!T-z=3i@IFUflY@H>S(H@$Z zwkd$pqEP|7BfVF+gp;92q%o2R$I&NC?#T%wZ@~PeYzf$d$^lp5W2Dm15KC6a8?_1? zMM_uTR-!EuxY|J?)R2h9!!=Ek1%=_bw%mX>biJpsM;b!0rf7XrHEyVpKq_$9>4QVF zJ5M{mP}24B<`{ZctIpuW(+4ZD-^sR;NK>dbSrct;uC38A!O5l%R+1i*qHt5PsivAO z&po6BOk9c7$2#sK)=-IYFF`4Z8*|UR};57 zMyum+rJ$-z*+|esBz7=PENU^Ruc@!YAl<3es1R|nlE8T+UNM|c*@hBq(VE&&Z7do? z(2Dj%_0Qhh+(cBb{Btx?QhJ#6t4%vki#uC;X9yB8_Mb!q=533jzEctmR z`qs?4CW3aI4A)mj(J(|8lwz9vVYezpk`49Mc%6xmci4vJ+T0jU#2TC8cstvN4Xes{ zz7WGc9yhEiN2KMzAq&RIl4|tP^)<=bWOZo4N|xdLg;fxhUPC+r z!akHJ84?dmi!2ins8`1m5pq>&Rav6l4y`QSP#jSbB)%usOj(G%^GNKLpl*@RvY2O_;b;kx?fx=11! zV&CM}wlIMfj9aYYA?uy*_ARN6)JJ2D%^`L&ZjXhLcr=lyLm^r3YqxKCZ6e-;ms&hz zzl+`8W$~JLV;qT)4Cq4N?$Wo zf^k7pQ(aRdlni>+*Vot7*VHxEhV0XyUjLe=SfmD{K=|u3p&tK|#^yv*1WO$3Hr**( z*icj5m~5(V2w6igw{KZ(EF8fwqdBBTV{X5N4N)||`gl{w8X~xTOT)FX`dBg+L55;X z;P#pyjVEgpSegpqeed>IP#=lnMUkiv=>dV;v#g;hR?`%2t_!L6yxXrdQPWgYS6v?t zNw4SjDygrDC(!`I=vBOf(309jq$$oU3Le|MxuWxgtrn(l3W7ct5 zkMBZc32J&%15SI$AzF{`0!%ED;p*C`_~Pv@!M3gG+5jV#9X(d%C<#|LL?g}3%^|*^ z6h>Ee)qM@Y{2=at!}?|STHF&Sx0lh-DLOXZ&e+DK8q~I-HC;oN&a!v}gY^b9VYG{I z4Cfj>F`Hi(LF0|^%{ZS3*QIgAQLG(R$Kn|8PUwT9p=hkBrYVj*#PLYgDe%=IHV>uu ziJ`4b9Ko=wZ%js;YcS!~Cn)8GG>Mc-U52~alt+e}mu$vbsLt#yGi9TwMt$ z9UpSj#o{?_4}%A-Jq#X>Rx$a&d*@UL!y}z2N2^HEZ{t(f+~KymehY(vPb?N|YHDs& ziys^imZ^nFHL;Nqw_Y-qiJLG&*m2t5zOoOC*|2lk-q+T_`i0t{qRMLs^(E@s91^ej zlYE=xZalX5)Q-Y^yk2Z>_+`qKtQm;A5L{tj173-DLWX18%{G z=wmuUKJ_JlJHv;*ZeWI7xXI#oJ}}!{xJ-AaFum7m4AV+CnZ7Rock74f<2T?R`qcLm z;C}HT`tZrncoLYvCm1vJ6)R~l`6cTH;BM2{ z$?D6=!2JlAziJ%6@@I8D}<%iPl7CMRk2f08XGv!}3_$Q^|()F3Z4W!}H?=)h#SNOn92kxgna1r2sn}$n| zUmUo@55~jgGUW?CM;j~CaOvs5M{47XK5!x6o=n4~$FCH)L-g((km53x2XVDNa7O}n zo)6rofxFfR&IIm9K5&Nv_n$s+)c2YX+%do%pm&sj6qhMqj)2cRA2`M@?i07t2ktQF zJI^QX^FDBl->p7y+@fLaDFP`jQ@&8&?|ta|6mYNmz|8>e0DFIk1e>wnV7S)K8->c; zznlP1Yp=}*;n<(9@ewZT{q;U@d=3532aY={RyF2k}z|X8c!e5y8cYpr^uErg&1o?O1`P z!k*#ktbH*42BRDqRj_VMWk3jI3&kItiU&)CqX{QSMvIPp)TBWkE1q`~D}gB$_@&(} z{Hp>x<)jNj6-YEVJP8^MQ}N=sA^=w) zz}T;{a5X&8J+h7_=hyZ2^})dDh`DZHXpPy9>l*s{PMS8&s9U=hwnFEB%z;IZt!}HjvmajPEtcBMuE=C9kvXWz@2-uPx2DH|Ek5#>;c&WdOSXjrt8+;*}&r7Tivn@Un1FmfUZSn;61lo_S}S4qq6{QqB6 zyV5B+ESWih+Wb&?$&M8dvYmeyf69>lZ9;Ku`Yrqw7<|osQ+U{8tt$qHbYBx5Tg*-P zD==8rU%_8cwlXRnhiW$puO3gu!+tbv$b6a2`wXaS@fS4CvUy#gt`goFn>Pq*yYSAj zdE90>F1$@PZw%CB!n?xeT@C6|;oV^K7~hM9_YIrJ^iz|vwRIDy0x=NDEqg)ZUOW|V z2PlRe6tnw^_bdEfFTBU`RJ`AT8WrB3Y~Bl?hJ^PQoA)F_nb*vHl<*pAB zUh9YUJE9Y-N$4x59gA&DuoOP;M8UO%`SqerK3SM2&YNa{e=NTL;SFFWmo(QdiMF(~ zEr}+Zmn?<%{_q_bWYD-Vh3I2P@gbz!j5IebZCln7ZL4W(Y>q^2ep56WX={nsHdQCu z!qrQ|btoFD_vBr?;E z?d@jqNfmHa1SEZ8HHkMZjV?hkwz!LCNxZghX7PZL)J*)tfpLQ(N>j6>wV}T%1Gps(9SsIa zxa3GW3TX!dv_L&_*V?MC{w`jf&}qV8zdgEF%`YY!k$DA$EO^`Md!`w-5;+`!-WPo$ z-4s3gss^3ekd_mM2pITy@;_uqYl8~F^>lAl4}c%Y(yL&`yDyaS^$CZ?^&xz96Iw7r zW#ehhNN}WNw7-p|sS^z!_p&juj^=&Orfzn|qz8&NE;E{xa!u;?6RCVWEv?xGd2Y>| zYdD7l#*exOuWbv>i85U!U9^nrBljTuz$i{lWEW&Pmfe zO)%8VnEr9^_NN`qCxb&bElu+$!1ZdLmZq6HC(DgE)xzbbY33xwt2sAKGfT-i#&GlO ztAF9dnIj##1Jg9;f$P8`F$yGCNy7JS~RUjCa zC)4%(FV94=XMv*2(L_O7y0~`X99FsVmBKbBJ~OlwG2ZwbDpKy2f^jK$?v}!3vOv~N z&=CVw_spLjR`GEkZ8|J1K3oJ2WO3w2H+IfThdc2(O~;2A#K)DZ072>`iolf=KQzmc zvP`@Yoh@(SBlFifvgCgbla{x z>Ul@%*IJ4guhdcC1hTAleBd>Yh8(GB?3m$*@k*KCI0jZ$y!b;*fUFqCwG=U4siQ@T zOYC%?`qH1u9H}uaMT}SK7;pkvAw226e(CRKI#R#XQp9+rjs?dtqx0gT(_K>2*m&TG z@k$kf<4FB0|JQFjVKrzeV!TpN4JnpB-I^C0o^hnMX(?j7QpbVg7>=2G_4tX7lx2vG z7_ZdvB4y%9_pkh~ZE>V%CZ3KMuN0aJ!eZ;7Ydhnxs3R5EQp9+rP5>v6W#UP<-;G<* zx~)>)q@{@QN+B7LVu{f0{_$gfais3oQp9+r`1T8Au_e;oGS>VXN9s*2MT}Q!4meJ_ z4p@2lK1b@LAT_B^+Fq%-;5t%&er@P2N2*gx5#yC&&lAXEk4N|TcW)YVq;Aks#CWCV zf#XOWu;l<$e=83k)l$TGrHVw#Dz6=%|3sf7mBoPu95G%gzPVhc7`J?8z9Y3zOA+Ih z0?3sc`TzLg4UW{XmLkS0RU%UCh3Kve^$a*tKhjdfc%`_KPZcfm%5E$p}`J?ws zUUNeKqSix2B#r;Gn~!C8*f0xd-hq+Da;N|AEE@eh+XeiI}(7RMUQ5Oz-C;=YmY(SEseO#Pbg z{aNDuS?c^89Ka=FEBiLIb&ldTKJ2gQYMac{<;+Cz_1i#Z4yw`36a5;quSb70=v2zLb9R`ZCp~P4z(3lt*T=iFLWZhUF+@G zMC))k6&n$gIGl>L7D{rhOE$A}|F2r@sw(Ajmy)+daV!8c_-JD-4medUfLbnaA;D^e zOJ|3kL{^pdAeVY=*=S9uwh2d_8mi;iQpT@Mda(=Jce&c7_tsnMUAA1fIuuJ{D}90o zPO-Ty9FcV{b^oakK?v$ZT# zU^_n8)EeVrNEivCyeuAIZ?JczY(n5soN~fh%IYTBoodNsSVgPS!9ih{9b^=TA>ufQ zQ>Tu5TH=`&&>Z>GZE+k$Nn+1tV>E$n>#h_}ST=*G9XMCd9C@62tZ&9i3LMaMrP#B2 z<`(868n&P(Yz5KkP(!jIT7#pwo(N#E%vsWMYf!6cwmeSb)YQhCaQshBnb}3=Sw?fq z%eeyA#(gNj(b{-(b;7H_v!>=&AZH3(3UB~15^rpd#--vj6J#AML*-jAq2zIjq$yTc z8;eDe_DQR+y_9BGy9t%II#e5p)g~Hv8q2A4ldRKCj6!`V775oiG-0E=ih?`xPS6vh zj+Td$g-wy#m?zLl*7zm_8V-lhSvH5G5!rHY)!9iG0PVs?^Q=$eJY>8!UC_NQI3YZA zX3h19=K4sTs$;rYs_>je!wgc%Xt<^kwgFuEDpIZ$#fegNp=dH$SIgsNuJ+_vZA=$Q zV9#+3C!#XS$Wr7)nfefpX(VbR3D`Yw3Vq@_~GAF5K$VBX+ zk5q?i5n={eE_kxL=Bp1eO7CQAa0V#R7^%a)^Ymoe%bv0(Ix*Ufp?Gx+M{^qFT!-Dp zy{oBA`$Rz;v_prSOg5<^wEA-qbXHR*NZ}|?W4IA}(&J7_@jk99v)^7=ZPl+Nd%e}J zqj>$IiZs^OHamH23!?AC2~GZ2W-r6yNDYqFbgZ#8phLm2WE`hy!0Sy}hLB@`vLx$@ zMbCtISJX7)KxJKBL&z1LXD4`5b1Yts^P-`3YQyg|?BOk)FMD#;jU1^(MW1k!cU_eO$|Oy9|4H&w>BT6L7MJcjfS~Ta*LBiEg7&w8OnPL;pMQ zw*u>02Ogr(oaBX!P}&|vE+_neD_Jg=X^#_!qm~sU3z`XcAUt!qe&uqRaGW9>;RA=P zHJW|kxR`R04;&YGZt{UU6uA3*;En_C2_Lv)fZOX6cLW1>xlH*-Rf~M!SYH!2Qt&j`{Z&A2^oVe$(-AxlH-TqBy|^j*u!JIJV2> zK5$IO=X~JUey{g|W0u_G1IK#xxDVV3z`f-I$9z7F;tyi@8XV2;wOWA(sg zI!jOie!#@T0o)}GZS4d6OQq#@_}O(H~YXL8OD$g+*IJ!`@m7(g+6f9x5WpJtMA)< z;;#0AW4Jf^zy*N&nhzY~_e~$TT;RUv14n)L_`vbIzym&Uzw&`&x&5aP+%({x_KADJ zC+@F4aLkvzK5$G2E~)XjOznucpbs3sX6E|9WdnDRPuwSc;8?zg`@r%2aZDy$hJI}> zaHnYOWc^zA6m0Va=DYm%2*>$Drhbj>W1N$3m&=sT?E1F*z;XWZQy(~n`2KcU9nh9W)NWmaqMC)${1a-j1OG zeiSojEjht##^&O+z2|brH0%isVmtMa1onT`gDoV5zaTcvVJs*Vd&Mn6@x6ADP@JJ( zC={nP=L^MEfDJ;Kc%CB^U(mxs&BAj~D86mi3dMT6S}2Y@R|&;2cc)N`@N5?cKN4R3DzF2*vpF zqi)a`!E>Qd>+xi4gOX}Cz@V`aPj-7jITpcDWl-{tX;yau&lGAqo~TCPU5zJK?SgWP zD|0R=M?NrV0(BFf95V%tuj6@$P`BWjFO#~a$4Ln@!;q1-QCzLxPA&E*BRh25IQcd4p-=5p z*UX8(6{vOs$o}1gQ*G^3G7pw#CF_hP+rX?z`?APK2}Ghs?H`svSc@fwna-{Ev=nRD z7GY6dxL;WLh|NqxEP$%5-bL$Y!r&_dq#y&tNxW741K6Rt3I#0YUF|qo5JQ`AJ(&j? zhGCTkXZw`>Rw@$HAckeDRrK1HT1_$3%Giu-80<1t=!Uk=dNN8!9hpPDU|8BRtJy!g zc4gO)dHl={{&&2}_VuWe1gRvcOtm8jv#L0RxK4SpUfRhsi21PmR2f91Wgry|z%2YK6@st#<@#2feH7u)U5 zg>3IMm0eI%+3YcB1=K8`Yw{9oojDeK*kr|WBIj(RYwbACD7`^VO8WWq(|kMFmqVEdh?5Zp2?uZg2h~r~-M{ z+#nR+zF!dPOgyj0Ur^r0*9paU^)>h_kfV853AGW=D}~~?LFxMrD8B2|VZdvJ`VpRd z>jjOw@%+3{_u+YkP?^HtyFv+*G(G$YsWufHpzv1WRhawq+&J@01p3i7c z7PL?CjM4Tfi&MX=vm~Q`%`*8r{?sYg*M-W(^EIIk!t+)9sVek}@UTv+eN9lxm%|_G z3mR-@N|tjR<;&sJi{i@#KIMC=?aSfW^Ws})`!?FX9PT|UzRPW24)m1fc2Iv3-)`G? zjqN)K>M8LZwSCXEeL2wmo%mjA`);#+S>>M;UsmtOgkt4avA+qFiorKPJ&M1eaT}h$ z6zX<76^@NU;eG;2;qC{u3x7d5rmt|1*f?Sy65l8ARKCBreVNvs;`^NK`;zU;@}c&i z!E#ix|FV7G19h+XPC=n7->INf{Bl9D;RdCdDqo(ORlYnmd#CuCpp@@S+xJ9JKM>z} zwr{EJTLFqW5;RV=eZ#hI9jNb!Z=>zI#P(ed>Q?bR!}e{reR-1ho8rrpv?^AEw(q&1 zz6M{M?l9-lMBA`>VPao^vOb2fW8X-xc&T%#7&e>39Yei?BZ9=?9|*Ru9mG($Zhh-# z=bUuXNoSg73tpalsp8CPKVGBs=bW$`+Z6|fhDGS?;l6>9VYA5+nJA=f`l*Ama?^*F zQ?!mJECZVvkmjo1b8r?H!yCT;CA^jG!(B8$hor&928KGiOq-WM#Wce*oGPdB*7cs- zKGZpUvgpzV8chzI&ABpBhfdnYHq{R`R1hpk8H4a-EYdjG)zRCHQ?LBRQ+|3-VMo)p zS!p&wr8a(TD%;l_Jn*3HETn7A$_>~tdx8Wpymnv!;~5ITwWwdpa3e-EGVC<}pW40! zzOJgu``q3%4SkRRffgumDYsDiB5j&BC6%1}$bIDAn|s^Rbd*O(o0LA2n%q!|Jc4PE z_BOzvIG>~AOh@!n2X&lJ#8H7lODl?^j3_!PzHJF=73C$6@Bd$WpT|y8jKBHK?(d$i ztiAsGz1QAnpR?AP*Yb`fix~i<3FyvO5dv|uMgEMuz zySg`S?&-!zGxO#~bW3r!?rY0=xjLDy1Jm^1`bz& zKR5&Y<4mmf;Bfg67dxc#u+@LXqGDCU&EeE-2PCWGpU2L2Yap?i0?tO72@gIX5u^FV z87T2A*5&vv3QQU;P`T$0W)%imETdS~6m`{Q)fzepzmNQ}wHYj&gkMj7aCG{` zUApE+;^E30D~EmwDHeF>%5deHp?J7j?Twv+R}H)xsNDZ3g!Vyx)sAA>s$Aa%NTRB= zwrtD6V~D_@sM1t);qf5TGor!#9V$FtRrj8R|8DZj#uWWrx6>9&E)T15c>L~hlaYb2 zP&?Qe-sAWA09%GR zv;WUX_8lW5c!%Qd7eMaIhAaDD+fc0Pe=S;^ws+tu4on*ndk4M-@~ALa<>L!jp0}&( zhatcTf|i+goSVP5mEJ*V)iO25pB`Vj*=Bo2LBi%q0zjQO2H9(vs3i_7yM;pr1s$PXI>u}Db1j)>Y>dxNR6GYZ;pTo<7nXw zS4~zR)5)SD5jF4RQ40}uic{b+$kv=p_GsI+*9;u4In;#QKZ0MmxO{mhDqSwFYiQhC zEobuF3Rla0HLG7O?~W?Dhw*o-AP#|AD{{|*;x@Y6`fr!_GN`=p-f(&BsI2g~ombcd zsI>4Hqj(%15D!lt$-Vso$q)&lT>AeAp4w1^ONtjtG zy)!_mv9<^ljo_=T6`-&Kg`5qFw}o(W1gcD^W>5j4@}Sg>)|H^t&EYkm6t*9fI!w3& z)LW8X36w(I14<$O5!A;JTWx&`)L(>p5Yz#o4ug7KsBgQxpMZKzcqc%;D%2Zp?A+eV zL%le+-n|f~hdBPkK6%T=5RP$qW5&&_d!9HI=acT|5!BXEK8|onZ%CZXEOgJGu_NcE zeEEh@Xz7YY_#VO{e%k=Y<2!fvhy%EJu}ec_EexrT9fXpLL)rGOPD}RNmb!7VH9cKZrUulW3lMB9y`~fh1(3vxk0qNCPTAY7GJ8Fj{nQ7=~eujYGaCZ`-}WIDLcqo zyRLP8>8s({_^fF|;SV9|K3N4x4WTiA8bt)+<(H zRSJu`#S#);b97I57Sdq=$&|T~0T}{$2F9=wh0-lxGkGONg;RPUT!TNh;@|ppLsy4a zDeeg==fGj8=)U|=?yZJD^yN$Ohsvak4S&Anx>DIgo0*v^SLql|f(L)wS13(?sB|Xz ztJR|BUlgkJqA-*jY4}6&%Svvn*mPMQR56Z8F`)Wa`7&cx2f0P-yG)|hB2*Z=3ON}{ zS_G7SJaluoS|xp=^!?T~d%LEOoK-riE3rR34^2_}Ksd}632a3rO3y3lo5KrBht_Mk zZ)^>y%_Kxa=nyPV*9{zA*zoP%`P^={7DigjN-b4|)zUL6fjwcW3EVWK1`by@Jl69) z?#o(NkF-`mXtvs#0UT0UVD-J78xE^@$~wVge|GywNEq(nd1-(6RiydK56*pZ;AfLm ziJsz%LAQWgE{{=_D&aYzqH00iEU`AI-Jq)F!7ztawbcn87xZ$gAJ<*N<1zFNLVXex zM{>2CMX4p=2>wXTvb`Px7v!I@-nB&vd)dAM>&g04!d11)6QDYU_cX2@LcNCTMxoBfpkj{I z7DrjTP)k6md{=_HPIyt5*X;7zL8-Fr+F(&v^UDJ2m=szqIpHe z@Z`dnVBp_zoj(S}7ZVsn#z0|x1d6XAF#PDg$rpJx?QzAlC^N}GLHz^OpyN~F4|I8` zTQ!$5CWL-dRFRGZRQxFpj zP#Z8DedPNk55-Lu17%DUwWju-}&F%;-T)4G{7SBBq>9Gu~yIJ+1qW1=90ye?)W!iO(Ej;?dsuv`*z<{<)J>WQIs)JrwNLDhK5(q!{BoA`i&+i zW1>z6$IENmu|_C!2Q`yZ1c5Rp>I`s{PbkI@eE+L2d8nL5QN~173yOS(_uu^*5_a;s zMWZNVqPSJ?#>Rtxe4nqs9?&Stm?(~lU?7Yu!|msN$oBH$Edc{%Ow>$pf&rF+;XT*x zk9w#JIQ0=IW1?n(fO!RI|xmqt;>M4c}vXKZ}x{$C7us84DXWlR)?0`lSvV)*ozU-_kn;>`>L zWlU5E9IwBA(H`CIp{7vjB82cWQ5S;aji?Vj^T1pW)u>UFF;Q~_<>;t0jvs}H)ABcI z6lF{ld&={)_3A?p`LyU~HHtDODlDjrab?(BpY-YZpJ^0jOcbi&YmHB@dM_4zr-XC3 zm>^KbL@^gn9}a(f=r#{^okmf{L|q~%&LD=!<z#!^5Q>!<}EL;)fz<^6SY84ZnFh#zZX=6jNhZ(D{L%d8kRJC@y78)M9Xgfe@|?>+kr6Z*^$Y zD9QlkGehHDK`_8$5zevt>?D{#G2ueAUQ{oNsAP5OmP+RfNi*#j0>cqe-|-c7Og>MWaCGHV8C>D&HMDtfbrI z!InZTL3yNA>+4YWTOlhbdxWdJ06;nx>`ian~rbGpowF;TVP zc>BY(_h%mSP&210G-XT_ni429x`fkTUy%1u^#8~}856}_sD~O@bj9T!>f;(k854z$ z^p)_U56=FThx(aDQN~2A5R{{BZl3mcXbPt_LflRwP{u^DM&7Cy|Iy6nJk(l^qKt`R zn+F3NX$;SN^Y=SF)CV+*GA0U@2a2u4&^~wM6%X|tjiQW+!qf$-kr0Ho_WU*vRXJU8 zDPy8mf#dmMJdyclC|ajA@)|`M6ZH;3am+A0Rks{^$wA$%QIs)JSAgSt)tx` zB<$q1MWZNVqN0L2A6JIEZ+honJk-4!MHv$n11A_DpW)8-pMTgxJ*82UF;Q`Fyb-l+ z=5u#=s4CuSAW+6cHGvZhv@jCkxt9<9z(Zv>=X$6oHHtDODg};r|MmNqc6E5Dib|#gkFEHbs5CgifU}Q!qxJn5l1_icG>S6g zdChBU+tR%OaZWH(ZU);+IrNduH+m`e>Xa#?a{DYeT$;yf{*0vK*ZfPyX#T9o@a%Uj zsOs;Xvcp>^zNGWYS|P3Z>!EZhD=5grZGo2Y)}|kh;k-14Glhkc5E|90IdDB)_m`VS z-gN3|S+g{XGG>c$ba^B5^yS}uzlUnoD9V_qyr7(-yes&?*KEp|sDhv_!j)lo z!Fe}%sE0L*GOBk*G-vF}xEeB^Pv=|T`jk&2RiDPR)t4j8+}D5`bR1h+&z(5!_fAfD zIHpmQF;VPWFR#+#UwzO+M=M!nbG?WlYpML2*PfbYA_jOFh&b z8buis)e259;Ghn?ynCaEx?iIxW1`jzY6`9lh1$cP^H7g#6lGMYpVyqReerjY@jQ2b za{f%8?)|eyQO3;uoq}@8T)KDo(@su!aCbT)5h!D#-UW{5joo^E#yuYDGL52)iMmQq zPF{E2SG(9lth z*Cx;mp;75v3!XRX{`k!2pZ3!EtWJkAX6|i*(pxC&*QX4i_)hNM)+oxDsOt<=zJL3m zhdQBAlrd552I|4PE)IC8sxuIYKp7LY0UU3vPXFS4N3QLg>^_BhGf8n9FY7}KmRHvXO-@GA4@s7z~sVg0TAM%b@(6 zmOr3Tlrd4)gX5u||I{51dZ@2x6lF}*WS5c7pfL9Ttb>tJBHH)4%;9oKfl-4t>hSYQrR)<={Aw!^NAWzGv2cI z>N}|&?fC4n3fm-i+@IF3TnY^dSwW5CSDo@}#*}c&7|v~DIQNa=e0mJ$D`Pm{H8}qJ zxa}y3ry)=5>ccL;Y3HA76lE0e^^>N9?FG_Vge$|nUz`JwlTP`Wic1-Dw6NuZ0cQ~W z=o6D4_fQFqqRe0O5!@~5uxA<0eee-no!oEH=}<=T?$sP`w0wLF$8$p#(x~qkGX6H) ziIhEkcv<3>HBL@&FQQSDQMteArsHs`oXw_;AOFaNT1U!NxCZcJ*d`-$0T7MivKb$9 z*A{kmBis}=?riVr#pkp@b+tO`}Lh|^0tEGL>N99vx!1H zmxRAbpK(@WoqBLbhq>F~giu*f8ee#i!(m`51NV{96p%fg8@sRX!dt>{$0$z#Mv4>C#x+xT2D98`-_7vChRt;gdHVN$1nqDBVRS`fijfJSA$&S=hTa z*2!zuNM;9`(`b`u4t`;qV$Dgq2KK|<7dhSzoU{{}XfhiujLIAKuWtj3CGAu?Ur6Lz zQnoIb(|78V?;Fs6zWlr0%En?g9N?y-iAc=W7J;fsd=|ED#ux{FU?!btN@XJKdiQM{ zSJr7Pv^ifzcX82#oo`Ae3N0D&-|Dq4PXgiaxR4vSQQ`G9ooI%4%TeueGWmoZ%jMwT zS~({klS}esx#S~-bTS@mHoFcMzT=iEZo_|aKHD6L+pyt;Uuso>B_c1g#y^@dGLn%< zI+e*#ybI>AojqIN&y%*o9FV&9V{kF}X->365)rsMmioSZ-(oy_t=(j2W0_<;6KS?# zT`W^t4R=_@!v7~MjLpHDwVN?-3R!fMYk3Su-CY>*oFsx8JLY3)__>Y7oAV&V=+^Pa zS|f7@rpc;)0+;&H+qhRs_&qJa@n|{`!)z5}Wq+%9D1U3lFvasJw0#1)q`i-yiEFH- zt8#71+*qeD62D7^0L`;d>M;FwyA zGu}jpIlM4Vvgzh@3?8eE>|lsZ{i-an4G2_Q0S?;XdwG;Pt#4e3;X6tz!yvn{4o1cP zmPgaTV{~&gFHVjGqPiLE*go)lW>>s>$k?bakH14nTR{quyD1&oo_x` z5Vy?Z=j>Fr&TVQ0D%;uZ2g$VqcvmqxwB4Qakm1}{Q=UmiVOT04IQr{>GbLWc! z{#*-%W^6&QD!9v#32nzTQ8wp|buc>jpjkVg%)_^E9xDs1(4}jjim9^PE_RbbtznJs zfia<5;`vxEk}y{>0gPJ1ifUlC!7{INW3i1L(MJCVR@>GsU0aH6J)P|xZ98}FF#f)N z%O>OR4Lf!kf2&tZ`Beo)H8!@z?6w-HiF7uS&ZX$)ypGPB<+W312P3RHWjTed4Xqw2 z;noWqr&ubQjpZ^i2QF5Rjdd`4Yz!x|7!b?kUpUdi#9&9KMhITm@={5|!Fx29iDa5| zD(dyt#=4gA(s;XcqRB{eDurT6$ye&vWxeXaqOP&dXV>VJA%T&ci{@LLia0O1swPlZ zv5&;?(ngcMiGcZ+E<{rJoMXy%%)n$z!Y^WojU*KKD7W@GJJW>C1HNsbORHbJWnSDZ z;@?Vn2UlfILrP3Wui40Y)b;4 zhEQ3#F9oyNnR%VIvqZ;t?&$8pi1%8nfGHTw;By#GkExfIU8qVx8C{~#c(b~*r?bPw z1C~o?Q!N>H+~^majRa({xDj~!*u}?V_$WjZZV2FvT$LX0C8NE!cemp|=bv=8V{zHI za;LBMaG0NLN#@c8r~C?!x11d?|5phJQyEjb1*nO&6k4K@6h@1&S%8vA<)N8UM!Ep| zlhp~UB+=2Z>U0y%+L>%39gDU|0^wL%TWexbXg0Fq?L#J(&0@V8HQ*dePWh-wPw$w4 z*A&Ap9$!>QH#=ipRDxMT{*~tImCoGZ&5Tz}jJ@VuA>S0wM|B7I-al6X<4>p(vHo=77_d>?twpo&9xs5EzB>*l1t;?z+S=1aHzn+5 zd~!FI!pCD2TE9SVj69$9r>F}Tj%`95HpNVc=srtA*dv~9ZLiQa4z3w7uI8hhMy zG}e@lRy-5G~*KnxV2UD$FB&Mr?D%-y;QTU6{A10 zt_88F2yUX)V(X7v9xEiHY3$@|)dNOFR%GL;d@5In+m2TBLst}<@wwq-JY_q}o1ebihYwUZHY^6XKAFlz@~KEcN8e-@m!wm+TFv}%%ka&PXet7| zO?w<8!&-der;v-`4vveBA5@#n##_=XD%UuFOno+%ZOXS`2k!1@B)V-|=WaML+ql^o z2)J7>#Pa!gK4SZ(w33zGsL~ADHp!badT3Z}x{H-&61~#__X<7TyD_bloxPrE_(c1b z-p!-A@?j8;&Mx|@=yhf#rXA;{kw9;;V@r1%Q`b^@{q)b@Hl1Fv1Lbn+xHOr=XvBEl zwLvwK)|g1I%aOruBauk7wB&Q@?wV^WcE#K@s0|i&wLAxqWmE19gyAWzIJO6cSaYOF zzViZ24m@hrSdSEFryxoRY;z@8+8i$=?H;FGN^e6Y>8hbUI=k98K#TXn7hC&weD0Y? zvOT&1)KciIXl~nev~~9MboV$_!`*CCB$`geZLyKiP0)t50DdOm76I+oy=_aUW&2tD zbeWE@ms$AM%JQWlFZ|VStt_dpQ_}p_$_)9|$}4zovPhjj;}tZV^cHX6Qzi)uaixKm z5ytt}$}R|`M#;&yR(vl3GL3ooJqkJJMRFeMi?39l(FNt4$62JE&~M?JEHZh+35UnS z^T|l$OeTcDgY@xyPtOJa0?5R*++_SM`Hqv`4UoCxucX%t{5_Bf>VmTBCrfW8WG>Ni zCoA8Dz%PN!8ZF2FPL|$Hh}@^;-Y&flK;}U$$Nx^2-j5OaTP^3L_qY0TU7>xs)=bcs zt30y!pE+|?rg(!-7SAdLV6`{psLdyjmakRy=<;%F!g~CM! zCI4sT8Tb@?3N7u*B*m?hK1S{_UKFEJXc*2N;y9vsxfqD3Z20B@p5P!GURCUQE)Rso z(a7Lr$Y(}Vtkr8vSBIysYpr~wcJSr(u$*LaR`CkB8<{=S5wEKoGJOn%TTK>=J z&7xIXD{-AI6fWWeB$n^94k!T&}twT^m2 zoz#-|eR;n(Nc0RvpYWL_pF=N2r(HsX{Kme~3$`>r|Ht$P%5U4o^t?9!M8v(YGZ;k1 zcrTd)-h5^mlxLRyTCjtI0d_T|S64lTYXCn6XQ3&V^61r5MX3_{6!H}C&AiIT-+1^3PkVXA!C|OSc@^=DZx@zm32Y6V%=PVr8!?aLUtai@gPD89nA|zJgMkZi zWlMeZ$hRV1?k(UjOjWt#25(1qN2lUR?!5o(;&W>T;f#I1(AOGxMPgKW;QSgqf6G&+ zdF82j^w)S1Hvk?3-%etfE_wNDN}Xudbh@Ox8T|40H+m;2v27c-bZzQB>3+!F*ZTK% z=5CN*jH|EpHZh^Uwu@P^WJ%2mk>@U^R(3HR(C!bhehB03Vy1JX_`^86nB9o4A0;Qd z7(T}HVLL#79&*kHif7?(+p-V(UmKt}C&FZo5nmY3<2#4iv;25m+cdfW4rWBP;U1G&1mxI$cT7;OG(ow0CLqW5yKg+XQFkkRUGhVa zds)j;m7Z)DZ9zX*QAZC#K<+}M zm!5ze=lRz0bUl_0bxTX2_ z1mxK7&rCp$+xVYOK#uwTWdd^ZA@}A4ZbiN@kJs?;UE*|f0lgS+Ttgwt&Mm_ZQ*sLZmYd_ht&$Fo)zm$H;1c~ zcg}s~tNMG-u6*R6bJNVb_fz(jT@id`Re#TK`meaGFWkTCiurx#4^3|j{^1_T&+jV- z=dxnOo`c1T;48x~2LCYprMA+MYY%ZIx8hfgpJj2KVwi-cU|5HrI>5l4e?`ONy|Z|J zu&<*3wHZZRrWS)otdQOCc+ZQq2M-azg^7U^pW!O}rdV`zTCuOmTGiiL`g1Q%75qi- zo7#Vi)mAz9j}R?AF;obYM)p!S9Rn{wsIQsr=$S zOn)SNAOFJ{hpb$~XOiM99-c;O1OXoSrNu^PJGuXgw!UCu_~%;#>f~cz1rqOnZC>9Q z_SS%ETg|$(Z!!)&t~sPmiqb9${z2*=uOj2sWq}&i39Ri~nf8*bif|J<0Tkxy4 zBDk_w;lmEs&G?l|uU{`z3D*w%s;z&;RmnZ*QeOu}&020f>ryX++JGNUWzg)M5*q@w zNvJTWjY7=>)h-k+?iaZO)-=vQ>pJ}C7B>VZV;Jodrfk1{cgwW^``Wv|x$ckM{SF?i5gxcBPttjdAkpagsStbr%W z95=U>kCYD_d~V>?DZ5sTga?_;;7H#>BtC2SVo;MxKS>Usm)~73oN8R>4WH@^77UeC z=>&RnRstRT;NX83=VFS?8;S)mOU}^~b)0$9vUQ|I4Y$&XedS1H)ur&|dQIQ0kD_=u znM;hcNSW$5#P4L8^p_}-!>8qu{fKi)S7Db@UL5#s*>JYh^hOFo)ngQg7Fgg@Y?!9s zcAUPVbNkdZZ5jS~LUkUSyuW_o-tFP)p`C%gBK}^eyPDnn-m~9=hffqwO<+(V45;vT zemb=336_67D{zby+Fp;H!6)Aw8R1m0Hru#JEUS$UUA5XNOBG#qer@Ecfy1FgI9{z9 zdQU~e?@^?_t4cvfU2H8Yose{##;ryL8ny-oj+E&>uSBlthR6CYE=_}`YxsI;m=)=r zsm6C;)r{hlRn)41P^97OJ-mBt}u`dxw>^a!?i{sSatQZtk!;gE{ zVj5KsJn=@U))_@(dj(xpuHDO_T8ZIjfjiY#5HL}^>VZQQ4bSy_v2+Zzsq#e+C8%&4 zp4fH9=Npt7tr|Fpzwc}wx#3R$h6fL>FU~!JQkARD^kGXm%dNt!;c2C_+*Scl_dS$@ zI-X{ip>ls)P+E7=-=J%8^u;a9z4%p&1Bt%}Rc?I}SEWf`a4EWs+b^+agQC_g7q6sB zE&`sS==M$N?QWO%FQDEhh-pxHN?Yea?E$YE-hSN@fEp0F0Z{!y-3jV8k)!8S*!2PN zFesJV5m0Jt^c1KK5=(!nDt2BFPWps*1t{u@a*G~ORVrO>>;X`!R1dklqo8&R;wexH z@oP{w2yfWs%`S6d=YZm2EZW88@wt}5Ug1(1PMo%=KE6-uV4xcmnQ#$&g)xhDZ(h~#6CKb<3 zRqiuDxHaTRtAR62K+mrF-c>3iJl*AFeL_g8rEbZ%MimKy${j}P3OB$?nV)XJr!3y!Rt z%*q!0l^y&Hiqh~(@l-5bvsOC}H!E~`Tz{R8YtHFPHy#>zbyDAl(1^3(J2X&mU{%BK zhqflqYE?Y_d98uNvyS(ni07bEU%;>2s>Sv5Lh%NzUnt(}DLoSh^;!I?<*~tMB(@FL zPYaK`L>2pPQ2qFoi=OzDP)y+y_*Ki-sXi_|-X-)4_0PDfJSd}5`68%)mDsPku~mj|UZ9i4A}6tU$NU5u&{+ym;v!n+Stzfkmltx9kJlq$hj zK`9;eJ5bj_uG*@E4pqEML8;tgE-wpekI1!x`aeQl?NT>^>Jr{vE_EL$m0qm9i++y9 zOQw1kQGMcr9y51Y7sJU%Z=N&JhO6mN7!#4;>@z+UU2u2f8n+0l9NjMd9)>B1BaV|C}q3PvDh%)BZD z#Vf!P7uQiG?CW^-dUS1c@Ixpv;f|#)klrd2=!0~$dru+W^=Ne94yxV1S4NiiepVs_MISXfUUQJ2XKV6Gc7bp&t6r#c2=4 zI|2sEn5c8X@y5pB+FPM`oV-4!3CaNFd)hTyP}ktfX8zO1%0BD8IKVp%hS^pKD7-YG z-pCdnIsR7(&I8wcm0pZ7+5AJ=MFEB{W=N%o#Jn=ZnmNN$PRMv#Y-GO+CAPPFm($Ou22- z#_ipB7NdgXOQ#I2#XuP|_r>6Nu7>x$X+Z}$WvSOF$}o4{R)CZc8kNpv z;Ci(vo_h)uwv$e;PKPo`M;wsoNg%E2uLU|A>99u_j@|g(UwY}3bUKtlI&bS}luFri zLw(l&{ldR`=^WMRP{wQxYPev4drO85ZNKs5KB7^S0m?VVpp=2C!WC0O!h9KH7fy!0 z+|`Y5YTB?3Xq2@=xmM9OIdw3@fV+`&(w66praea?f+$$>Iu9R>*k#E~a|;ZFnh?Fk zH0G&?9brC~O2*+NMLmQxkSh}DINV7zC2jrq(uiFi&lmE^C`@V8t(+N|Or~J&5N)y5 zqfRq20aqfCER1Z_15h(ER)D2k8b*HOl&CJ6$Yctc7?6BeY67z@@H7x_$-zj9k5G-s z`gkgpj<+-w5UC!l8qv#=`Ai|1&qi%NZZ)D#ZeX(%egg{83|eo?rcsbQqY?=l4{VK? zy0SBTksXlzEo#3~La9SNI{l8va^7MPx<;>o0q2h1v_t#{j&ooYj- zUaH)%y}fH2%u`Stm_cFJqX+TwOgz!Tq-}NbX(pV>H>ESNs92pf)3VQqUW#$pl5NRl zZQ28xQSj1{ZOV!V1Q^T4vqo$zYG;~Luv&%LsXAY6tV5mZoD){qZSsf}Oxn`GWGvda z+_l`PZ%)PIgcBysF{)X9fqM5|0BP3xW|7_R9E91GaH zj5PChs)_Dc@?ymn=Rr(k-4d}7qSYd-gu=1dC`+LzoKU3Gi9`f*$}ERAN>Vnb;}#y&Vh?Ic9Me~mMoEFece`zHrv^zbW18J?r7vtf@Vt#O7~lJ0MLd6aN*TYGXF}x~#duCVQkf9!P$rz;IQq%0R3?mkQJL`B zS4KZ~%v2^Ec>Yh8!NfCbl!>j6C=)-MR3`5Dp;9*OE~Tvb5%alny;5d*4x0O#a!~#* z<)Cl;(f+)8tx|r(BTD(XL8bg#*DK{eeOW30lRD~|H02s)%qI|2Ch=K!gEHyi*~;We zPb!l)pE>sP;&+wFmS@U@+m$J))0HW|-K9)t$eUiUmmt=72L^f->-&oCF57!Y?|^bqrhi~r;%siP zExRV08OmoJu7lb95HRz(_P)Wc{#G9vo=TAc>-YbJ_Mzd->Ki2LtJJL=Aa! zwnChr4y96Rs5$9nQFrnuV?$^R$5U!7tR`#-uBiTIZ!DaSsR3We8))xqYRoq^^bchF zni}%$9X;8mhOTb@GLAt6hCExm6id?4rz#FK$Y zs5xj&`d|iJffQuBy8E)AXwQPd!-0@Dq$1;K6o9?RNI(nUo$p4rv=XoeZB8eW{#;AJq-pmZVKw!uuUdmyi%4Yo;)!Jhv7pm-O>kZse- zz}h0%^0odZ81}}ak(e)?jCmu`FmpOE#0(<^Lw$oo0|WiJJSz?*(bUkBUE#G7VwWLO zm+9~6&!L|{KVUXIvjgeq>Car;mg`@wbsbvL;DElNvwIc1hWa|&*o_QiSG4uD=ZA9b zJ#GED&TLM($n?B4o9jo0;3i_3H_$#fDD&M7FU_^i;i~0yUL+9@`~6Ap>JD4Oo)-(I zBi@|DF&zp85-FeGyQtQNT^|Yh1HoiE;jL?Q_^8e4crqMFd*>~5_$0&4q2@@W+1uXJ zW1}`d5DBBJ2nW4=WEE?#K0lE1MMBX;*vl^1?iGwgBB6LH>Fw(29 z6SaFqf~iCz7*Biix$a)OS3D31Bf|l2c1?Ge-76hUB}1WD(A()G*boT^g3+Lw@^)rB zhE~{uHAMZ7ui+gkZ`S!fMU=}v} zeF?B@vv*ZC*U>-d@QnwW{lNgZc|Z;rHo^sp%5ctI6k<#JD*vZ1w(|B^sopz z2pS28P(P`lS9DWyEJS6Y%My0GV8oFu?NgJ!gz9b4$;yswHM-ke=OE&C1W9>A&4G9v z&CU^`y>nH2Uxq#5&>%#b(IGK@Cegr}(U|4Pj(m0WuNXo{+O$YC9(3s|FeLY(du>9Y zaP)6<#-H}0)kGtSgwKVFXwz?xN^=NfQ#90UQsF3MN+L3PSs3iWIb1r5BJFLCMkC2s zBK~%WP?jA{1YJrf83_f`;eZ#pMoE|)#8>gxYA{tpcP}`?94dn-4S#bqNZ|s#V6J<` zN)}#CAR53=45K;OtG213b!C5VJ4!mzG{31K-fpE3O9asJVo7I(_V#yncdZp-LVhKN z+EGy_5|L00#c1YUq+N;xLK5L1+1HO0$-c&n6+E774yDv^(i>XFQB@mAn;KR%HPklE zufy=(*-2)ax2S1ROLm}Xku`8o^~Y4mQ6>vA%YBfh5n*pTVUR#jkhKh@J8S{uar>LL?{D+l|8Ov{X1`qi{Hh zb`&$Cm$Dmk43jHu~q_t+cXzes2Lb7xH%Dv z#lpzDNUA;zG|0%C8d@+Z0n;GYA~jw8*1)kuIu#10{953FTt9l#!NKlTTGRowGmK>o zx`z=q==1sm&EZs9ZzHmupSwmy6~veE=R77Tz!A71k7)s_EQiUE$>$gun*E`003#|S z+0HCx8=az~krHtPBGf=rBe;j}txL_xV=(AVG$+uvC-qFruF4uSyH>pf^itGe(9A^$ zvz}lg5ssnkMdt?A5u$H@Uk{3`6X}-K$2N|9u+?{2gC|0mL4*U48AR!uV_5@70{kV~ z*L3#|^`Z^PG0x=MAclr?I2BB%&~J*+lJkw>Qe%3V6ya*d9QFF+kit?ay$H-vQbbFF zOS7Fr8KxS!5Z>0{@stlS$Mi-g9-|ch+_sN z*=}WrBBtbK8e-mP+!sx#VV&=#P^Hfn1qq%1dWU-Q-A#)IGuGhoNC=A#khrX+CxlW* z^nEA*t=GWRM3b#Ues3TV4J3S+$4LUZ^ksymbGW@5eGVkd2K2a`-gH|jAO+3IR9vT^ ziGD&Tpb)Mmgv6~Tgm^840~>MFkx4D!MGqDZ#Z|3IIWR>U4L67eE8!vsX)x{5>?J0p zkT(&HtI6hOy>aT2qt2A1)sjU&W_Wb>nO$Ni>Wu~hp|n2)v4Aly5;D8U)yn={_oe-P zc?x@K!W8^u-V$aSQr<`e)7w}As}q8TA%PlsXlh95QfY%a)Ya8%_6>2b8jXZfK3_nJ zZ?f;R3RZDUL<6Z*5RJ#u#oICB5N*^ndN*sTEy7vC>kkFgL@?&_>Kz<=K0&0ny}M6m zm4zwD*y)JRFDAcHsJbmi z&Ap-Cfjou^ZGay&1@i~J!6-%vUn=eOOVK)bRx9y4vun^YM$-;@n`3G?twsYz0Cg_` z;z7UPp9sf|0KULjF@&&$6oZV4F7R9~=gJ`>lxX4V69!I4X0gtNmZ+*REYYFQ=*CJ_ zmQw=YHLOK1Vk?=DHylg{1O8~zN_$yx+Tj#d8Jc}5Zx}5E6b0%^2uk{Twqx z2*FW?5D6bML@E;Zg%YSutp?=cFxQ6qR-hlXWgv_-!DtF2BYFp|zF3-AT^vF|)vjTU z;m67i2$D{Ql4;B-mttOmQq1*Z#4lQ)VQ)}P24g{p+Qzb_l%KRkVJG=eb377`Boj9B zMavY~^kGRMn2dwGSQ(R(PR^My5ax0aYi;R|V7x$(FeaaR0YL~95)VXX{v z5>-P9gG;5@CRWwNdbT|dkd6eS7!nM8t;G}%5Q(N!Sm+CQQyqEq#$=AYRki9>6A5(r z>5!h2(F?1#tgGI5EFMXR!eL7+dt<>U@*edkDLI@a*Foi!3}S{XDa0P^Sn9Pb%GkRy}@Q55{R{BjS)I9E@v?d%3#dT^+OWE6x6;D0A~I)JY73=d9edMxOLlj+74((Ldf}`6=cvbYO&2daK{c>Q$B#|SdHXSyXjco;q zy$vi+CXx}KYch-W`U!6$7!5_^U=cl?QpCY#Kr07vy(<}2;R$al1i3VXH5sFG(B}>V z{j7qbZ4yPM3)NU^p&CNY=5Mp821Z4v8>4JlMW z3#UO4EDeS>b_pC|Bfdm57RO``xD73+clpg9x<5H zd~py9#?tXnJnBb945A(ADbQ;J*^Fk|#VlQp;#l2rP(ZVYMN~DacieJx#hh|0XSHhZx#F7G`gq>OZP%Abm+(aV@jjU^cFha%dw1I2kS?F|J3SbD@(BWsg? zZsjNHccmB!JFz%)Ns$5swNyBkjDwT4-o$7E`X(Klu-qcEWgnegG8_*CRm&b1Cctu^ zs;MCw)GHHW6u2zaVk`H64>CvsE4x@9@L>Q+wzZy@4nc4kY-(7Y>&FTZSQ9dgsJgCh zdxwj_iC8cg4WK(S+8<}8+!W)!6}mG#U`2MolGCke5BM?q2K@;iW(%?e5viQ42_|VU zgg#6thk85uclKrE0ZlfD$>@M6QLU@X0m1I=1#>lP62v8-kVv5poG z#{!Tr&T$Mt+UV8827m=gF&(C; z5Th(|nL*ZtQ0*M3&5%M$_J@#pwC^5G5|G&wx#Iq>*u6CNS*>Bye$-UD8Dl$EIfuxS zmZYM8>!6%xR-zdcV_&lm%T)o)uf>F${g87sYFN!xX)$PE3)~tw=))eK5BrGPoJYng z7NJE`h@uc}!>KKBC>f8&F^(pD%i4VLcq-5qP|r>_yS7Vfz*sPzN+%;Jd*uiTOYj%h z2E;fA;n^AvB7YbgDXKRRh%Q}Fi}h<$78JR&Ok}L#lF>ve?#G^}4+X1to2GPzz5~3# zW*{URY=E1AAvT4;NvS}@zQYb-kV!R$P}GsEY!EY7q!6k(6j1}%^F&@R?(1KT>hX2< zbKzXeu3Uh`20vZQcvUa9nEdH60DZ)!A!QNr@b%R z&;1|QjAOoJjkGx$i!`S(6VgQ-pJlOql$3)^TLVMxRs(FTQEhFNx+AN*Io%MPpI^!T zTCXE($RsveF{Xn3+xtXCYI$TQ1sc{4QfpGS&{5P-6kEzd!ZAAa&VFuG2y&v3#WFvZ zIrK#xXg)wqBp6gNQwZmvqk;0Is9A)ktl`4V*kp{EB8fgMFmd&0sc#orX+|)~38c`D z4Px4OO=9zhB+<76twa<4m@kQS4=;AFS~0qaO-ghp)Pz7z#W0|is3@qxA#3P#9I8Bl zBxEqxYU#?Z7V?J}xC9k5FlG)ui1q#iwsLy06o-{qFu2(5VU5aurl-3@&U(5nOxTRp ztzsnui_qFs%&L-N6|(hi%^GVc?ZW~hmPvgB(7ws&LB%RR=E<@{M*@&`EAuvcA!TFF zr#WV6r|C2svnFLBe^F6H*q909B}S3M8nc>c4h5hOV3W~gK9PShT|#?lNnsx@zt#+h z6&@rvl0wXea6<8?!Bkw+n$IBB%d7z-6vV>dm?Rf*up1*|6H_ciCFW3Q0a8|x-JLaf ztXYjh9U$iQYcoP>tmq@2vw{Y#A)7H+#iGzs(|ZYfMQQzn##h{GvIa(1iX5lId#fQT zotfdFkmU=d)iAmyvm;HX>*l-EknCVlMb_YIDhY`uZBZ+;lorY=Hn({U`r`3pxH7~*A++fisoLVbD;n-#y*1)MC zb{K+jEE2Zo`Y5CVc}O4gBtdQzYZF*AB<2*&P#j4o(_Uj|%`(f;WRcEptWP4WHCzuDk=G#BYeTUBq$Y|?lvP&rq3Z@u z7!nAlP-yFVo8!d93=Zu&NVPtHG@{k4&)T)2o(zFYhM!MRJI^E#@rDE8U?hoIk^N<>-sY+IqC>yce})2F1!>6w*_=8Kal33ToZdvGtJVMiZ7w;z>xg zkrWq8H5JmL;mnpE#2R22+n>P{sQW`|=Y6^nDJq%Rys`LyV23fkskJLh)L zSfpgZy*a4D<}ExC^QHrSOmd*!($d@C4-rXIXF&gLsy)gs92=o#lvpiGfO|2$v##+# zj-i5rDchoQA%Ss4TrQ6cHPu>a#3DW{?Z>e7#!=0^#ScJH3tbJW)(i>7Q*1}3qyCV! zxjU!7x`febHd|#1AXTHc?eogY8v}4(7w>-7-;8~5fTyV1!PWEtg(jT!4NbE(qnOh=p+}h z-!Vf%5NP&c?*O|EvJW+67fK-MKiU?wGV$Rv)4HE0lPL287sesPA^R zLBB8$OtDCgWd;pzU?qg5woY`xLMd2;g?{^rEcJ%%B%lh0)oXzZ2^dL{DS!~1X_JC@ zn?9=bX?}g#)rb;vOH+qgj=bEU6%lgh7PQv(W!m!nw6Q?69JjB^>W3sW7i>9e;WZJo zU(W{$r@gyxbpFKh_h@H(uElP5cTZ1S2ab=({RA1I1x-5iwqKlW>qHskunmtx5FOYX z7iHGnM^=Pi2B{Y=BHyC4=!KHg++}sylEnB?zuo<9gE<_}Fkd@S9`c>5kb^6=a+Xe_ z>T~U@+qnK?apGzl6!oFdu2DjXj;b|L&NgyVktGODu-0yS2Q<}3g=QOu&LwvDv3Vz> zVN!GbYe%7K2`7hH>8@-aY!fOo=w+a852YnZMz1gK;POn2?`x;+2m(k42wTw!PFOdA+^z*ZNc?qsXT_GztxRH0d@odpp6s-Eetc65~>z|Ayy zM25)dhIu$dtMpknW3lGSErV!WPC*4Jj zX;$p0WZDE1TN2HEmW*3oLHi}oa%yVhf9&RXjeMXWP)rbyG%D_ovY^5;?Lp$P8*F z+ht<{)}d@6dM0FnO4hQsIqBwTbh0r8Y%DLElAWO5YV59Bo3T4md}6PwpH>k~Lq^`) z*0EM^EV_%ey=ZP?=5Ni2ln|7CIPYBBSg)OTUZN<<@OnkL`bI^0>^q8b%`X*Y!3>X5 z+vicLv*VOEZW*V1TPacAC@WDOUS6Wi9w<>7uP;&3yGoS1-Yij0zN}Q)`a-Gl;okAe zQ-2t*tf`!!9C_*lr6V{&X*_>|vNAV8`Qpd~<(1D)P-fmSL8&=&qVh=VL?!vziOLUm zOjPcgR;E1CT&AqQvP^kx?m^03`Gb@{e&ZnJ+E))!9yy|137%W7T>q_d<>jB2E9#%h zm20LvjaJd@sNDoz*uT`v!&KzEan?`Hn=_^Xsj0#C;_ z-HC0dz&G9BYNwlYF9G+>P>vLThvWBf{56Vasxkq8Q}I`+R4At_4NARonzBeaQCXnO zR*qASR^|fpcx9ndqnw}|tIStsDF-Xn$}viNj4AzbKl2+}nRzjew?5#|)6 z;8?uzPr}8Zbc!gCla-S|`BXgoTa3RY2+iEdzo{sT$*58Jr|FkDwE#8eVuv~3i$}f2 zR+0O6I0&|v1G4k~X(z?TR3H4eJ4aST0ajz_cW})3z=5=X%z?B6`lndo$YKrPfc|M) zt^eO&|MXouUip7o)%6{pEIptdYgO~!C+*n%xL4zVVy!$2W?kLguggXbDCJTOVV{+9 z_vfaTr1yYI@4lYW$5Fcf+seTEb;*zaz$FJRmmHu}4yaiF?^m(j->WS4=X$L7j(YdM z@IsD#)-2zTn>>QveOF80j~mT!?sK0t+V}Z3G~6F}Kp9@w4wrjx|7(=t_wPQMeY_+O z*X!-;O*RMA_YbJ=V@Z-4X>Mx$h8`1+68!H{-{1c$oDLiS5UbgmKHPx=0NTzHPAmMI z9RS$hyU6zWhE^U_{}*3l_71Oz)$4e_?ms(l;DXA%@5uuf`*kthew@|_Km+(+d9B^Q z*I|+O#3g+DbzbFPdWYXTzlvJx_IQc)zwVgLzF$0uNzT8|5uJbe9f|vOO6XsFz2d$f zQrf?Z8F8`Kfm2S78yyaua>7xp_tX&)6wCwf7oql8JJHElwdBdo7qo+=aY$^T8Tqujzc`!Q5*YVBbT#wB8kOL3l=*iIr`+-=)*;pvx54`DEnC_5wm{2&2bEK z^zlLMq?LY7QUrE8edTg0Q{sxtyv3!zvJ#7&>U28*>Nx%;=!w&Y;@dOktNCp!;cI^S zO1$DEC%(WXBX^!9l_!!+a`N4zC*Mti@?E3I(^+l@tj0LOXgL~(gI?Byi0%g*T~GVT zgL7~5INeysV!_nTy>dA z#pv^~t_RhMocPq7eT8@g-yI%2$G|N}RjEmmh8($_gK4K=W#n+gZvI4Ij5U=8P z4E^-1!J_ZrTW{s3IX(=$_wNEPtg9AgdHLK6*DRQS;Zj_sh)X>$T%8kR+1&n)ixj6% zt|#m2j?vK79iyhJJ4RO*cTsI%Fc+^}XR$=#qfWT8C9~2skb8P_o$l$)b-JfF*NH}t zx^j)eJu4UC;**|1mjD-us-9QWr_Rj>eFV$K%?o`oKAup-2Uiz#yLoX?!2N8+yzn`T zVqRT?#l3o5y*PLmAxN(x1cjG7L2>bjTlzW$|G4_dxrM72?;gpxro2Xcy;#`NrV`%T?0{SaP>g37U2mpa=&{L*nJmC0&k?vWn80zSEoBmbhZ!R zDjioIqgQXYD?5WP!L)8sWs28fhBsxnr#(}&4m0B79M_oeWw8O*c9W4a8rMK_WG~`X ztadY;u(*aPR=Jttm76JAx$r4gxtZeCL@&LX%1_fjC@%+%YGZuSMiI@q8h2bQSg@cP zaAB=}4@2jbvy{P4|0cAyT2V5%lYwS#C%CFAus4VG5|kDr>XY0-VI z!&mGtcHnuHO8?wEF0s;)0H44!u~Jd~h=-;GPjzK_xs%@2xG$l!N>Q#oSfJs&yrOt3 zL2p1@T_YXwI~mVyz}c?hk)F4*);o8N9gopH1)RTXcpxwF9O-L=`y0Ty;1F0~i076* zdSro2uJF!+SGu9@X%Q(c2BY-vj5rr;SZ-IlM~_Lw(_)DMs%N`1Jy(`*49) zG<{tl@KNBrI$h$S8eQ|d5_lIJp(uAB>7eIQAI}2kRSj>f`j|FDQI5w$W8k^a3jinO z#BE*m+36zStaswMQ}dHdgt)0G!t~ykhBN{T@** zY3aWreX?I`)!ovtoK&s9NyvT;{pxAKP}p~NycOS4IQ>}s1QM;s+8tB)>WD89YB{!= z$$bgWYCKC64>~qQ={)_yFz#0$yl`M}-i4glpSqyqR1E0CUR3m7s2oC(2= zh_5Y>il>&gr19++Tuvf=D>UC!sx9G5o~NPUzLAMl3lZ3Z8*y6NB1?VewFG?e5N<<} z?&E|zuEE63B@?T@3Ct4}5luK654D}UG};=%Jt}2YpM%du{G8QxFDsh z>Lc)o;nN*~X7O5$M8{Hr)=(?1Q7NnXsNw5dinx*5vZ@Y};&k1dYvU#+Ub%-O_1D`s{w)f%Ama-}gqRK#iC1;hr9S}IW`i1iY4A0yM zd0H&SGR@m{XZ`Xn;e%Ups!oAVtOZ|UmLMXWQTH*)3~iEOD&Sf@K}!SU zn+XRMfkZ9_aU&m>&M9JxI%bVs&D4mTo7JEd;gRsZNe|3rSA40m4p%Ivzz5T(<4)?=x7dpJBWEaa*6LkO3rmRXc7@!D4T%1C4^!d@S%RoT9Ti3;yhA zvbAo3VDsbf%B#qcCzdD6Jm0=T7Q0KmjOOdH%FVsrm^il27;@Fpf=`^IR)Zm2IaDTk z2VXFlO4_}OF%pA(LoW`k%(d!dkgw}r@)I)#;|?LuF@8oa*@91-<8Gv~D%KD?3c+fN zMdE_dRyDM=Ey1*r9jmp1YZRqh1{|#sfhh!+C@%x!GZ0tsuT**({kP3I?U=3!=Un>C zxPxCjYbQhw;r{yl*%?1rIdRdUCx79$kKCMDsVJ&&KkxO;Es2MZKCJYvWy#eeFW_pj z&BFcZ?vH)-n_JhP^uSd=s{TdAq*oLLq(J}7+pf$UzWvjWpZCBIqyJeSJ5^DpA>vBU z)|dbKNPjT8x_64_4^6L*&nU|I!u^KDJ@+K8f9sX|K3-QBzU;zfit-iVzU$J=xtq^9 z?1@`kThr=oIe1xZ|rgWpO|~c z8&`gR)@>Ehk1lHYk)r$!<#rYPH~{jxYL@{J^Rk|y&g|TkW8h#%q^o;{L=l~0dvCQM zS3P@8@|i&+_;U)6{`pHL%1)qy79tQnG3ZDF2qb28zuWmB$La7$l!ib8Eo&_ zPYSDWKkEJ`WA#7|>q1>~yZd^^D1EuwGe-Sna0?^8$+w?b63gEEPXjk0? zUB$Tix=&+Sch1)rc{5`aJq8^kKkig6;yw47t}$cEh(QUZqIg@>k>|W>LCoIO`t9nb zU`=EF*3gEnYT;47RP$$c7k+BjAK@!(y*F4h%M;uftT}$$?lQcbI34yADz^CYc&V$# z%bbEQzin3;Y^TC`4dC2@Zw*{V)_Og7J8ft(P>(IaPi@(=GZ58!;oy-D<@6j!`}BAr zHvM*Vc#66?UQ-?1?62B|7eyV}eQ^F@wNRoKe!9au`$RewO7>K$g?LS)TK_W*X}kA= zyAOgNC;g?$ckoLwu2lI2eldB6O&84X#M?ZjLI~!t3iAYhIUWBQo^A{@nvuI3+J4qd z<={%M?qi2Yb-8kSRU=$e9uLw`Rh5RF0%FP|$11vE1W+g>q&)bJJEWY$;kF!Zc|0jk z-%zi%g$uc}s;U}}8G$U;-L*uF!75md0GOa(Xo-uqGU;=O$FbVh}z!czBfN8+10nY;bDBx1S zj{~*u!waeLK=oCQCO4G zRt8&za64ieiY7OXbh3``zp40 z$3;iBl|)CjmiR{Q+T+{kdy|fD!SWU@Z^E)?=vTplzmZHDEi~5(MtuhKl?(7lR?`{m zI=IYtFjyN=VUT&{B&JImT#(#0(7h(xBb9E*V!GF8NETwYoNUD)R<=44c+=rVsVn87 zHcuO`hwbUkb}Hl_GEW+hZkRSQ&qTnW=GcWwqO}K*`RW6#2J8odxachtq=wE;X!?PwEEaH^k?_dS3%WY`k#kOy`%KwaHAo+ zJ4&A)mVY-3Uz9#mtsAC|rO$SarYa1Y-7qbe1G4l-0ILD709*hFQBO2oG(%D9T*;B8 zPMa)s>Bdr*ZffE3Yw;pm!eeL%YN0Y(2vnmzB*4)5lSKKmQOF03Z>xohEt4yK8>4%M z{un9*8WF_N4lV?7drf=^E(;wsu^etRY&DLW=)~7R1_m&NWR+lQ`EE3YQMIug>2lV_ z$56^}Rv@SkvyFhmhHC-Q&WB@wUj$@+kY7<7$HFdagSK*obs*ht(`>kGc;va+1$ZWxy809=_;WZ4yLv^A0t-FAT-nT=EZ)WXbNEAbMydw1L_@=fpwSW+6fni6s z&%S$P_qd7;Y}LbSJCuqm?qz^Y`5Ld9xn(2lm%qgc()wv?!Gi&`0t^M)rhz&5-BTGX z+^ZITg|SuL)Kk+K-_%)CEh3K>R!pydUfuA@`m@LpYGH)j6D>TV7Su}c!buv|=QU@r zQW>0Qk8&s?}qJkJf+HGhV4beR)NxEEtD!J!zSs~!N%Uq6e~D1E^u%= zm)wywxDtO2|QPzC%cAclSAdw}NvZUM{!f`5gG@B={f{L1Zsn*i?s{13o8 z0ly0PUx1*g{0MLd;8wuj0&WAGjI^Mp)A)RYs$otw#jf?gr`JVj$hK& zjT_y1c!KVd3Cfb~rOHBFL_WTg@hKuSVI>|J@=(J@K9X_3Vqntl7Kg<2RE<}vaGCk! z`4f~d%iY`vIGhx+zer79wT7!b70BCoQ>fM_{(*i9zCS4s%|?m?t3wTSO`3JDH7AAu+WH zH=RWxp@Ky#S@VYZG;H+06wf-Ayfjk#SXW`AJ~E|_*}C^A=++U7PM7Ss+=9;d$c|)# zR?Yn>up85W5*n@sd>+sX_#$8$@Na<3$*X`L1l$eyVZhe_KL+?ZAlY>p9?7n>l~X3v z+%{@9ZtN-w)1aH>ut-LewlciGU$}W@j8|rWr49y5u^(XyW6HE?Pc1(0S^p{JiI1;; zWbSRP1IN(4_#z(GDa0;TPE%l8m1(TS_I-!)l9vnnbGtiFyth}`vxlj$svWSJOFUNQ zhXagNMF7nSI8-{Y8>_lOiNJY+zj)?_8_>o{+e(KyDDeno1K4OvM0Y_O{b)**YNpV# z5y}pw#KQ(g%HQcc;|VjA&SC;bv8o|V5TVFuOvU*Z?0MY`bv#^X1dgzsE`Iq_jn1P> z@T2ZT7aD8lBVFF7qli$}(wGRJ5)XNavETj06B|aC205U_Lj*nV7^~n$!+9gkL{LU) zShm5*&n2EXeo1-m`PV@76*h~C2rH_@1MW2_qr<`*%@q=$T{tOEf=`KOIetlR{)66{ z(Ue6kc;0}&p5{pgWwsESNuwxFfoq9}5&={8SaQzd(UiHfTH>MNgHCyhLHP#w(M*w) zExb_ySCco=C6`=jhJxfIjKHz+2DzfdBYt5!H}=DBGt>hzkhXAPJM5d$vItOd0*lwis+-ddWHs9T3xI)NMWnQ!|{h)clVy$t)px3Xo2%Ie)Sf| zPo+q+M~nR^5tp?U93w*MHMr}}(D7!dD%maK^DB(k+8bAkP;7BDSFOKciW%x;EmSpp zm|93Jnv2Y7O*~0qLm1|3fJ{|n^_JTwzcCL(QVY&-G=&B;}eN?$F{ae zi`w4T2|bR$%53IhocSBfW`^)JGknvmzyIRytj&cey1Qd7k+0_B7T@d(ETbl&S{fT_ zM*Bc*pu4Ze%}3^Ie$g;)J~GVcShVsOfpNgnien zlGETFh`+dcQ4y6NrxK1`<7O|)GNTn@NY1L)LXE29kgj67B}~-;9g2UJ4#kN_XI}W! zq!(8&4;-AhdQuSL!b}V&ZaNfA!hN(3MMk*0>riZf-x$-c13DD@q7ZUGhoYFCjG=R| z&&oFMnhphf^mkK(LdvV}#T60`#dc#IgxP_(Nvf2-%TH^tA1&FNG_j~*k#Tad^U7m{ zG_f0Vh4Z!e-K2@6gZWfGs6_4_fhyY0_VpXUNL%DZdG;y z=U1Ff!x;30$SK|U%L&gO;7sBy6o!>q?BvTy8je8J@f`VG4);aC`>cjrEPc%HSAg>+ z&dFhn^f~CA2frP_sbwE58~r=CN402y-0*W~}n-1J0!yUa|6HH}Dw^M-aqMv6CP-I`Q89 z*@}KddVgmtTTyQMNf3`b>yb_;tS3PZ9Q6>>xqqjl9?sdM%h3V*1k?R!01rJpgmwX5 zlP5-aYT;jf&f~z5j(+nfjC;N9+mVi))|%GNZMx9p0R}>e?($X!AOBbpIu~>a|FtZkRS|)=R~!zAsVFBL4*0QJD2o>!&L3^)qE~DY zYUnD|(S0M^a5TWXXXshIV52Bxvv4CK5^Ldp0WJ*=l~B$dX~K9cg)46Od)G@BY4|H1 z6_0M1J{B-nla^?X7i$H42_WZSgMih5dB6t1Re;RTYCsk|=i9R2X_E@j((N|QS1Ldo zD(TTYbr)4sK)e90#bvAns+&RoYYlY5{M89m5A@aZ3oI3bGaFk=)RDVH#i)h*{1sbD zr=x=21Uv%pEx<*h!geOm5Xv+Nn9N}T<)w+$$_jMC`k(hiGYJswN- z*|t}6D?0W;k&Mb^ji74P=;cWcFWk7_<#v)oR$m&vx)DoHs6I}qgPP-qP%TXJRe+NK zuL1M|egrT8_%XmmYJu2R!X+PEYjH5NQ4 zj8{&`mnw(OKS(MW{=?2A@GL^25J2r(&*h+3aP)Owf{RmmbvfKo^5l>6 z;Xp$EP^n(;0r$X$rqT$ddUZ3F`moS5QL_XK(KQH~N8_5lBUn?t2cEl#LHxVt!cvC^ z>d^S*Td6pFbc(Q%EnmU|79G{p&J!3?fwGwLJO)iq1W-8Aw zvk+n$*c+0Kz9O!B&Kfb548c+H0o#je;f$jAltR7A-lj`A7 zVJpQit8oO6vxPMajJ>Fb>-9Jr$nM5X_tve;H1u)37CKA=tC4#PtP-00Q5{u)4+2uN z=OMt;03QbAV73#G)wKYRtS;JQbxAi?mvmz|#-SU!%IcCfRu>0To;eujsva)!CId&> zDq&Ma2$n7B>&A_?AD&~YhnrNTjlHv^Pr8glH*WML=9uc?sdu6t9$BaBhO6;S0dzVx z{cvi94}Y*j8JeMPZf-QR!99kWd2{u%NlnL`+T%h53l@F?6>>oqdgMl+K((NBkQVmY z!$v;nH3)5{Zm6PG1h>i451RrwS>;eTXM2+h=PVehaDI-kU4~zZlcmb{@mnEm+wsey zE#=V`(Y2bQHiy^-hhjP<4;DU{t(ao^zBLWmoeAmg%b=|r#>a+0#{Y!o__!kbv!?*7 z;r1s$FW{d66M)YGo(1?kU?<>#Y$2CFVyn$bx@_0jS^ANbwj8_6+&6$rmFI>KMkkMP;o7kz_I0Gk_fdN zzfAke-?gEkJ9EJfyrhVVdKP{(#Z=Te-m|`s>H6@GMpK?jUk}=zQ9h=6^=i1%>`g`e z`CZ*HGZb4D4SOzo`Ec+lF;s)=KDcqA8S2aMqY*etm%KqlIw?Yx+p?$1UZ%uD`ZST} zKZkJ^!=Ere&>(T30B#9&FkH+~*WLGeyBX>^EfjI=YUAX-y{V0(!hrK@{Oa6$h{3(b zuqt5=K`u}l79OLtYw{S?#?4SX21+AvY)Z#$vn3u8BWzR~H$%m>Py)vm*Wn_R;3C+l zHg1Mmp@kASwz#H?P~sOhs*RhWKBR?`zSevlVT+4u<7TKYXrTm-EiN&cGkAk)<7TKW zS}1{|yi>LD86rLG-PvE9IpYgo8{GoqvTsKE!d*k>r!nkMgiNh^ehj;hN%xMsu{gn}#+67$4I4r+%)-u4rvZs8iWn zc)9C=TS7UNy)B_!y#zx!bjL*)S3Pk0Se3dh5sz|q(E%61dFNbF4e*8YE&AWM?YC~> zyt;0f#;^P1z|!d zpga5nyF?f^AUBP88*egV@npjGIo%x8Pp| zygN1AV(EJtcsqdeO?JaDW2J8=aGuccilvYJ%bUQN!VVh7z_avUbmy3G3UC%W@freY}F<8Q`7CAq0lqwHyDv2=}GH@pC|c87qCfm3NhfH&*&S zq2Wl1?&-S#>AL}VdpM-Pke*xm*glTJ0P+V8A~0j6Z%Va!^X*vaTL?U>aVx(iK!{Xh zi3bl&vGUsvzfV_VL3I|f#!lY|a6Y2pjg`KeG#p9Mz5M*}yc2kPEcD#U??K=lbu4DH zcxc8dziG$eh!-B3vC`M1;YdvP^zqu26!6}EqQp8Lz%6~%DA)&QW0rlg#2YJp(@(*A zAs(7y>0^K32hKT8JeU3;4;-BJ|iF+zXs7OaP2Q&!zl+3!Fb| zcw^N^*=drN{_B?C9(c|K-bM|VvvW6oVftSO%N{C!PzvYk>1PC!T{I$Mf4X9GPSH_VyG!w*v2aF2%#JT-?fU z4l4d9z?+*j^O5_1DBA$iq@9pXZ&xp zcC?^Tcdc8`WgfV1{B7Ph?pB!lpqxsL=3iUug&NJ&G3A;eu3@jAhux2|sv*4n6RsqG z8Du|$A%)_^0X@}y)l>cCj$`MlJJ;OadFrojxGM3d+Yacd7QNQ|fS&3BJ=M2)|NY+e zR4EO2zgK_9`ZT3UeXxp-lRq@PLvA4e|(8_6@qGp;~)y3QL zhpPqN8&|f&r(Fl$j5pk6x+Bmk&_=dbUvT$H?1Ax^8}Jw5&3W!|LFIQUSCOK{8%CO;fg=XW%rFj&Wc4Ep+a%tlfszSJVCLpEr#^DxO z{r1ShqlIX2=Tir@cnd9!B@d0fR<@}nSaJ0SfG!j~>i6(A*pWc1hm}#WCE(o{JYrd) zrSMCymT#0Dx^|~4^ za~x{6-+~*beAnZ7(yUkQ`_f}v^H-!st2FJ*Jm}#{_x{eTVrUwnt_;I?S;s8nxaQh} zx|s;EH9>> zAp-}N_%?ezn*wowak!6C1&aZA!P%Pv>2;TxcV7RidHXZS3CqXqvxf2Jyv_V^fq~<= zfEM27O^f)B_8`8X)Ga%$*+6hHs1>(P>ku1@cei!mD;R>w{|Xvu3mwK!9-jyp)Z9M` zUM1Ine}~z(d;$==B!({WXYtOJu`dAr3h;}7a{&2B-lnZwC?!cZmW6bKMPZz}p{wL= zX(N|m1qW_Y$M_&uUO~Txdq;OZCD;S~+vYpb z9lczk8L3rwK3US-cu>GQ@;_ypnuF_l-_?E>@ry)_Y#k@kr(eUm5=AYUvz*&I>ykFQ6N{ic=47Q(@jZ$WFEKYsO&J<%ml+jGL^=fsex|&DX$slL2o81Us_Z z6qi=t1PC{A8TR)8zl-v;`HLbZfpTx4CVw0Ij>kE{!}6s-G0K#tCL0(yYE74RIu zZGdD^KOV`Vv`J}Ex?Q39N)}~Yx}m>hQE4NKGF|9hj~uTY>Bgdk#{^@lh5xD80xjHg z^~=W3oxbf^d=%iP_VRy*F;Ny_gDe#vYmqjV>`Qo7;hF1@=avXuoY4UMJu6BYDzmKa z&vlN~eINsFg|2rWL!gxMtd`=OP?&AhsRJ@z)&kSU5~cYGO7{@Jp8|3h_Gf_gfEbTO zsV88UrB0ia*Q6V}2mtuAGMB=BU3Q~Hv&GYy+w3zx#B)=>-O2>PFf$I_Lv7V10J=CgzQP!E;1ZhTdH zkEJHOh(|Y!n>8^WaK7fa6D7`?cm$C9=Dz?Whx`(75#X-?S!-_lhtQwu(P$0J`ez%OW|N}rS(Uv1;zLthYzPU72l>bKFSf5liAzHAu@iHW96L)rUV!Nxp3F| zsX{`%$MewE;No2$e5LSno|{|F*0-i`&yR=~=Z8Ob{%Pb*&krJatw`Rb7S5T@PkU+n zanAG~MB!n+g>7$Se$$Vml=;@Kzr_phM{>P)NnH{0}SL&bN01+QwDXX~VaAdfC&$Xe&f3Mj55Ym>| z@N~r$ABROPglk9Ec*hMbixx`JLXgsmEl&h-AaFL);@i2)SGZ45Pv8h3bpC~Z=_&Br zxy#~H>FV>$Rfxet_koHnGiUF7wqO>+XzR1*_%?b*YSKOpNH^v9-SlC)IZe%7rP zBZ?SDEsL6E4JLlRi@3!Wt1estsARERI;!TR9j^VgUiiTrX=35%7kdQ zt;YgI7z-5Zu|RPxzhpDO!=%e`;%(X8HzMJ(Q{7_Nwi~vG4cn83?JtIH9C9tgRv9*m zCem%bVdEv&((OFM)@j(jZ`d9(Y|k3DgV3?au!kD9V+`AwhAnE?S`AyfVe2t$s}0*1 z4cj*i+pUJ}M~3YuhV8e8?RmrI!PdG=U!`H2Vc1SKY(Is~F0y?V!~S<}y)Fe-0nD(nd5P zTnwNdbi=f9NTZ4jYmer)7_yk&Cjn0c{5>H1QGG?(ltpe+R_ysJsFQn&Pw$aK$N|X-LCsaA%s{0$d7+er5Q5 zOdC$=hzs%oKY(}A9|q*L>m;Blz) zO2Fd*4+dNYcqricfQJEo0`N${>j7r~-Uc`m@P5Ff0AB(;8t_nXLN(wqfX4#H0nuuP z`B|tF0ND?A;*mlbZSpbz>2|B;3$Xy+Db*OZ*|5ntVG;2X(zwMbF+Ed|!p^Bm>Gh~qd_+tw+?AgemnXCfAKi$sIA9MJ z!&h$Vx84q3Fy4>U=;Gs8hOHDf3i2PqW&QrZC zZ}(HZX$vK$fjmADFsQko20o#69^gTM^?-)~HUJ(0xB!qMCf`re-pN;&;gNhrn>-#W z-LBJo#a#!Dyv2aR+A>Os7)Yj5Xq#PFn};-0_-p>qiYw zBIW+MNz%~`)5g-b3i3XbD!C>MNREmC)&Q!25x^KAOM4iPEN$9kE0%6-#nKHHW9gmt zVLY-GOB?xyJtZf!6EUG3uN>StL76gtl2Y2i!q>M#P(N4zgP?{ft^OUY7E>H+nf`;t zpdxDwOB7Da+xXJfbcFZgDOHZcZ>zA?8Mf15`;u@A;P;EdR*GM?tPwoUgVsF)1Gi=Z zT3VL<)P&x&W&_FH=yPRfwUbe-)ov_WEVIyI8d$e1W7acG3+k>4@La%|fRI?k$c9A+ zaeD|x7x6vX_XCoT@WHp?6@beDS?2{jvd(FfElj$R^Q9ZZF>c+^Ro1z*F+Cp@Zp98@ zOT5Xzk+w?MxH>4QkiKr*Xmi9J`vA5{RoV_k2uYuGS+BZrqc1U?2e8El--O`myKNc! zWXZCR@(W$N)lJK4jT6(jtAWi87?Cp5T8T?Dc+JD%_<*G46U(n)7!;pa9=Xix89Hd> zj_It?^@m=5Sr2>udjlPw^%Hjl#0x$gDHwm`j$x4ZSg5?LQ^96!85Z;M@{?cUQ(r$7 zpZY=z*%6ryicD6uTG%1iD)$ z#P{Bcovq%t)*v`vUcGW7;?ND_Bkvy!NY13`1`jih{eZ^8y`hW5{(z`%e0-T1imi%9;Mlm1o1`V4$MMTLsX6|}yGPd!#~^#{R2ZDV z5r?K?RPB(n%v`i&zI&D#>Z>A*y#K+T3-(&(nfRZ7|NKvxp>Eeg2^?E44iTZwMi$1w z_W1Vm*No1Es0G`}b@RmVgBs<%ow`2km0RvGLp`B|n#R~|^-hW1%*D&=?ptYw!pv6~ zfn&?X;UW|_LC7tSe(8Pc=v+`%EAd!+fWwWtz?@c?!$;KxXAWjv)I7cT+h!=tY=sdx zwp<)3Lb3K~KCu0isb(n5Q-l#Xwp`4Bdx>WWepwecJ-ZDeBayA`eWt+Kj$ggK%QMZ! zJ_>whjLOAPB9z_+=Y=~SHcvu_wDbrZTP`?TGV7xJtV2f3P~;dIfwPwn!W{#=5|5w1 zc)tF?PIN8Kd{qk^a+98~V~pDA(&9QssV28r&YjE>q4a!Rd(Ukbo1rj53nOrB`8rmF z(rah)y@~%YLyc&m1dgqCjuWA{y1+jCo@erCibS^7PL05+M)m2rIL^q$r!>mPDb8Gw zp2=g^KfLtUW~l46Py)x6ixWgBy@wq3c5XI9as7}+;Mhv+M7Wx9edy*L!)BHbTLoWN+)MHA8Xb zlSbg!YUdQVmUy@>K$O>i{`>i(Ye%HtvkU%u?VMuN&QTiWQHEt8R`rzl)$l-Ppt^WdZ+nJ@{gY| zL$zq31dc5ib-*q0^x$_qp3`3c_S2(tF;C#Uh+n;Y>Wo}mq*1OLl?zJ2W-fNW&~%3x zYMmBJ;Mj73>Om--dwIKt8S2woD1l?+s0LeHKe(^@95d8+wNL`b7S{q1O7#D*@pcU} z)X%k00>>8DLR(zCUBe8uOA94%Y;iS;P-Xa~;q4k`D6Wgs2%L9(yT&4fEb%;rU)IiT zZ*Kg?=o&m-;LHJ|>NU8?s6np4(=0*_+Hcq3Du`KwGmriIHZ#;IS}1{I%PGexb96X( z&hD%k%CChIIE+*|Uvp7J?6_Tng&+*`WxrkH47j-6uCWRDlrZ8aLh|vNx*4P|nVLKdUi7s@*bT~>( z8$~S@RyW&SCtMa_sx3>Umb_S9E%~uHk6v=qf;%rNVMGQq6%FOQjl>el)l25sg`Ae! z(LUB2Nd$FCVwAH+!0A5Lrz%fd)L3mbd%LG(UR_;doe02tN)qCp5^Bo)Nj7)LOSx<& zzbdP}3RRSull3ZvRB0Kj8Jeqvr(i6a(8>a5#y}-Gj z0|N|u%wqSHyaJqY6!T%&k%{xbF6V};fm7?m6ICICiXUbn37qqtcn*3T8`l8mYA2ox zz5fKx7AKyA9<%ufaGrDGxzH=ea<#1mDygN1AV)em_ z+5wy$oCd*+RUa<^=XDLQSo$d6AA#x8NqA@sJeT}NfYai{bCe(J;}YO(aN@bp`wDPw zcH%kcu|9qdoIg16T;LWt&SM&0vGlRtcLS%4Q!y9= z&n3Sn0B4>P&ryD)mj=#qC!Pzv^}zYC6VE}9?d?Y3Y<1$f(EBZL{_Mna&||rlp^|5^ zqG86$@9Dq^JMkR!szIX@I9F(Rs2V51DyZh)DWgvd%GG0e6{FfIQ4@WtA76u z91o{|Fh)Kc>0>;{0OvF(o=f>9fODP`&q0snw;DJFC!PzvZvf|ePCN%acB4Ci^MVu4 zh29iQNRQy86sA~ytKqj0IOl43#p(n4GfF#fy5^IboL{@Ow>0oR1Dsu)pu&t*AC;Jn z&g7I7rdaw|ey0N`>BMu%Zx3+RIPo0i$NK#gaK7fmbD_5#I1f7UTs)a<5mD$#k_60)N0W7Pk zMza-hk?u@5s6Z3B7;Ima?QH99&t06&i9{a-->cy(bKcXRY46E0^V;VCkA(M4dSEUS z^_!m}WEM)`*Csfj! zfbioCVK@(nZHi&$Z3Q3}U4&Mg)W3uh3$)$7W4PU_*~*p6VPo97A*R&7ls2YEXpbqg zG?d92WJ#Jh(ndexl_*RfY3s&~?lgEpk69T9`H(X~sU=6qSWSx3hLKyN%~(iZH*U0N zz*EggJnRY8C?QZlXrv5#&e^7&%>1Yu68t68UY!E}wjoAR! zAer_C@Oij6ZxmpKu-ew)aWnvao1u-zDa2VA$5bBZy7@<)(-6ngtd+>Lu>nj33~I4K z(R!HaT@A2?Whj8ivsm5eWK zWI>@$Bbb6%I`c3^CXTexuL+N2eA3p98(pr_6=!^tqO_6mC2huHEi*UTTv-{L@lC4I zM#h))VKH(^yBmFpsWbjvlA&G#@`vy^&tGvpMmLsIBDVc+3}1rhbiC1!Jjd#A9ui@} z9E+dP7op9z5Mdg~Sm`H8SKE7$qlcB=zLWSM&!b=rb{1`qX zYuA;inQv@_b*Qa=kGkRc!mAb6Jcrl9-=l>PPEzcw*fP0s7aVYQ|9yyPCq6Vg`54^+ zCna`bNSwS_IQT~1C><(?lYZKIWQRvx{N}pvJ@Yw)H^^@m!aN(LQi`@RYZF1)N+nGU{S;#;1&|D}jI+SJdrsB;?68c7N918TYs2E*a}-QCeMZB| z4(4&CwLFxZhjYqi{nYr&JPy=Q-GfY#J0-tmjKTK{3_s5z?%Vy ze?MR=;2fkUibr-ww3YMD7tM{ikZzX&pJk~Vy2|lO+EBgXBZnMkV1F4)!P^1zQ?PS4 zSp=e3N5lSKhM8{I*ip9QDd7P+g>mV|EglG_VmvFC@jMM-u1H+=7$mJ~gqCqJMT}23 zZgE`zPvq%@smck+(=mwa&_^aJm56UL@>Yhtm9|P@PtRX9LP$zAhHW-%GEP{8fJ;c@ z7N^AYOe#?(%`aCbeh4*PcwD{wxsAYA3n*ED`t7_YWLb361=FLOF0PJly6i<<2)Nce zF0tw2Cvm1zEj%-Hl(%thM}Bf}bEM37C;P%@5BJ^1A_*2=cy_YyHq?(IJ#Zsi{Z{|x zLvP}S6bU!-r0~6wd>&=`%WhiU%5$pjqB(MS}KuC zpr?SBq_F8 z?~#v&&QEN3h0?&&c<~ipi57x24tYS_9%B;-W}>Jp4wexTqCj- znUf58qYQwQRc!_j-!WtXGps2E{M@(r@4T30IY;M#^)t-k z=dlI8K@O0$0L%|837+y7U*S!Cf@D(Mi;Ysi!)igR2wwU^K>*jke5>Y06o*>4uI9@E z#&P7m{%5j!FW=4@xf@-jLQARgW7OzX!uFbB>mR2N_Lm#Bj~TY>4BO8P+iwipUkuxB z!*&=1)eaFywPEA^BhqcYVY||>@dgR$`#HmQgJF9VwoQT_%2S9D_W(L2bZX!n0rxF{ zf2)K=8YxC_KfrQr3CqI8phU`*(}mEG@_2+$K~8rH6`z5dMX2CG{%SbAh)7c&#Kc8G zEi(Gm!tVv$j|=shpXEI4i$Kv0^FgtK^M1A%& zMt4wPk}heUx)-`16xhTfZQZ!h#f}2gTUDx5Jv~_&zkRBWKGP^efon7yMH@-qni4o_ z{`R~|%vojQAV!deOg|w@%Pa{q7Fj05&`XbYx3o*lBTg$VgsyiND$wnmn%!zx5Y8 zhf(*l|At+{vD7D66O?%pI` z7d1O?;mMh5b}@7T7iE!}tt7}-vq{{!YE}&~N6n7Ft2;GYOxU{!JEMXd=PmG6aE6+_ z0}}sIIizL>;Bm9($vc%i8uvTkC~z0}MUWo0*>2)}Fvk6Ea2)s{m;m>HQnw$0XM>-B z=YgMsUj-3i$*I6VkRHEt5J(T)Y}R!V$Y@KFEi9Zv!LNgdf%2vWK5wO(=4f3!BagSJ#NWSyc&{Z8-beIuj(EDSGYJ0SdOfpr8scYTN=aIm)Q`HV7GFrLCsJXi1wX|tnv@@pgL&Khwt zi{Vq5|7}g$objST+DmiBhN>>0C80(0pT^_MVxEJZ?V7 z9fyv5ELys`tvZamt-5gExyaFR;TreLqob{x_u1*lYIiea(nAh2l2P}nn0CS%q@A$( z*0@ibbW%HEkxt7^o-k5k4CQKDEHh@=oZnhKC=W$rqWI{IFjB7N9om(q7m1}hk_=_q zaYqd~o=CY=nfVOpSxX_`?B8;c@q3*A&l#8gV<$qVhW0MMR(`p=F!iJEv%+dgbT?z(si#fBy>Ny^cU@ohzlIJW|zaI{kDCYB?eET*TYIg82T4K+9J=$9bgP z@qO4(iz@S(2l3r#D2K2OVgX{HCj(`f{IhGp##f86{4*)>^h%hWCrdfx$b9EW2K;(5 z@RwOH-SM~el1bSee@i)JKrd$igNgkZNbKniBr3KpJ->9$t!of|_L+*pr<6OWjx42_ zJX?xE$ubIm2}L||_g{@METL%R+hpw3iEIfc>9H%djaDzuwURxN+r|~S9%}jwC^;@-F*!X+^ri3&4-{ zfbEs}(Wx&#NBe#W0@=kQDYN_@ za2Vl=YbC5)R>E4p8@*7O^Jc2Yp#E*=XC1}$=_~jkd+c~PauX9*a0sDXTF?%Pf zcFuGTI_R~E^E=0u7SvvM)zic8sh@w8{JULaruAl17N0t5%7W>$r%zireafQ7(IeQU z_h1e%LIk&ZRfi)CoC(o&~Cy}zE?MmiQ&sksbIR!ca< z#8S)EHGFL8x4O0j)3)SwTtRjmK~`t0dBFCFVq zFP5RndKO2RSbkb3mG?g_9qV;3mZ8Z?>qrx;#7pb)$zRJ)$NI#JWoWX}l5Lu9V?&pG z<45UO10?df3{6&A#rTHuhUq`QO+634Jsqpmi)CoC(i&o7`Q^Ixz~UFuv8udSh9)bm zqf@bPIQ`1QY{THog!8>vhURnjK0C(n(X4@5|NY+ zj&X`}XtL5O#W!7t*DO5n#B{79yjX@ND=pIkQ+rpv|9bw)bS%`Axoj)V zl;IksNT+r9fA#r7I@Z}S(^W_hs;4WU@$o{vLo=@GEI zsA#TB(Xa+V9?s8FKDpXcwpl1ogL#r{f4;2pw63jpgrQlL(RxoxwcbB@oKNb~dPkaA zev3Ndssqc@u^#hc8JeuxIN8Lq`q6QwHD13V9czad%g|&!<+7}_CawETM>Kw+0v)y_DIJX?8P!PS!t<1k$%b-zIanvI@YOPEJKr()~P0zmC0Cn4?Xph zbgVirmZ8Z?i-(bsR(spVE7P$q@nRX8th7d(SjGHTiyH7kVoN&KQZJUF$y)>*-hK(6;d{hRK`#Qi49)-N{r+l*iM7MqBsLF}ujcV`lhvy|)6g)Y zo3b2gQmL1Csnr`OI{zv%FY_ z#)LO|K2{U4-`_~dN?j^f_I`i0_yq0u_jPy#@8VWglIw5xnCt3qid}MYH}qZoE&a%D z=)3w``rO51g=FWjYaBn1nISgLsa~lvLu@)hAvVsaZsP=nWY$JzDp~cB5zx>ueo}ne+$J`_ zsG2#w@lvOuVd3<~7S_XG!Fu(1m(H4=)G5Sfjd6D=^5$%H1y0RFq9CFv!LV$b|PCx`yOVDtM2fi?_!h*WYZY&^T>& zV}sqywV`R&oau8H&YCxOp;K_u$dgYl&bU%LUyjJ|#5r=rh*M8JwYd1yvXQ3%T-y2a z0cXK?|5p9G`y=Mm$`DC>d8}z|NP)68>X#Av3O^ zoq$GQFKmKtw>pkoGGV*h`E4+n9IA|Rse=`?Go7rTaUPB6bOr5Hr1%qZ=z{WhCv;~+ z*Hc|fu2lXq#@ytuvC9*o`I1K`>nModJ^0r^lcx?PS9knY5q3N@cX@QmZxBDtB0L4n zi|T4}rTCfVYyI@!SXgu{BkEjobyt6~z)$pO3?cu5>QA;{bq-xn{$kKwhPic@I+|Sj z%irIi+3C@Bm%k!-^rriHh`OL$DY}62o&rrYmo8&mU-4y`H$Zb`E?oe>??LmkT)F^$ z8$BBF*A-NMtXyzj$)O9XzgwZZfG%)vb!fTvSAQo#Q{mC2>Ln+Cs=xE0nUzZyP~K~x zxh|J3ho9>2x6u40mo9)`Cp3F<=>qs2q%L;G6;yv32^*P17gT@Spqm2S7Ln+CraeP5E0->yyw^Z;T`pY?zoF#mx6r(hOBcXz4>TclsJZr+ zzabutr3{t_XTo44bXTgg%cXvMQ2X0U{oMx5&(u-n+F$+s1)3K;y8Y#E4>Y|eSbizG zfbt#-&B$E3fcl#V&E>gt0sOuV%};Xaa`@@_KH$;V90u24j0X2ObOX+|R8&)7{jDM3 z2xx9Q$I|Vu{+@y6RgW%JF9G@62Tf#><(HxhDDR2Tl;_gr@EZo3^Pp+Xr3>Kq6KHPB zrOV+bz5l33V{;f>e?O%Do`bIW%a*FU`eXfva}_kFPPTOWtG^4Oxx}MO)k{wP^n6!B zb3-m&KzZ+mW>w z)m{B8`BVM%ZonSmrz=GlP~KCZiRRMf@KgOYK;!1p z1@QYNG}6Tf4YM7$F;P-S90irDOW|QT$zxo>kP28hP)k{wP zRDUy|S(Hl`P~PjIS({6j!%y{hKQwRV(gpAfPp2IGbaj_M)!)e;jUnV;Q2nh&VVsde z7gT>csJ}m7!uqb+mRr8z$H@f&`FjbP9UfhG`BVM%nuATmPgjaAfZr%+Ds$-q>hD5m zzL858!0#4l?#!jj;ivk0(xWjMf6r5Y*ItIbvCwkcU;SMR%?~}g zRK4WnPxbdlXdca_3n=eSXg0KdZjVofJMUHi-5sUD4`46eU@%rA_~p$lq%I>o+v8Ft+Y%WZ%4mv;>( zO!CvUzxEPgU(mFywsiYz ze?NrgmmXcJUUKrM@;>CzSdPK@t0VCB9J-+Vy#!s^H?hapSZ@2v-)YcPd34?7PxUv= zqp=*j&)=LJy6*D#C+NO+?dRujJv4vu==PVtPLF1P`MU-AvIn{!-(aZ@27>Z;A9DQ4 z@9`zlk1gFGpu6$dnd|&CuMDOBcZJF=$@Sr3>Kq zDKz0<*>ZH3Ked-HK=Z|1x&VHYp=rvc%gLYkErsSgxpV>i?u4czmoA5&xpV>iE{CQymo6uNk_SJ5W^*oG0KeCv zc_)`HhhG?e2mF?Q8CTHzdmqp3An2a>oh3X72ztI#X$L?3J@s+7rQ4r8eIJ^A9$k0! zr~DnU&hqmA2jx#<{#fY#KyOms^$gL<}PfR{~sP^@-Aslr+psm^fm`l{$FO}CCi1JTl)HQq7x?7O`KHi9Oeb(X9X!6>12BPVdqS&ZzvzZ zK8=~tll9IJIh^3<;AnRF9+X!~OO7=OrfTIrA6z z$F?YYPx{%@cAB&1PHSe(hB@m+hq4sIVh&Q7HJ3F?D${J8>!Slu zRE4Gj8>m^Dq>1xzI!@!f=`%9pbaVKODs__|tC0v@V+EW|)BPDVD&_+ze)DE?m<<_U zG<^XF`344G2P{J^B$9q z+VRrPIp;=Y|GiJ$*rk>g{F_v;DT7r>3vu7>T4z%I^-`3l;Xx4(}hK17> zXt#2m>7obU?sKrR!RMiurJOitnpA76>*Et+hLP*j`?*rH)6p{>N`ViA8y3!MS;VdJ#94dz@LHT#@~+f|zF?-_N&H@H!XSPJvZhT7^$lgKuw zJ|X{tWMaVksBDb#i(s@quk;*SjzFRHZ=5Wo94__KXqmro+MM~4iTg`hIlV*=qhaj1 z@@moJi`CRtPmoSGZQ}cS^rmrLlx|#lQIGOd%vC#j?%z~}nG?1QlcZ1EH1G1c ze*RS5U5_hLVS0+37cN6ts9LV{xp;ESEKXg3;cZog+SzE+>WWp2iBx}E%S8qz0^O+WnJnZ3&gp76t$pT50uCPNLz|NKwd zC)GZAO8EuRE?f{_$%bD1Ii=_d~PoB7DxcXGP;7o4)(f z`H$aM^Q*EmPjt+d3`KbzyWe|yUaaQwIS1tZ{Y!g#Hk#d=p})Ce_U77~KKpRXbt6ZP zyK>58y1`_qC~x2kCeU@-%@eNJ3r~WtesEm=t~sk?d{d_++i!{y>#M={`)FU`}GRP(T1Ky zc{{$=cwYOL4}Rs&9ev*#-ZJ+)Oy?N?SDw1Y-LT;ML*AMC_%jV>ZfD%!S>wO^u}d~y zb>o98ZmOJkK>nRK?_&8QwtG?Dz-8k)UugSP`H$cE#g5ZjHcVjYpYb1Z%hH}rx0XEn zmFSnAICkBbv2@vu|KMXc=N~X`+pos0m{IlpExXTP2*&sy-0+>A9c#~g>#-lr`Su0( z|C6baUm5?=WA7Pu(or*defeuUdmOmy?57w8r~b|7Xx;CAfOMZR>tcHdk2#ua+MHtT zyScD<=;G0*9zSJH>S)15v${RJXkl|x)ASktA(O@h%`jQ`A97hZZT5f2VG%~cf1ZuY z=P#Hww|U0!S#xLafA0yX{=*DY`?Kc#hddgaub4mmKjc9^X3x6FGBHi4%Xvj4&7_&f<2C!>yrz1p`#GN~Mf1OZ*b+;>8)vsP=^3#^fo+1=44RFLYX&9U zv%_q$GnD(O-c~z9&HgwVS9q77#zW3$QPa3d6b6e(^6KM{{R~2D>=S*8Xt+A2r6+OvbW-px)g!z}sT8H3A zMjAyW|7nihOJ@dH%>BjSFi>M&c8?ml3XI0He)(|l{0I?G|B|oWqsF>4-WD-_{*fqU z9UJ|JF`t0ZIS)e_(}nVIE=WHn^Dq$43tQ$)$8N$D|2Gar391mKms=s^D~Y#r8K`_L z@G3-u;kH8LDsYzZ-}L!+v3Dn zZfeY(T$Boqv*XrZcEFhWtPaQ9T6B&~n({B4G6Tg%Z9)hilYmKW3R@($ZW3VKJ9YfGFT39YmG|5yAwPxl^qq25fxWWC!Hfm-<}`3@pLr5PeUdJyH(V8N zpM*G=u8Usd(J61(7+=42&dgw=yyyw>^66MJb6v#~QT|qfM}uwPso*!jDCmL-@H(&_ z{4O{ZyaD9Z)^>`?<=_v&Vc?Pc?30zNz*(E}yV-Lob$cwFaqv%+_BFSzF!v?KFK>7s zJ~r>eR#aiw-VmoeN|*#ekdAQ z7oJhEzWI>Ix`!j{I=;8(BfJZH%!u5+Wkyw7VUL>D4t_iHTApCrx0=>BlNAkv7u*$X z-Nf;Ho5Qh+iwl>miiPGCCfw^w*1$VfF|RnX^z426_Gt&qIvwaUQ`@+4+QE{N(b_eW ztvzR}37h@h*zS|oyEr8u?|{Y0IdVcDjuhhG58PLT!(L73DTY-{cgZwL-rt~$2PN^4 zBrH=rs72DAoN72CGU#(@^gsvOs2J+~$(J!O)B7`;i{|8f$pl>1e9>&kM0`#`nq6ZqMdEmwiFDdo4ta}}6+R380Hl(uDCms<7+<2S@3Io-p2Fim4! zdNO19g_sSn&j>JA5MRBuY&BWf%PHJczz(zrIQgUc8EQWb>eov{8pQG#gv+KOQlC=p zpfoIHUTI&aba!uO@b<7X=;=PrKsJjjVhhK@*K*%Xy_Hj+@8->{bzjYRGlx)Z{+p>+ z`t#n*vbW0T@m}tVtlmIo4YjuFPPo0yI~rN>1H5@pYu%@7OJAxj-D*kv*VOFmjhA^P z&uY)_F*dSp;Gh{5Pc$cHur+(pjO9;Wadc$e`Wa8`ol&}h*LX?c4Uq>P<|Ur7=lRZ( z8D$;9!5&3uD>0Y!jXbcy(sYJI5N&f(@A!AkJHA2hcx372yu+=VdCeaTSIjGntQyaK z*Ec;6U%QuWcW=5U2lTps-kYvZoYbB!1T)@rS)~7+H=UUO`)~RVQt>b4S8w`Zc)a9! z@}SL|{wP?C-(Ntz>03d)=?M2^5_}SD1)l=ff=`2YfX{*VgU^E-!52WiyW2o`Y5T+E zv*7C>Zf%j6{5#0cY|AMBH$DHiJpXsVf8f6td;{!Do{=8O2>1+mJg9t?gUavaAaRUD zi4w<36uGQKv3|;x_0#iGUHF%LtwgadNtE%%Z-__Yzr&I!X&UQN3z%f6MJ3+;Wy7=M z)Dq}P6yEOcB#MnGiDF%nC^il8_H!e5P#Tu9i$pO*yj_Q9dr z(kBwcjn}vj^XT#mW|Zf(42ZXG&~d~);;kQ7F4?j3Vz?ylE9oFpPV>M7Cll4UPqD%G z4teaXQ5uc0ilXQrE4iFP29`5}~B5y{tqNDlnH8*$-W=7QQ z@Ec6$jInL`eL3?L8?2MV3uQ@-u60KZGbUeCMKQJ%c~^fUvSJ&F*#t~Fad%b8TD)Qu z51Vn5x+yj8v%b-YYMNbPb<;Ia$uh${JGkt{X!(>g1~0m>*8N*;=_|FR&-r<-bszHe zlHvdFnUB#5xG(s` z&T-1#ik8nUu61YBMOLVB==_Uu;c9n6VNB-nGv40rGLOqXjFvB=qo zFGj@OW!?*5nfNaRM**`#JqGmVa78>JsX@rF zrb1E7QqlAMBe9f&m4w8v-lVs2BZ|og#dK$0hG(vkuCHO$<1gLYul@v|ERdzx7vNEroFzWvjZAVI8xt#BYl6OF8P}|=t2=kbWWsGGi7+; zRpSkxYWIzr_1k-kozZ$I4P@awoIiq66SH4XAxO7mv|b6K;G$?5i9h} z(SLWABn=NM`8-kSojT-+!4W)-l@R3{OINRSS|E-g?8IDCj+av=(!t=_X@S@@uR-$Y z-;#xrkSb%gkkZk3ssTOqiFu0~8a0SNZ^jI5E3Giqk_}_mql_>~)(*nDm#kX|4UnvA zR^3Qe4WFn9+w_d!y?jAcB_;91~&uonCtD84@e#qSu> z*Gas?h~Lc53R1ZWOunpNJ=E4u&scf(FZo(QYF%OOzh?Y~cqC_dC_$R0u`UVH75qX> z+t~I4m@9~Hk`M&x;f2oO2)IKKrUMY9g$TGX!Y&_Sr^`=I!qajoPPs~O+4OLvDCG`H z&r;@np_lUog!a)0>?6Aoq#F9X`k!jBG51?TsVsjy(~WX+&TG;2uZ7Auh;wIj&wJI3 z9%@Lc>`D2?+~<*iF*iDjAiT=!OA?ZlF?TEe@yO~9>N?(bpEXn3tbEYXs%k@J59@TG z#j=U#Cv+$fr=BBf>uPxCk;Mp(=F^afvrj9G5z4_o4^~HR--STl2=5V5cQdy;x!n*e zUve6{0f|Te=5z^%IQRgm66m5cSq+%ve-{6jI2J9igN2u z8;oF%uYaxg4m~MjPj3uYK(OR>S#WpYxs&s+j0V}tjY-B#Ew}>#l~<_W|~Ux8gb~@a;|uZApc7)k12X!CFWcqbkZncwjg}J}Z_zm$$7I>(Zm8P*SX(xT@7t$QD;SHE8i0}6ZK|38^i1~ehQ?k9E zbJWujPMKUCGBL>!(q}C>IzEFQs$l5%QyvI5)08@aK=Lp50Yb2(3>E^BHRxg>oY63YZ7TpV8KX zDS`N>cvXHDS$Ad+W)P5g`7`#splQGvZDT)E_-8GTMq4-Zh+@FUDxO`ix_bG(=2OdF ztSX-}Z1AEJ&4^fg;ZX>4WV$j?6WUS}+8Vuwg4$jL5vwX7Uhq`Z43=yTkFTIykyRti zsLzeYn3ujtcmowxA?l;5!mqQX&r448BofHy8{n!A!CH_wqgy*n4~2dJ652j6JzYsU zw1w9TU>Hdc2^nq1Kc;%e`{_Aaxow*Ra(N~3Hu9!=GT4{5>+#M#eovbUN$!jSCuGUn z8M9|`baunsdBzAgl2?3#FUeRbi>{JaMeQni*Ww!_dG|khk|96ufq{Ri40V)tARf1R zp0^-xR4yIv6bILVNstGcTn63?t^)r6N|xLQN_9K{J_2@t+rSN=Wc5aHH@FFue0>k4!KE8{oBBbn@BKA5JlF3G{W`Gw4Iww||t+3@T*ste@cG5wrlcK30P++N@u z`gC9BBoA;RP5qpL`iRqWlQ`PJabYn(%c&&g8j8!NiNmBT)D@JbrOZ1q-#Kwq5d%p5 z1BW}1gZA|?Cb}mF)%GL@qwe#$La;I=1V=|!OJ&8e-M2t513U>z_R+b%v!sI?jX|z7 zNIzTRa(>x|HKor=NY0G6*@%*plZ_m!F~cQqxl4wJjo}@0--z7)2?HaqYUqQp6A8~) z`Rw7?L0F$}7M6nT6Z8pa@s=sqqJ7-JZzZN#NSXieyunvk7dKyWf#GI+rXS=Smwjw9`AG>GEoeAT(e9>(d4ajtV|s(nR*Lk{vZpn)PNDKl_s$V&G3pRTA5|B z&pNVdj3-+C0Tv!|_oFQS2(&-W%&VOvVBaUrlX8YtWDH3VwS(CPtrf8U*AJ{nBUDr+opX%X5uo~P8t_42=Me`ZB4aDe7egx8cO=|T5#%Hn; z>4t)HHq%H&`2wSw5X!rZSnenUJGjqK{m=a;6jE{V;*@C%voU-9;@AijF5 z5yWTobIxG6WF$iv$1zNDG(#pD6Fz|9ldv~r;-^_m49lq`d1fe<4#qvdr>eeTqF2y!YGS$!m?y}ILSRI+j;yNyUy z|GmR_`ZCxGXql;tnJg`R+z8}&n~iJawkPOn+{Kewo#r-I6lwsZ+WiNT_gw_>HaAv* zY-SiXhATvCs$A6}wpzvyh^la;i($$4WQHN-?-KN*!lm9Q@;*N2fR%`Uib_#x8ssa#vXP7B=_tj>u}+ z4H}8Av}WYT8i`JnekQv&R`G76wSaJDJmWWThG|XdrdWBbfVqlS=)G!uact)^+Y5`%Y-b&gEvvu^_F@EkF_L^6g8en{HE=t)9sCFQ4{!AG&F z6Z|LmPw;KuPr3L05Dlv~w|28QCDN7cCbr!mf=DmXYjK%XK|&Dx=LOlwvI?TD;eXQchD zC2Oe{zpYW-qhbuK^K5A&Av42ln^%RJiP18zFi4^imRv0p^VJN^n)!C=G)-?tHNh=% z2K+imDzfTAZx7qFm^oO8^`|{jdUe!(xdl5YDSwg9uC!9FhI>L`hP{u zNND(%$}BZ=Fdp}Lo{UWxHFGLB3O@`!qh`uMshKmtZD17q1RM+Yf=3+GG$m^xlBa?b zz{y}8D7A7n$XJNRvy!X8b3qQabr}0d-T_Vq*Mp3KB)5WJ1)l<^f-8A~jo@`4D>0G_ z$@gqf>gP#*R{h9j)sOX)`mug`rYfs{$=9kM>k4!Kyzv|2k!1D*(lpj3^|Reji%Pux zD~RvQ1fqVT{hTPOW)!OD1XRzls2rnyP)T8L3e-=tm>8Cm)Q@!y#bwjPk<||fO4Cy2 zRpdJrsJj65W0&6C0xPCC%bwI~8KY$0<+a1eKZknO`Wj7l+O;`XZY%rHuFko1YuSsM z?=(x^eR;^}u+)cCg(SS*dK86bHOIIti@JTiR7PaQPkAEo8zkEqoFB(9`omIVs(D7j z`x&kAm_L}#z&*3D33pq(aWfqN7OqGos26~xelm>Aau#fIH9pPpVY1t?6d_VPey9K&(!mE#N?AImYJaaEJju}o52!R{~&1@{FhiSGR8mk5^a45 z8ER)k8Q?|_o7!6Sq>OwXi5^X8XId;TmOl?%M*kLyQr1bwSJsxj*Qg4}T3|f5-7I8#EAx)=8{(0i?4epgn#Q^$UZq$T4m0eW&#<#DKh0v?mQzW}H58Xk6Gw_t?w~X+W!};GtYqoOs*;1c z8)nhid}_Ek$hx=79Ib)>5wdrF+cGnF5?MX8Cqfb1-hqXNRQ8e=jkoC8Y9e$8huJyy2nPwx;OG!4D^D>+_z=aHzT3n$HE_hxxd3*A0z4- zLM69j(jR9r=!SUvW%J|hv!>RRb|l(oRVLam zV`enAes49?)$Lal*R&7JkGDsQ67AFKjAo0skL@SNVjM=-O~z3mpQ$+bJd6$(j$U$% z#*r^aou~5D8<7f(x1u9^XbEWz{Q{PduJ19Utv6j9eV2p1%&5Oe>WY}kEJDecpwaRg zU8FGe6EXJl3F@U-l?tj<5Vm=KjSZ=$&Xp^IrrMy*1Z`5JSjndfW8FXh49C{Z8vLS< zR899}{4SHr8Exa#SJ@>ha!dDTY+I}b<>+;Qy3H^X6Ure8jsHyPq;oDN(YA5MH=Swg zTWx&P`L({W662lDs=V8($;Ei}$ZA?Y3X{*zBCFP->@=mT7ltuTH9@uCwP1{CcfBbZ zbyGX7ur)HR-`Ku{wK89Hwes3mY6@QJax=ej7UL5t$B%);}&@&q$Tfw|g zOK<-a3f@H%>%nkM>pzq956$Z->7j!7Z)9ZE0*E!6p2Sz(yk;2@vCyk##jX(^k)>~c zV(bWJzn7H^B1zd3Lk-?oQVim~lIX^q*qqtJWB$x?j;#6$JXDR6T?x{A-k_Cks{I|@ zYeIdOK~ElHSV%sqs9WTJ^(IN&)O!1%Zl3l)KOEYtz--%M!MtW|pry}F#U=RCG>vMt z>okoD-gTNr#SfaM(K0PnkqzrQK`x2b{RFvW?&pjqZp+BO%3Mbj*;G$^{=Y=Os~+wG z)y-Q6t_AM_ZwCJas;*ghlRS#J>p}6@2u=kzfpft}z}vw`!QX;g!8gDsK?mvhG{}ge z^BkxJQ_q7*@UNh{buWU)BjNuBZUbKd`=D)J1B=1GgL6Ugy9-o4R#2XQg0fHa{H=W= zm+k&pKUpf)PtRI)kh%!5_KCtnPM84oBCsPok}rEmf`*5svDC6pSlbJ=sKh&U8Q<(U z$_0GK^mE2+Kg>D#>BF59HVt-)n~z{h{79#${wTVC#fE{Ornxh*O5|@`Lvh$N<>gb# zZNszEw3K;gw>mQPx+gSEqGZvm>j|;F0MimT;7LatG)O53Pu`JphT7H73ON5X#ZF-B3vKA}q)(;CaS3Z+;DkHZ)SGEuHXmYfC2{Y*G0X#_p zX;#LP1IDBHf;F9ACgrP{lpm~d(NRnb5s@C}WIwquYj*o74|;=A9ZnL*oM1Mr@v|tA zu{Y>%YRQRNOG|vZQ_Xa7Lp$T^-{@_=xbVA|OxcuF*0_;GdtqeZm*ez9|ENY=+g{%* zDH@Gux{uVjPna6e=%kc_)D4<obgc`)JK`GnNvcGpf5w+exp~iiVa9D~wk7ZEERe zbf?y^F;HoTB{V>}gNjDMY!lR%%(i`U^@=x>C+~GI%{j8_6f;a|+qjgOY4a#EDQe$l z@V^U@QZ;W4yl){~Lzf-Gt2gPLOewM5+>FSX64OBxTHEvku&WZ&rjF8LViSBxi)|&S zs}_46->zD08@}CXF;!1@T1?Hqdo89Hw0kY~9-+#kf2qt;K!@P5$@BaOC7^of8DfnT z*c)66hQXV`KH#sxzTgJ%08n{i!)&wGt3N271HeY{23e=&3<5jA!$8(2I7finz@xxj zU@^E4JQ_S2Idm*o0uBW$!BUV8w&C+zQ2c*Q{#lb}l-41{wMt7atF)}2)P?oavsIb> zOTJcVSyz~VBaGh=kHnw8k}^osSeKO6@rGJd;_Y8Se2=kwPcC#$-re6hVf%s3(N7O> z25lP1_tb2XSFdM~o&?kIgymA4a+Tn+>EXzlE(=P}Qkpef%?CNhj~c`pu0!{uwDjJj zRv2s7gbbziyji|rRv535Rx5kbtSz3ZwZ&TBz{;+@Nc4DWQ3ETx+Nd&ZXP~yM{^T|x zy6YB$cb2RLrPbCLv~z28zDt>(yR#%|JZ)sn!l8xiIApCml}`7EQ5R8WC(zut)zhYz z-5GVK3}c$?6YgK&exI~SG3yS-*dekj3KID)h(bsL!(96+^SNH}5 z`q;wLJ^i+-q=St3xz~z^xJxY76|XlMsJfIzw}`fk3AVaURs(0p^O!{yIp%IOF-g*! zZL5pAv0;T}4?l!XCNXDuhgQK(X4I5MF2Ok>Udo0RADd-yYoZm;PjE+lDbo659)srG zo{X2SuP(12HaOu<*|0aVLd$tlI+ZnP?jx)cKH08*cr046Inug}M5699b|x-b`ef;| zsr404t%=^FmY!mOk}^sTrN^4KfVCF;qff2Lu#;$JZH78(E#KdHKZ&?3WK&{xX~$E( zQdD}yR>}U~HU(%GnD|qG8}h2rh>R8AU^=tLRACLed1O29qF^=dm&|vd(5$%8tJU`W zG9JRhGkE|x3tgUNX^QtC;-S>%qMuj)X06L(fool!jfWoB%jeLW<$F;U2`-f_fJ#9 z+po+-rudi2EH!=t9#cGjHd-{MK^)Zb?;7wz@GP(cOn{rfb3lhUj4~$Gh5s_BWr%bOp zD!2$_iqp9qRR5T1#Ux|=&euQ}Tmr5IzYhKsyc(oTCf&*4a_(n?*MRfXQotnG2I6*B zfp>tbL75fb1h<0Mf=`0q1_#k*RQ@5L%GsNGy%AJDdpKpXCW~CwWU+oSS*)MhoSub$ z$=8}J))gi|Q^e_h_EjD!5e*O9&$iSuSt<>+sKnd9g7|*X^8I3=^Tpi}=fv$rPVv+I zFKURf5Z=hr{tHY&EE1+{8zd;6)1V^00Na#rP z#>rRe>sB_&sB!BxJ)7#8#~b0H@do0oBo33aECp3BJhFNh%|HTFylUIW9IWm-o#jO7 zn<~dG_?k686yXls^ou`?l{XJJ{lqC|moKcg#P}9zNu>2K@=cKt z;|69Nn4~b14HMcEL(KqzXOd!rF-VYb`4qs6FQBp+2H@9G%xNpRjl^2nW~8P$c$h=6Y%L2S04%}0`t}IT#sqAo|%D9!b`4U$BmMi`j%?+&P7Ns z4U^j;j0x@a%AqEG_+xT}jm~oNry+`<{4qf9C%1tK4R0jlzKo>$l9Z{LAL!9GZb-DB zJvGsOejPOwZ$F>ulq>u>8SXFBoJ{XTdyS@T*rji5uSEMr{Sxh$nAsSJ$L1&67nm8D zc%uDlVLcC19ojB!eZJ-}jL}I2ZpHwuHZvi1MyANjyFAED$U}sTGa;3l{V-E2jDJu| z8wnY&k1%@kL~vKh-OCu4QG3IlBdrhVIgM3NehJetx-*IHV&1>lJhe^5CMW6H6g&Nq z&InYR*wD~PIuFKk{AchrvmYcc_c*gQjpTJx?cI#kO{~ODk}#M=4wxl*&kV`%kTHm+ zU>G&athvE7RVz+3d4LUMUrdeI>t!`9qVwX^tjRrLJef7=&8&&qL-xFhv1$K^%SVl%ZN@2Z}nFU)ju<)H}@1_+rc#Y!cQIQ@-emtV$ST5vk0Z!Z?+cogwxTsPIMW z(m#A`$EYT2j7n1ovPLx_5QBUKh<6gEaG39nRZS%eVSlU&`JN&DBdhwrPme=7K#ymK zK~GWOzn6PGOKBIGsM0FR**4>UqnTsEM3sKqhQ?sbU zoDE=XQ*jEuWSbTf+SN8yJ#@8ARU6&ermC^-Y*Q(M?rl@4ukMGf%+?_*A@MJjyN>(e zcr5Y!Z^NikUEBqZ1@8tg1n&VmzOoMGGJgi&1pfm56MO<3j7)qAoC-b-&IO+VuK=F~mx3>Vnwvu1csS>1nEh)v#@h%t%<;K{F7&3M8;^teJZdA~ zsZP06zgjBR%I}mMsj>_|g)ih+n*RFkl4drwp4P-B%FWX+o^JO{8wyFl#d95iTp2;o z@i1V=q2>kJ7gV03@oeGQP0ZscpO)En>k9LR&(GkbJm?MY3pRQFhtTr+;HFDu-t@yk zB{3MR1&;*lz@xwhuo%1)JO&hRx?suw0*?m2?)j@Ft9xr(vRrnXHS4EQ8|x>2%9DS| z*S2KqqQs86w(5rQ(z1`OF11))3bl0dv92Oqb4?8SiNAjZ@t$dUM|wFCco#HJJi?ak@rqAkZPUY%W#tq-?!NL+wK~O4{9twOygTwbdz{>%PseyBMkYw~u#SZt9(;LGPT{R=I4k99PPuMNxt>nB22)Em zhCY0mR8`#7C z^R~;@R%9dKH{1vt@01@aYWneBAb-TeeyFQCu;=;tm+~S>qj%-cp64k@hyl1y1CIhn zgGYnq;ISY}_mV@wF<=yARX}nTSP5PSjs<@NR)hZp$Aj;KHK1(1v%sEUEjSsh1E+)M zfOEh}U^7?`@~yBl8N3HPALQF$=PTg-;053Ya2)tIa0)n#bQIT0G`Z}~+}7`AFSG!( z&%rqO$DRwGM6<3ieqS?wd8hPsPT7?2j6m`XK=SlM^7s-W=AO+gP+XsP4w48cc0VqA za%}tHXT)~T`^!7ng{Ju^Hle92dvaWRq2oTZ=lxj4mX<=kgnCMIN3piE(S$@)n;f*! zZ#Bz_o~xJY#FI-}?9_Ct(av)X3$zPT!}O+$?J8zN7x+(2MMcYKD%x&I($ku*Gg@ZP zZm`=eWqjFPnZZo?P>bmaj`I8)sd+hPfNC)_LA_gyjwC07mw8s!F^o=t;1!DXHMgKs||tpq>QPWS&F| zs3)O0Y5OGPvQNVLt@T2?J_&`}Ct+P`NY{3G5@=1n%4V~6e{&@*m|)iOEi@xWUu^Ux zz2q~Z`JmP-#)MiTtyhc=we)#tth!H5XD>H8x^3)e_rTVVLrW@KKkj)|&(@E7x18E~ z<>)*{H`}V1!W_|7m1rq?sA{TWJXEEzbf=R8B$nW4tD5Rwz1TRKI!D=9&=ZTeU1J^S z6BEluZ;Fk+w70h%$DJifSep$x%w`;sWg1nBm0vozB|p}7=^$Js##M}~u;pmCDqdbS zXh9_I<~>w7R2Dj}eMNYeRt;*a3U{8v;vx5}c*Xif$1Z=eaAA}?$J^la~FmwBr{}-`ou~X4vLlT>Won2D1)5t zuFibI2en>VVkjG_jzp|tnFu*pv$`H}O#m7l`Q z{FpZ*CqIRLer#YmKa2eQnC-+KoLX_|=*X&v7|ZJ%$HQUA$Ex_EUNK(D&H?UOdcN+1 z>t7A+c{du`+BPW;Nf9IoLy{1Q9;dr0O_IopWy0I4SVmw;+N$b1SsHO^9l!c`W2pM% z?Pd#|*1h4#HNT|v@%DqrAVXS91@X`$`(EW)*F}~;z%8!&$nv`s&X#0VaiSRasPd|W z-6&$`4I&$TY0u`q?s+`1M|W^<<1N#;N#~U&u*E%($7cgOXGZVL>ufas12X)HZz3zS z+Gm-HCEt^b@9`N45#7Y;9Oy?#<$(x^#wyy#_^^y5W-Yd{`tEVW&!nly9E=SuTC+*I zlbVnOvOnBiegT-xX2IeLV#-Kn6q`1$0aMA)xcg1D)0TpJ#hH)nIuEU0w!OJ8vmO1| zl(b*CvyYr%-6q`g!tQ!z%!gv+Jf;bz$nC6>d_3A-mq!MQSuHYD8*FOF;dop1Uc1TW zrK6X8r;|3TCj6Yql17smuvEW_klWj>0oN~#>qcBZH?Fm~B)dY+&A2pH zXLaM=sNmBiW~3y<^k7~c$wINej4uZr?6)tl^Im-{BqzYS~ZVD7&G%G$afJQe&7cslr9@JrzLz-sU( zpq5(S0;)b~dC7U;uRzJoUxUibt>D$*ZJ>IPw}Y#|--GH|-3k5-ybHV)yc^WXF6+Q` z;5}dm*a5x@ZUEl^>0l%~!A+pr$7b*Y@Ig?YpgjbJDB~7TOTHfl4+kFswKDL}pq4Uh z1xJHVfRcJof(h^$@T=gnp!&ftfGyx(!T$nZ1iuNs1l|Dt4g5a%3aIzwb?|O*JGce> zJNO8=1AGzO3BCos1!_se+n`oWz617R;EDG)83x}4`-AU+1Hkt|HXCtvgGYcLfX9O$ zf?7hc2Rs?v3s!(1fv1BXgHiBP@Jx`A;v`?8JNv)}Ft4W_?d}0C<~{^|4a^6x0(*iQ z{q6dH9_R7bHEqz;@3V1Mvzkg_>n1`h_$11Y0} zG)*1}eg!1&&IKTOa~eSM;!Fik1up`}fQ=w&Iy1mC!HYq*Ms;R^=YW@hUj;7(r-SoA zXq?NyIp6|N3kzDnE5YU9wctwdX3z!i0#|`sK|c9N{ta9Mz5zm;{3rM=@Llja@B{FA za1Z!x@Kf+Rpo9Fl5&R-3eq+EZz&N-T{5tp(P`$J7(57wgOs)b)vOyZEuh{`ut^((3 z{G>hlI?Fv*f%7d~(j$GH?|7~P=cl-&QTjT+@LUBt8OrFEzB&uaxC)%jxTIzJIuCoU z0_Ry=(l>n_?S?E@fzEz0ny0TLNg^Fo;OxaE9n{zP)N>U$eYlr4>Z@(#jjOs zB(-I`mUbf9>R-1LVl|j`g$cOP_zmG};-2h$rc1GODb&&xrd;Ym-(+IoNKwii#M@Hl zy%=#`WJk4UHx)WhG!;1y*YnvgyQ}r*v)?|PE|tH5kr!>`$oH#fC$2hyWd(e)S~r;u z3|S($ekz}u^uL9LgZ*#ilSN!@iT<}%^NIVCziQmr4i43{FP^HNanb$CyiRaBs&@H{ z&Ew4yg%{c3arwhnVg5W->u#*&yNiq+6^pzb75TnVODo>YYk8eSHT=u>7FrnbQFzIE z21Z#h_;y~)FT8OKrHe^agw(f#ksAK5${EbK7e8GxbjSMolJSBC)8;PJXYq_e&T5|3 zIBj+VgObzcOy?Z+{T`&q1JR_ao=f)hX~uBU8YSpmN?(m30xt9XZs9eM^L9`V^A1o` zRKEp>fWHGv!QX?G;630Z@Lq5-_y=$*_(xD0|4-mm;Qe4bsPG?y>p;B#8$rExcajhL z+R0VmT%Yp0!E@O`5x>sxG;wTmRUA7!CHp(%$sV1ZbGoS z$hh*I$a1zxfq>15mP@ro?moL0ta=+(YOUdD`vsp>JQcY{-`Z6!+t++hEOK{YLHpRe z$ldwj==xW~vCx*z0o=C4sE&mqgjl=H6I>rUB54~Oy+RwhQgZG4nDDYYS9BbWkZO| zDSXa6HaVt*(?S?=g8lZTC@2FRz;-rZQs!iyBn zj1;Tb7`f(X!j8re_u0-K?lWQ#bvHyG zj1}~7^goopen(i2d~@5={O@J{_s$#pV2syu?8;dG0y+EOtnc5q^K?OY{hKCUk9@<% z#K_N+yQd-RBd5p6QS1Wqzpn~a$bzXt^PrXwF)G`NZT z67VnJap05S3E&%GDYz3H4zhEhGXhj+U?f-so&p{Uo(3KXVu&S&gB74U0cU`Erj=kl z7y~66$AVu0t3et46Tt6*6Tu&Wb>Ld?JWyY)Oa`9-&jBF@wW9L3ZGK$Al{ZTkCi|Npw+`P6{bAm(c~4qSd%=3Z84Y# zoT*8JO3ibyvuSh5h+20Shk%;1d3QF?bjQ}U?hUo{EFYU_E@<7G*D@AY%jt2qO`~j4 zce!4V@@Tl_1l$^5Esqwq92s}VPG%g<4DNC0^A6=N;WkW;wp~!v$w?6G*YOC0%tzqO z4bullM44O3YdKgEAF2$)hX6SX<-}MmiMNgCw2BxfV~igab@NNe6$gD0+Pb&rRTEqH z_HI5?1E^hNUuX*k%xTU?Mvr2l_vKp6C#!7~AJRF-UsuG5-jFl9dZ0^)l zI%aN+BloU4UJJ3^^Dv#)>yu)c&P6hvi)1?EYD*N|8mpLSOlM|}%!jb?_RFXKNe|Kt zNhaJQ|7Q(neS7#5 zIo zP^$B1pjJ`-9F&UuG58etJMa+lyAB)){t=uAJ^(HNH-J(FvW%@Nkjw5sZvCXdt>1P+ zRCfRBf!nGA>k1RF0~)Qx!o3{}=;_`J`QdIpz(le=XuCJNjiWlWE_JgU!%_KGTK*N3 z&f8u(jA%hN*`wAINaw}6q;fts)S?n^{|e%}+fWX{d@X1yWUW`b@`p82D4I^AE57i%#_sW#MHqQL#y4h>Jyq?sdhK)5CbGc-31$?ZdEW*=h@_)E-#rc1TajoKivx#v7u7gc#8V5VbxYpttXk0hr(inHh zjNTn+TpAbrKkU5;d{x!eHhwNQKnP$0GC5x$DkwvM06|c4$-qqrBr+(IhL8jZh9o36 z41yR9P~ru}*;?y7i`7<(I8_h?oUNkbP^bDTidM0{N{gER^Q^tkcu!)h{rdI$|GMF1 z?Ys7~_PF+V&RK`&-$CPk__+8D%0Wf4__ly|nE2RJxdkW#$2&(n1|G%^V&P70d-3Q}%#zynX|ePx}7} zl!sjJf>wYgwpaI#KEUs#_>F-~4!6j^9KS!t?`t)V+PELTsh3rd|KpK}^tSygiyed;Wm zeMg;T)2Gg|sp0A@n?7}xOjfD#H!EKvc%6k8!0oDbm$gaDoPxz(TI|j60|9(kr}1FBrE~QY3Xy9t z7hK3#3W6_VE`ZgEZFtgU&CAiuoS|=pFWNq9J6PMp-yQ&Kpo0bLxSO8^63gt^_BAhu zlXG_S85vk!-~7g!mvfSH_KI-pV_pxWtH!zzeElTPE8#m)d=2oOAimY`rHXGIe8-D# zy%ow~Rq?KXPsy5NPG8iTcg(p4C`4hf>y-J9IW^_A^U6!3o-qgT7My3yao-d6jv(F< zV;B~f&L{FJ7M08|*C#|rAfy)(RmVvxM4u7yP$`5Uj^2fViCNPehf4iie1||90@6@q zeoGif?|cjxRe=GRV+QNibgUze8Ha(gMdXPZ!-eVX@BRiCC$^=aye>eKY8KFtj>c`;m&EUK>NLh^pIVi%?55-WTh+IeFA)KKg%@ZOFxsF# z`TYKxm$@gmUO9=q8BKZQ2Oz^+nw!n9NFBn1X~S^;Wy9s~Ss~bH@52vTk7zuUvhqXj z#3I}cW@4SxZ+l+^4M$=LMyBO66`PGU%Jb00Ebtg!fNP#Zu}iCKmKQH7sXYgGRf_Sk z)q3?gy?%iCJMO5cD()%De6!?CQK0IYXhn6EXb+W#4Qe{(gUW*qfsw75xoA}8Z31Xd z&;rmCK?`+b7lAU#(?QPw#q-ai1Ux%aNB0-7 zw1th`4o1iHL?dCGYCJX_D*cx=$g$iTiL7}GXDG?5Il?qNAv^2nz=jox@715!xFV%( zZErk6hn;zTeJ||HbL+ceXP#Hz2|M%L`gYuzNAnw=I2w@|BJ~%yR9K|SM5e)qzKx{?X5udYN8U^?cHy23@^7|oo6w&&tx0cdZ~8qhOA zmxFQ{yax0k&~>03DEKgi(h>U9jc3K%qC-{3W?H7p0#fOS@=-^^!V7e7YjnqXUWfD! zq9d%me4~5!4@S?}KknqDiI=b1Gib}y8oU98>Eo2y^C~LK>t@%~4V}HPrhNXu5pxIP z^ONGAy=+AK?Ar3m@{+pp*-J_@(gxL(%{2~WmR2vS8B|er;?6||hlijssH_&V%@VHi zxl+eMU@*NdH>j+9ZvFh!DP$s>z^vxYOqUxJEnmjzfG)@@aJ=|YCwKfFBQ@i8#={Z> z18HE>M;A2ODvyH`Vh(HM?uLXB5e#$^G#=)tyy~~Ml4u!Y zZlo>6$%0NWhO-nLL4pC6g>J)fk9-kd3dR`>Jcz$$DcW15;PgV*-UzW2j{2c~1p{62 zm$fo$%E`~i$4spW2B<@3%pI(l7lTXJAui^Q;06O6JecpbPyH5|U>eSvm)Z;Pu+)sX zqZRWnfTioGVs_L#7wUG+U%By$1Y3%u0i9r6HP0zL80aOTxGP;Vx6GD$L~{ir{=J%G zAoVt`8l$=e0|QtTxWR4Sc`d$NDF_J$vK{5Z6Lf;dRzTC_xN>n=vddLh(1E*Ov$;mh1~!yUF1w-j`OacS@2;M!?b4q7qFmg=Xa1mjApn@AnazqsDN>7$;u z)M;8uFs`(^yVBZ}yZcyMYO0nJj4LfJih}{BMfc|i-gcz5KuZb6)jFJ0g8^<5=!PBE z_rv(sp$-HC+_sxq*VAg9^R#47BjoAtM~IZ!-yeRXAkUV%NJ|OERSIr4-K}Fw-KeDm zK+!I}6?(ULy#F@r@60A|d+t(dt`rt7U@c8oTC!L{q>w*2X5+fu`{lwe%- zlPXeXuYBp$7dzTgd0I*^u694(mDW3L*g>DB4(4@}wrj{MQha^=GwYNT(GTkU2*y>40U~9#&Mo((^tYv+ z(o%wP)!0B+S~om5Ezb;1yY1_S&kHRrLd-=DlCz6FO0 z=AfemhnOuW-!4b6F(j@9hl!LquJ%dF*{7rgt@9%oS4q=F%51^F%06e>QscCgU|h9| z#h*i4zBzsIX|~i9EhQLNS|dctY{9_hQ(v^Da8p{GU|ea9bfxwARrP49T^{-LDV!Z*qK;;{4HeFL5-#VuVW}~BZMp>iZ6*}foaji32 zq|DY?UD2`LmbzU_3C2~5F(PHQ&JAs@7;8&y(^7(Q)fm^mc3+-7r+Sku1=A(s1mjBU zG?7xh6|>&=Ilr@|zSUBKaiulZl~&!p?Q3nRu6lY9j4Q27O9~#Nch++wZ7DtiPM3+x zy~Ylc6Zo}mot}F-+!)_F;{>zC(K=zPb#ipf;keex5-GEFcFsR`jV)EEr3B+DMYc$p zt#hbTbg3;hS4#=TRbx4>w6?xk|Gh1R7hS~(#+6pCNSUp3;)=G<*i!4Xlwe$Gjd!Kh z^P|2m*iygJQi5@%6|tn4nL8VXMr`sMo)_0T6GX~voq|bIuCb-?(uX*~xJpqVQfBM0@7Pj!r9+%xTs1aPq|CHF zTK&TdwiI665GNQ{T9ZU-0RQ4z*>&JSTPnbT9!@Z>vzhT1qgkw9a&;WlY_-%a+0`5#j{nN^80$MZm({RlRK~JP|HVFs{~_0e&!m z7d6BM9zP9J6Pm%b$Db*feU8?dVYSXvT5?8Q>&y}P0Oj7*{D~iI*M>WObJODZ)|rctU|_GK zbxN$(!84lTO5$3lRHV#OJQF+Zb6W}z;)@fEs}yA-Wws9I9a{>|Yl;($tH#Pj%1mqT zC$GJ4OD)z?f^nraPo&H>+tVH2IMSBF14`lq<4SA3D=p4DwiF&i5+@i}S_?#q<)Rz; zSkI}p)IC~CFs|0A05%v%hJK;)jo`((+v8hjpO{(Hor8z>z0{V%-5_y-ag`z}QfBL%IVX~2 zOO$D^X6u|a>H1&VQh(M`f^n5%rAT$-UtEVxyDHh1`c6v;##LkIxzgIdsZ*0J z)jbh`aDs8AwF+Ey^2W4gcD?XVw$vakB^Xy)=ZlnCuEOs3ooP#r*HVIUrPW|b!DGx{ z^~<@o)Y)1}Fh)gPS;hPcY9L(*?czK=xB$FhfTxMP-!SFX_T%H*>q5aS1IBEx3#|59 zqSLxS#q2npYZNK7TzB@raK0^dsg@Fqt6bC^`}FedzXi^-r5?~yf-&$?{cxUr(6JQl zT;*B=PB2i!K)A2h{c>J>xz-{i7$pkMX-dCa$-ozSmNMah0M;q|8z*oEtedz7!V;##xFcs}$YYsBlejrHFxR z?-W=HTj~TYB^XyJ)>~4Hm8GzyPSa9?ag}0&NZpAMy9a#FzM11QCR{9-$1vyif{$*4 zRf;op%p2l#>=NMYQhXJC>nvLeH_^oj##M@qB4v&VC)MDiVpdw$YAM0E`st;vv{r5` z?`cbI)l!0SrFEG|rAkh4Pb&Mbr`S>-YAL}`pLtkh@P%mB7zkX4Bq8|2o(l{tI>-y& z8bi)7a0*a!N{XD};P3@;n==xeUM>zc1bngH#tcmZhZSK-4Q0%HvEAm30Ee%>Tbxlt z!C9^I%yAD7Zd!TfEWmOx9y%rE9DgncHyC(WLUBL+#LL&jYxos{Ne$Tj^m41c`s%bU zkJIogMat}_>z{x4XNeR@rCLfbuC#7+rSq4=ef(Pm zb3fRo*4<)h-FrIbTMSthIOgu#M9S2xGfYD;~ur3B+D#qA;$;$K`(YvM z-~{8Uu{*%EHQ}$l!V_$%JS`;{S6X+96#FUDdSqCBf-P08r3B+j>n>MX%bSjV)t0(a zO9{r6*4-k-d5LMQUhrAWmU>i63C5MyJ+8FQc;lGIZK?OQlwe$GZ4#+eoz~XBF4LjLh%VE)EkLXfKxAcq=+ia;dT1qeyev{@{{d9<_8!VT*pFRo>`YHahe6#QUcy)Y9 z85#_Hhreb?AGJ#QfKKbtxRO3DQf5i_ZJ%+0E%mgP5{#>)e-J6Nq^q}H*~6ClNJ|L@ zIOHc;2>wtrsV!znSuT`RJ&`z-s3&mQ`$2M)>w!4<5Cg2*FRm}gC()Kv)JBWvmekgk zEH_eRN=$7zyuNB_MO9hL0Ff-MuBxkFR1TB*HT6-ISY5OPsR#qc9O~-aS(sM~)46y? z(>HxP&@XW-l#hBUOZ}zQ<@4rMlvb2iMUf6lSyIIhzb&dUqt8fnb4wSLR8*yUxvDBg z`eMCYU2U$k%-lMetn>KXxVdI-+*~s^ZmzgFn}o2N7CW-1_BNI!s+YNl;5%w#Qw znWDu|2h%<4;a3t;5v%# z;5wSa!L{--yWQs=Sp29-N}=s)91%Wz3B_jlfDCIrRBi6d9L&Y^PZrjvQR?Cu(%I(o^FCR8l?xDzRZLN%#aPiMSMW2EBZT zg$eIBE_7~NLs*fTZ^+Rglexo2daV-ppiD(*9c5O0Yca)FSbTB|%PN*&6sfN&E5_Sr#l?Ai$#EQBjQJ58fL7JC zW+>1cK&8AbniJHMyw}8+PGNXzOW~@bS`JrLl>Q^~Er*-Eq4o5KwHUvWAKGHL%74q@ zO1`Dkb>p@W>`)$!aM*IuHJjm7L?4vO-;beGE?r99Vq8ClQgMy=hw}AfC>0k6Ijf7b zn6Dp0skmB?DZaDCCnviTyyuCvc4c*~GOq22HQu6vZmHHW@hQhg8L)QBO&C1_4k+1h-g_Ub?7T#U1=SM@I2 z`TihTgK^!e&yh6*uK=c)JN79iFAKJ1crcX(AbvhZwGJ}0W;}n6&p{ETFT!NU@p|Smh#8? zyAhcCy*QutcmbFW}SvvBszv{qr{sfwy~be)-!6+#%rp98$5h zmOs2+W%R^F*HZr29>X<8fcWF5e`~?d^WgmQ_cd@Y0=K=7imkQ$?FZ&tjcX}?tiSGk zRb1v@zx@3Qfdhftt+4_8_RAm7jb8@l52-4)*7EleFkfk05O7J?qkrrlDaRu%Tyz%B zN1smvCf|$m#K-nn0L)4+&L_TWfw|p_^NDYV#z+S7$FKfM!Qbn_wN!tjPk({b4K#7hOyG*9`%G2IgDdB!O$K{*F5tHf3?qwUj^VOCB(1d2v4avI3Z2cyXTg zV1K&}n8&?1pZMMa=3_6;6Ce9W+X49FaDMuig^K77-1IaBhfjRtfSKgQdE)Da=qiB`>pbvV_2LuX^}yZzBk@sRb_4UC#!>J6+L!5ksxk12 z^K0L&2>Beidq*gY)xMtf+DHVy3QQ+@;M(Bwi*E<{zAHF0VmH?y!Hds28} z&XhhOX7>QDrMSizfi8>=hDCB)H!Lz)8y2Z8!`-g=C4;KxE;L3OJ-Qfk@Z}t_+jQbi z-qSmA=fnz}``1;^i-!75?jI_I-JV4i=T=nB4`tyt6%wfhis|RI#cR4o`z{xwKPM*S z=S-elJav4ycw9I;Yht(v=HpaQ2Uk#0c=E(4u!OF{Iws^#ot#B6JdCJVoh(-I_{rfJ zcpO3TJKKE3UX+s!iB4VqDy2tejMCxJ>WsM+xU0sPMj}rEBR^}3L^35ST#$ohzv8zM z{^arFjGo}!1LQzMa-TP;Xxh}`oWfiLBzCzL0Sg`XAB*|5?9K?d1OfTu3JS9($j=ZG z&o9iHnllyVBNDq@YK4X;Gyf^z{g%AQwA|d{spASzqQowpz`;$NlFD*^8MheU;;t`^ zVgr-dg$2sbD$L161txa+6hBMVrn9=fwzS+t9)+-%5hg)pIMCy*G1ylsUNpZJjhWbm zxtd#D4P!D@c_aj7QSe1seF!?>=(h7ILd2lt7}EN2iV_$U0POLQ(HYB zUj(m{qBGk&Ot=-o^tvGAWQ62T2~R}(nx)=ImekYa!ZRgPy^*PQ#;?WiWKqIz!qJSlPwGPk6pxU!-yDq3|VWkjp$vnO^L z1&RFP?5wH96LY3U3bU=|mFk9GQzu!o)AA-w9Wp|G_QlV-igRHFQ)-Bn8ZDWx>XpsD z##EiU(vm7wL^h(QJ>pfjwK{4cUjJq!m_08ag_<%YJU$1FoSh@B$KfQLon1I7KIkq4 zna#tS!n);O*TQ@m^pd$f2!3gq2*v4aJ!&aGJ8xpnq$zoYlcbxxfr@cx z4%?t3Vqv4^=Ao|H?~XGok4hrlL+68qqFF1^2^GQ!sMaCfJ{giqBBIls5eg+5hVZX( z@i8J!mnngaaa#rqK5kySGtT{_P1i3^e?=LzNC_Nzq5P*z=B8D3S1mtlj9|LEhNO6Z*X-rc!t=Ve{H`|H!7WWw)Jd{x`6H|Br-!u5-; zob`v#mK#R7@YlZf?x07%Tl-M&Ey;P8j+*iWY>}egeu1!7taw#al~&f5l@D6b3I-3L z%&VBMAfl2bi$Y=)EYxpV#)$s27g^Kql8U>`q!Gdsw{1#>hTPeRUZFX7GmfwFP+zFN@_4i zt)NdUlaU<_ZlK$vVPRO_|!rnzGd5`xod2@$Jk~MgdUE| zHm5irzXp3gAH*YWuGdH7`X5XU+Ho0HJa>6ieZ;h%$#&C3+9OkjH90L62I^#{ub2ebr~yYNo9lsQEDlH|cm#cR-^s8=|q zVLFB@bBM}^ylUfVfy3Gwhv99X4i1x<;l_jb*xYPRfJPA*QMhN=KqXH;y)|WxGNAD{XMdtxh~qiIeGm|`OcJBW@Tyd;SS`4 zg{KwHX()+On{}4&QOjp;?XCj{ACI*a2ETbXg5j9KjW6sFQ6;%?x2WXD?6mr+lWC7L zif9W1rHBMyp~6B;+2d4PFtHS_UCt#XcGc~~{4Z7jmSf(iepG`3%|&-;V1Ca5f7m*HkPkulx~{t9}h^wpS+NHr*U}yu-zLsCOO!tOD%`dI4w}=!KxOKv#pZUHalu z?LuFYd>>KqsL_hYa?HVHI&xLJC?DH}hobx(h;k-nE!Y_4>jWN;i4>Y~o6av@-p$ls zaMCXwnsGB#J4WS80Z+xvI87w|esL>gpl5rdCv@mA=u!uV9>v0CdX$4It=SrhL78H2 ztm+OM>P-l84+L7x8pCs%Ma7omWA$3KFcTeYabUw|^_F*R{P_H)x;afN%J#RTcg37h zb+cC;71^+2x)q66KSecVP;!k&<55zjpX)6j+u#7MN?iB=f~}AEy#*J;@51HP)PIGR zQin{(w5X-j%9WaV5wwu$V?WVwH0Vaq0id^ljsU$9Gz;`9&-XDY%rj)0bp4SiIHRr$!;>)pSHEZC5_(U8e8? z;SNR^S~&vR(*@eo$)P>?3RZ~fgQ*W~6qexGybf%Fzs7{9a9&-$!kBN+HrxvLqcfyZj(fc(B4G9M3t@DQzdJ|4K22aJz4 zx~B94$lsac4R^hmJY;=BUIySi(1=^J6glEy9@xBGxn*nq{it^4>-V5tK`}8jq=G&K zdJ-tAS!}~U0?N2BbxJdFJ)@e5z9crceD<)TyzHoWU>Qu)bmXdLQa(1*1mOjaY;PQi zW>OPHdwZhLO=M0M3o)^)`ND3lzpwcwIvR5YEOIxW$>u6XpUmM0$vOq`Y1|;%ZQTT{ z7IG4WwQj->@bj~por3EoG}rHTHmBKBocIEL7xT927MlsUHwJS3qW52WjAD7 ztM;W&eFRtW*wTszkHI{cj$GBg%E$ISLwEtaQ-1>5_gHkpuIPrY#em($GGwZ57+apU zrkUOFY_(3o3o~~Th0h?`!hb-wlkO=+#AL>Ft#0P+xXsbd8Ny@g zmShbgS~FVlF@E>RsuUp0{*GdnWL6>jfl}q z!ZBxiRba>n_UnJK4t#}lrsFal)29lsstYvpRWu><{1)hupl^ewf&K}UD)25SN9<2P zF9qEXdKKtrpe*$)T&n5mQ%$dUY!o>h%UxiO!6hsoF6rUkZ3CZYPp{zql3BJsdgKt#LC3Mak6~s*@;H1-Vsd8qVRRaN%yM5~ zXLf4H2scm8Xv~V>)7x1ga|lSAWliV}zOm}fp(=r{ossWUb4bUh&`Iyn|G*b&0X@2zjw7t5fsgk=S^&)->Hr*|D7nU_%9(i?9NC6~7`) zIicoh3$QC3y)?b{G5I725{V`>X7vhCbXShlR%An4<{WT*x??=l;LJp}x@vzNt7`rn zG(SG?g2e-~j_5f*L`-eS*uD|bu*j`X2(JqQujGR|)B-mrDywk>C0_`VML`At{_daA z3Rx30IO1XYREy4_QOzHS=H?n94YVidFiCInMc!+tJF#P67l?(iNG^cQ!GL(-4{I$4(avsL`O{c;+LMdM&d{^MYoJ95Eitc6HS>Eo~+{0w1HK`g&lUehdG zE55`O@(4#IY+vg#V^1b;-WJ}rukE&d!F2_x zk?=P!HI1JgZg?+%&)f&HQNHx^d*Z{!E4wxxOgO*uH{06RCw}|nR-D#Faf+ym(*f;+ zAI&M*{C4oLryGArT-8JO+NQ#?rouV+JaJLuUlR9swE8lC2MU^QO>IDycV&%%q8Q=F zg7}-f`ZN4RXf)dRL%=VYPx$4ZFl{rSu%%ld zH@j)U03kIv3=K9HC4RC4F~$mKH-6G4n$h@4AbJAoAleOqO3sRG|MAY$dO3eMO1J=m zS{vBt9a~6s|LKkA&kocd&I* z&FA%da=33$-61+Nd_gmB?=J1aZZd}2J9^vuiNW2D{-ln=p@7U+_+e^MPHb0r!|B*3 zK8swTcVwrI4aZ)WS!aBPWMY4Bd3Y*<@ z4vyj38=LAdA)zns%8DdP#ax$qzt94FZhF{rl2YV?9UM2db3osUD?wHqPlyi#xty0I z75gS zwwMh%6Lb#fV$ivutfx}Y%R$RPe+xPf6nidX0qB>YRiOO7O*LqL(8ZvbdW||zOsz%~ zGz?k~iYe4s0-6iD4D@u+^Ffz`-V7Q8MT^R(G=B+t6@Fg}ip%&F=#8M)f!+i9YtVZ^ zuLpes^ajvBg96jA4|E;q-$5@2?SwkH0`xG@ji5(>UJ7~?=mt=Jb>w1De#Gx0P<~GY zX*bLOy&7~D=mntjK`#X5=c^k*qoAun*MhDA-2{3&=%b)_gMJ8#yf%Ceio7-)0R1g! z5PI`F(6*otf_4Ud2=oNdEucd{9|j!-im|&P6ZCP=1^Ra-D9YTh9CRz_<)GU@Zv)){ z%E@6T=pR9MfxZH|8}v=kr$IjheFiiD{dgXfgX4>!JwRUq9R&JEP%d+Bz@?Ts^d-sL zGK#lVhb9@!2X)PK3|Gq>=IS)hYHL&>l|D&NuY zJ&r4AuwI##>HN~UN05H$%t6Q!Ey`t%Upfzg9~2bRGM!&K>pWnHB_W?Jr&sJKFqR%y+F&qTtjbH&P3NYI)tVNxuqr$E}b@9N*43KHA0To!-Mp3UE|Z<0a$z1FoR)B!^5jBwh$Q!ZRc~TE#ge z&a0@Zs9T_opO|AJ#9MIO46sPvagfbt}YM>+oCgWFL)5Ih^2r6%nh8Du)9jMeA97$7fHc+cxcx4qY%a# zPLOW{F)DlW#CrrIJl{eb30^x~LvVf71%H%Vh$_QL8gJpt058)>$PA66tg0dzmfPMig`2yuAfCE%rZS<+Ta*DT3hpMdw(=gr3 z@TgHh`Pi_36rSvzhqg(hLj5Ox%aCs(Qi*KmdrFLmn8a1rKl`kZegvSpNoCNrJ{X)UnjE){8l5klPh_ZxOxO7aCYlaXX1P;$+|_JLovoz= z<0=J5&tPB<{vwk`dD912^3dmO9d`a;Ut){Mvt+%Ca(NcnOX@cMbQWju_XWst3E%k(!QgJ$Kj6+W_z!{Ng z9bY@5zb*BamJ*CBt*#&gu%)nS7AF{2DLAnP18Y^V@%r5}L-D0JMlfIFuUU$ttx|B! zPIq)%DUJo#?(b)-8kaUx~5#a(v|8E8wrpwkkJs}v!T`W5~XvghU; zEKlik_V?a``3!%}QiQBhaHl~R!aw(D%-Pc}#oie`ez2tuXeq(CO3_!O%>JIa_M9EI z6qbGB1mo(1sjjp_bNeURQpag2!MM^oUZl+aUfgqCA6trFsHPK)E3Fg2wac}sa?E+Q z)I=>M7*|>+iWJkL%Xp+isx38FO9{r+I$YER1EnHk80*`=a7TRWaE=NFoUPN(YMo^| z=6-RlbCO7zJ!SeGWoO$`+{Mue##M@w!L@tJEk|B9-In^5mJ*Ds6az$RETe?G@a?ST z_)-i+h}$at0IL+g)iDo0j7VU4u-C_pK4LOMBDFv1Z0?U;b@|E!AI33C5MyaFLR68@>;Y826+t zm8qo!<4S9UE3Gp|Tz{G^b*7dQj4Q2?BE=DaZrDTTFSn(*-=`Cdt93HK4Fs+W~&WLNBQ$)(tvE^fC*V$5+X(_?DN-5-uCz`SsSy9-di=Q|AJ|fV(o%wPrFEJ} znQ1-O9DUuE`bJ9$#+4R(aWJ69QoNmg^{fnADp^;nU|eZsy3#uC>qX;iseW2YFs`)1 zB4uj$xZ&#^ISgwl!MM^I=Su6*8~49tr!`Yc3C5LHmPk>+@lJgf5@S`*20*3DD#_t3gg^6WCL%1Pkqq1lP`@UpKEAtZf#m78eFgx(qj5*he`Blxzm2x?ETM>~m^`~rR;w84! zM_NiSu6pKv#s1#>EqA{0wJr67mJ*C*ff@pGZtJ#en=kPcG0^3Dw#7-U^@^$-9?0|m z+E9>#p^XFC9PwFCcsm7brc=n`ilF=PVJ)2wqpUc-@PsMLTK-}3YIN$bR^8` z&Mdn#B53tti~9uV7~(@Lj>E*No97iJkO=!JE32kGY_pO*Y_onn zY=s_{>R~Iihv~?Zoeg5_CvqHh;b1xhZ7u~JPmVYwom_{ggYAC2z^Vxk+pGx>+pGx> z+pGx>TcJHnohvujd-F$UYgB4nfJ(|IKqZ#Zl7vryk{H>NginBy7}}DAPk@q$D}}BE zFTc2W{FF#ZRT$)|Hpm!`|3(yvkgCPDQzkLx{u1~SK^{UmosVs^YdXLNiwBoU z+h&eAi&1bFu>w>7?VSGMID55ZW8x8DR`J*aj#EfWHn(mE=64#$1&-K`@Ub!RlEyGT zIzO8le*%9maKGoF2wZzye)*ddz=LqW%;M4luC@F%0&|JRwUj?r$GyO8^WsE1B?aQ;XgU2acYxQ?BFe5e2Du*Y3Aw)9`n0hbHr@WT~bAuP>iI4k~$ANj?i}Q(Z zKQP~Vah~{?zwY=moE|u<96s?)3E^c!Tyz%B6Cc~-ybuw#llJh~5@h{f8L~0-Wv0NE zpa;k1`dx^jw)4ZWm@kBE41In$p2mG1VyNx>aP0r>d)pZL{PgM^=t~FSqJ0#W{lHJJ zrUUmGFxjaJ*P32c0<%oxTB>L2!BxQA?#21E+YVq}^5Q)0#(w!1VA}8i3eHN`CqCLg z8{oxx;$!}3|7@lg=M&#DU{-r^p7@x*n}ONv#redy2blM~I8S`k(;qYjUU7cyo75KH z)5Gyvh!X@H&yD=rcOw+$g8_K{g$Frs?Qpd;FZ>3WM>Ni=XHWk6L4GeWX}I7loKJa= z1?D6#&J!QoBLa+RbE~!ZmH>C*kHp9P-3ZKXFU}`_9|7}~7w40|6dq?eoZq<77vZ5e zT>Q9!rZBSp0US?GtN#HUyU&$=IL|s_FK`b7cPS6h;GjOf`cj1PU^_5}rwgprd3rQ3 z<2BA|H&6Ysf0S#CicybOp7E6WyF3mTUw_Q^?QuBRT=kT95Xx~6aBmD(skT(!2H-m4 z@GZup0k{NQE%lEFfO$gWS}X6LG)5wn_>ezOdD(6U;&Ach#WK<8o?*tMsLTsKw!V(_ z;(ofVuVqN-)SqDMt8QsUv~os zEBtu7QFja9-)_`%2y4YO&VTJj{S+fu|Fs*{l5H@{&eBgdU{xAjUZd@p{p2|QZMLWM zD(By5e9C+R^^JY#*RUPcw;u25Jga{sMceYNkiV#>PI;)9f-380=2NH2NEeMC@MY$Lrn1yfLF@xDt&$hphj%sc>Wi-GzOdOf!v2{Q+Z#QR zb^qC}90Md>M&~3J6YyCa8w{6o|#{Q?o49AALm&BBV zBe~-@y3^|}>4lrpQzLkJCiDIPrJET0ek;o8dm9oqZ-{2SwEqECpHc_znv|~!zW%rp zjOF;-PkdM4uL`}@@;zsTnhJC+I9}TxJOXC;L|liu;E!^0S534CX7bACuo3jKL>OkXd37_ps2ToC7{?PHe3LTU0cIyQ0%rEVxV|@pcJH=SSHtT%0Z;Gc?{aWa0>`Nger z5jd)YaTLtd9FBYWV%H5u4iZqM5xkm-m!fyzMbc#f{;b(o(6r#Cg4m}8O*Oj;4+PPDw?HG+mck zBXmeK0js=%&;NDBnDsLwdmu7IQoM^<7rKPF}MVgN*%iHAOe9cuC$7bmp!UgNFH= z*_)yUjmGa1k~e&dTEReMgT&ua%eR%^MP) z*swC|rB7;+MTYIN!s>r%d85CT>~fHECOpycn<<|vDL1X$gxBexg5|UCGn3b!j(8)n z^{EZWcfp42)U=$~i+C?JdmUcFlstwTcLY8;;|G=cc00)}I%oT1K1JDoxDV6R3^S8M zw|;Um;^kO66IX(~E^(&#!uWfJ_#*f_O?(WQEI#TydsqSuMQPt%@SQHaX8cv-@L?!Z zKjEdqrzFxX-z>|w(DJQ-Po;|&&Gf5`*TSb_*$khGd7H)C1D}fdL(9j9LOE`uMDQuu zT=-PXMer3!=q!s@4qu+|xF1rbTn?WqQ365^;CdO?NYCpnyw$~t_eETZUGYabnJ3hj zfTJaIE6eL-o}lvkJHFpS6>z@a!Z~3bc(i`479mw7i^|2S;6|{chzX{lN@4ySU$rge zH+_$S#5D*CNzlA%+B%<$@BLL)RFxa%D>QA8%ff)<%CV?9=*Sn##O}=7L7!>fjGEmC>Mu&e5x(L79A)nQteL-tLPXt{IN?XW`CkJ#c=ycFB z(3zm9wT61odeHMgmwoBVQd8}`C|@V=RJ=q{ zPfh0+Zzci}Zz$0SA@9AA_Y~wkk!681(`h~bP9*()>8Kn9`Xm{BzCO`7_QQTg&prK( z!^;N1MCV{*Qgzk9DtutPwxTq|&!UAYs>Hl===i!MV`_DEXi-Vk@{sCTuCTnSB_)*= zWhy9MG^?cQ#Av7*hB!5XOM8j57A6^J)z-COo)~*i*&-COrKWm>K#20u zVOE6Eem0&thTQ^l#ZPhBUVR4f`sZztoJj0-{R^=tuO5cNYzZOh*xqncLhAj2Px^wx ziSQSeQ1a?!;OVvbCpkJirSZ_{Xh)H4JakHO4&;xf{Gaudqo)Hzt$gUndT_^(p$F|N ztk63w-?J9(b&L0r<@*7?ez;%?1cL+zrUaTs(L8e?zZQJ&f}i)689oV@cfqd>{Qp}Q z{C6TBreoeXAaj1XPBYhF;OY%O^rE2vv5!^8w#*z{L9vRad>q(T36J?>+@_lYk2l^*;W;-D zX536wNias`qfV;0cf-f{O*aP~Z``%Q`{(k^)ET$w=D_2PcbV{dw`~KXHq516AN(~3 zS5VB`D4(5Y1Xwjk{~TQ2xK-&|-k3~Hg`FpRcXAj;pQf6F1x<7I@fg9}m1uhwYCFD+#RCH-W`LaUbl3tin*XDU}B>d8NDL#j41LFf2+K4=3lm9d2wcgQ2ic@`f5j(0C{`al^dCFf#d_ zY|XM`pC_-$M}NZh2ivxxz|3>yk2xOd**Nu)vP$a|#8#)SV{JP2ZQ~@N=IA?CVe0R* zywTm*n>pfR{O3DOdW z_^cMdM_b_08UbT$AtV{v-(%R;@UGlmW07%Y0oT#wQ=K}Xj*{1OfJ9#7&eZT@thg{N z_I~osq2}h6G-3bf7DIYVxBIXaVV~`Bhwqx3`yk<&xDw=zxiiH#5`WcZ@-+DF65d4o zoh&}goO(@jkLCLozPlx~Gjv~VE9b-4UwE(}A(_>{zlmX9`F6fPM) z6`E@K#=xg!^Wjr@nP>5K!Z$}!`>W*(VPaRjiI(pM_*DLW1K-Ume->{yd^ZU1ZHu=b zzC7W53!iF*X87FO_dP&(tyA!cvu@yLq3)8nyi!iK@3QKvE3K`liK^W@h8=&GBKvj; zOPyOizrId3+njsi_VeI*_VX#&w5LLrsTT&YeUZc95Pn64V;u&Y8~7lQvhlB~lMVb= zfZd7wn~r7TYH=tSup=byH-^!09DJKWM}T5w*udJ^0?Jj!qo7xS;)u853DExq-2wU? zDErj+pj-3cZ6(JIt5KI~wM<`1`BbZw;BQX#%L7C*?zqbi72d&za6I-m4IZ zqlk=7Mh5bKGV&in{(B++DJWMW%LQkq*LpdeNc#QKQzZ@@-Of0A$8&*RWiJG}1zrqT zrwtqq>O%O)5)RYKT!#)8#QNY}9mA`u%0m=#Va)>y36SrBgm6x`s3ht_InF5rD5+NP z+l2Nph-s2lSz?79++i<^G1f@zK$Fb>e~01EXhFe-0^Iq-vLMx5GR2;y+0_B;)>thE zR?dZWz|esDS+LcZ+W5ENQdn%wo!(TC0b`WG)mvc>uW@@|%z*j>`>}FHz|;&_0@^hv zazXP}biDIUi6OE5S4eC+g)n<47I@B^5!wtZ%(>DQYXmnBGvs4HFwJW6u*4=e9kLic zj0E085}T_D+??tuflBePgx-n2lf_3>LkE+oVz}pg76SreGK?p2IR^MTyqKkqXX`4f z@wrRh#mfN1-*M#4M38ed=dc|CPmSjI8Yqr|yL1VWg9~>27hrl+BfA>MIkMX~k*@*B zbj%|M>=e-Tnh8@g^4*~n&_3YdyK)V@m(&w99~4`48NiPM>-23?HbeL?F$ zj|W``%6KjYJqC0WD9s47mivSL5wssDj|upD0OUac2{E0Nh1dryV6j( zk)DBHR$m$--D`*gG(#7df65>j8#Y9YD-~hFHSJ7_u|`$6q|*P z@5S3v$0??^T_(>aX$}T;U2S0J5ntI-yS0>HjEcIl ziun~BZ|K-w6?JtrC8gzxAslB5CW9Xga4&ugeD`Loz}SJNaLyZBI{4OhJbkz=g<(^iU|eZ+7b(@U*pF?j_}rGFmeUEwl~xaM zgMkqL;u^I4oQrL#6F>%R&PtS=U@j%jPhn_ zj?zqLJVyZ&447lj^pqaom@?Q=X(?i0|D?3Cy3SN*BSen+Ml3?<$Z^KZeONHSJkUKo z?9-?0n6J?>6QjJZxNFw9@?Xb&-MXkBE~a7F>g9tZ0p zjyI`}1t%Cd2X)Mr{*O+I!#Ln#-*!$MN0KDY$k5J zC}2y?&{BeNrIqSRYvx2-T1qgkwE82|Jv-P^f74Qe zG3u+F^SS7=Lk~}qczBvK5WbJ<-hfa5KId%CHB2zT_g%S$pgYOR;o({}Pl8UN4?5<8 z0l?XHcyHGm3T>%WEhQLNxtNP!K$RB{*nH9Wpe=QpmJ*CBtwFA|K0G_p&z735r3B+j zYp_U}I)6i(E5_PVwOUFruC&rzX+=KhI@*?6ucZXzN{g!=yIfza>h^;zb-R`lj4Q37 zuC(g*ZC`6kZPikOaiulPDi=J)uQr{1ge|pKO9{p`W~Pf&Uy8t;^W3X{vPZT9T8bF= zNXro}7+^cnwR^GX16yjaR%2q^QX{|#2H1n>K8-$dx-GR(OA!N=gS!%5KiNNWY9sME$++biY{xX^~ zAFp2)-!Dc9hMPEDJ=n17M2-F0lM&Z1P7x`yzu&d!;H$ROAuS~sSDRvDMt(SE(ye>_ zsU@})AL6DHjH`aefEx_3ztGi9e{rr|KPPD^V%ivWJmQ-tF#HL5+Ur#Cf&sH^g)4_W zZ^u)r;~_?7y`ko;$2xS+dZ$S|+%__w^DG#s5)e?relq{?UH4K6ATnF(B+0A4tXg+hI?(l$HCBsdu&ep zYXn+ogt84LNb?PYRAoxZH%JEkRBdg{Ps%q)N%>?#XEZ)UIIibeEz3_nL8k2|pCFZV zhAO5zLM7!Jq@+f+Eae;ID5g6lXE9wNW5*U}WfrH6o0K`Rs33d7q;ZiAWlztX* z>~KDeICgkN)!5;Da&YYMv8h?Pbz?`2O$~=L4O4nz=7jOtS^4>SnYc4Bb~v9^96MY+ ztk|OL!kY5=#U*8B`czsyo@+)}lsP_J7|zK?cJ%!N9p68gp$VD!xkdSrtZ+^y?ktSW zh>ji3m9`a$Pg#nKE2`%f&#SL0HH$T5LUvYB(fCMCX00l&v@XXkeE2{;8mDzaH-$2|p>{ASI=Hg`bpfkVBK)GEPl$h1iv&?;yMTi(t(VS9fuR zsC0FgaD})!iz`IQI4jznj$eqke5OQP@pOPz%&hFptb$2d<8vltJ5`<8se@{&TV-CA zxB5xe#LWD{yn@{Eg}F{?`zD%_#BH>(!x`n+;kM}b%y)UN}iK= zN8Y?4j_i4Y%pB%qPAHlh3iDayqm;;AA4bINV4NohWT97yHls@>AHF0VmH?y!Hds28}&XhhO zE>;iVs>gN8Pq0J+6P-WL42e#E7bq=tbixj-vbq$nknpSH#dXoz`cl4(nAin%Wz<9$ za2Q)OSACQGFtB?=a4E)~+TtiqPZGOq2CN{fI4>LLnTcK2E9#;!?VQ+!TcEm%bITD-6CR8`S~6cHz+5GQp>u_J*Oa}2KcY#hW~Sx8~$xp7dWE-8%-{t z8*&c%PrRjT9xxz#+Bqj-4j_J8ZkoUL9_{OD?8Xu1~QYGQ`0CZ6DSpK}PD z-)iE!&MM6M>$95p5;r?f=8Zvz%WT2^?NPY7lgk@Ca6F6fvvaru{F%TUt8b^Uur1kf z%LQh##<8-*o}c4RA6WA4OpV6yH=Umy#)IH51FnX*fZ&*}U;aXy1M zU_R5hmh#sNaU>lB%NV%mES&656pw#-)|3fMffwf~FOypc%vvwbC%#*Ox!;TP#K-)- z0L({ToKJiSxXqM;i_R*CCqCwH5HR^(oKJiUfQfo>p7;_G-(?!Zbm{!sm+v!O3*1xs z24G9=`yS*!2j=+@JaDbG@BfC-eR>P5#qwhHW*i61U@y+6yc2<$;l+8%%hSW9z{I>b zpZM+q=J#HlCqA~vD;lFp;$MGHp~HRw+=HnKMSb+^A76q`+pR~Rpm43#Up6pB8rPD( zu>PumS>?s~l=nJd?)2h3 z6W`;&JnhAK;$#2)SYzN7=huH9K*$%s-OQUOa4ppz$MH?T+{)XCaIMwfbHMD?xR&aV z`u7bm?FLA6c0K!)Hx-yPFV0h5j;E7=ndim%#J3uljb5B5zD|hmHyWdI=&yfgAn+03 zQuOVamg;X0a7P037maJJ{(9ghXCL0^glnn(sDGKjO!eY?%3BM}Dlg7cUe@1rz&z;1 z`Na1!Fz0d(Tx<3B z12A2AyB5yE`II*em@!_Qr@ZXHGl5y+#rec{1u!>yah~{Ce}B*z=8w*={`P{u6S(X3 zt)`ahj}?0-Fn98nFR3@^?TAM5W7U~0WM zpZePf%ynLzCqCBSBO0S}=wE-;DBzR84ara_F3tVs559Ty05FG6QMlIXuP<)l4#q{- zTK!D~ro@Z$Dew8f#Jo69c|%C+E?}Pa;(X%!7?{6$ah~{kA-*nS@W3$kft?Totz~pIMOYK2@nXfSt zA^u2teNJzyy||xlNBXCp-qzGC`j?#E4#OS%qmA}mE>1yJC*9v}xAlIgrjMboAh=M?7t-?EC$ zBk(R=vCpkpR9shGPjgB7xSD6%U7$_*S%o>dc%m|~%cuBRDtBq!$p2hh+B`5%c9*Uu zS}W)7y-_st7@ww?A4H?%pFS--X=?G*aRr`}{cZrTee;X63JVG+7f&e)XXVIoeF)J^ zE6$39C(Chts2xC4!V`-o7oPcJ_XAj^_aaiMQR|i;?j+BvhT?ed70^ibF+}4lN{bd% zR~54$ykSrcCht_&&x^aCKuhaaQf5g-EpLt0)|M<6IR?DzZB0h_{{vIp{%u7~V86>R z#$Bi>;qf_W$?P0h5=)dZB%GaHILRH#E-#xVB64=#lrV{i%0~9x0yk)RN^xn-3qeIIG*QZs%Nt`T4(hilX&p71bfvJ)Y9q zD4rpx`sO_IyvC*=hZ{z#lcBhD|$A9mgqJNQn?)ez{2N}s+PFaoz zO;|0+^ZyR}+%f!8JzoqIbx2-)ws?|~S5Fg9=j7D|;z>(h zzg#?{R;~S{8a^=^9>c5tEL`J`e%n)#RV+meWo}maxR+GE)s~NY%>%d^agFe3&q44Q z{xPmjTv;e5&)iXk%;ynXx6RF0k*P(_SCLKQ-2R%i&P)lEd7x%dgH~$(LTF3~{uT>*L*DB@|j2Xry${h)QAdqA<_Z1@cHJkY;_ zt^%cIcE_bOlfER{?9;sKv@c2OhMZjT2Eu5sM9EPJiWbuS;KUla4Bqx z6*g2SF+FhJR&wAKDX|t@oj3E2l zqI1(SsCOXQe=ItD^zp_+9im$r4<$t(Xgt(8`Wp@pkQlWJA8ODN)td$PhK{l)6ReeNImiRypeRtQHL&Pv>M!g7;ra>W!# z+;oMsz0=hthS9)$T?N_~^lH#BC^~yXZ{V*5JpuGrpd1u3aH&CoJ~b#P9tQ=*V;Naq z(~+wN1?A(Q!1FS8DCNdz%AD93<>LU6k1HrsEaNtvU%c6Z6r+~uOvj#>`OA(``Pix| zZYPp{zql1LFrcF`U{714?~ZoHk+3?_6$V5)PgPb&#A;6KovI)<7vIZ(&Sl3cpmGOt z)_k74dLGU+|DWtseb-IILcm-*a3EM}|Kvch;2&N}poed?Wq)iL5s@xF&hFw|MqDGy zh)P)^U>Q*=9xNkfiU-RG+Qa84a{))0i$CF)0XQ_E6aj5`(OHzAzAQpnyz%`zmqk)0 z40l0TbX3FLt>1I8^sgQ6{)TR%hDCNt<;%8wQ!U>P%eTk!b%VkyiB!wS&d=fVLR{W8 z8J~$@_|2ex!)NXMx&P|XQ$CC`9ch}5dEoHLfuuk)Z^E$1eBG&sN364C_`DnRf5FGP zqG2m!Hi140`QPw2=zX9ZP786V;gmi#oGKoNQ^jMMnYQW3Rl}+BF+bCU*IPrJ!>Nr? zJ`SfPf+mV_o6axZSqQ{1-4-^2eTGvzM&)CRs<;`anG5>;;#SBX8BQ@Z=l3dzjl)KU zYkXQSkHo%;#NL28q%^&`IX5B}c=s`($mrZm7!`{J@vSFo>k{PFB{!5En*wXRlhSh5 zyj&2&uqAOJ)@X0ND+(uX?vU5GHIUc14J(Bwo0B(p8x>wx)Lj3OS`5Hy5^an1+ddd6 zEytCBe@bcBfR6HPB={f-!!N<*QChqLQdwSBJl{F%_XEt|`Rygh<0KU~>x&sc%Wxed zWInu#`+F!L^Y$3%DA312CxHF|l#R6&v<7q==tZF0L9YPa0ZPT4hf66geMw??Pw{Tl zp-HmnW!k1=xKdo@qvBQyPYh>s@eW4?rDLeVk)wQ6uw}TEVQS{jbbfJTgGA*$qMdOB z;!eWGpsn5*m}xLRCCM#^^7VpGr2&tX8~XjyP)Nt3+M}?snXC0S^$M?xd=Ev=`vKZ}1hn@D{-7%J zM|1siT9wTmbG$0AMo}|7s{84(w!Ht3@%BjkJ@v;jd-p&a|XUE>qjGu8SDJrz`QK41* z@W_6Ul+G`Hg$#5F8ePyu^#0JL%Fy69^>_;np5W5pECgb0!Ev`I)p(pfGV0mf)iZFO zfb^H+vIkC_Iv7Jd+IEH@)GX^6IBQFmS`+=hM$M2GH7ygD>6kt>4R;^plPlzZ2#sMo z;xwXRIOsmm@t~i8o(}pcC^hLyTxwvXFG)D;j@DQc67-$ano`Ngl0Ef0!n z7O%x%_=b5tsch)S3e!-poW;ktFpH1Zv-tnV-nYOz@ea#2OfUFJOl!Cwq zVVAX+HrWqK8dEH3^oMaU45_mAN*im~Zv@SLA4a-jr>o>6McP<<{|8UTfF9a_BMj@3pY>MS2Eiu7fW--Ajjr-keCul5z7x8%2`G5b&FMH$~gl8DWfptC&I71Qf)|p_usLYmio=Rw0 z=bFtC z%DOLYte^Coa{%<*T#JTD7yspyR`QV|ZLIsR;7P9gUVd*CoJQS0s*5SDlw{qPHr9O^ z1}tW5X!i<3a@y)XG~&*nrdYglO&rAPz6c+bIw;=aAv@fBMJ_c~ zYoRB687pr`9c%gk7OISvVPD3oeXt;Pn+o&%ux% zt{X02Jj2a3+02Nt)X?%T(A8>J;wl(UCa}miA$9LhVNni^gOmfK;ERmL{WM@mkkb;_ z*C4}1lo+mnf?+8#TrqGSDd?l@KAmoadyGf8`+D10qm_kuF@1yL4`uwYRSnV4p*Qly zG9GFz$#`gEta$?Feub%>nFV?Ca5qTvgzSu!99W_)rFoks3}alQ&Aw=JX<+ZqX!pp# zo?nrWSj!2J#HBtJsr%0J%8Bm(xCddq5MMnCQ)RB{&!Tcfkc`fM*AVDcVNZ@`MeUDVE`u z1IM@~=G+=h_X~jU;&X#C4e?pn1XsJDt}$MLjRfKw#x%n*3Au7H6IA<`QPOHa>tZ$I zVZ_)lj01;)91!kRbm|pnmpT%75-=N>3#8uV@xU=aPPoqjGGb^$iMhZKa21exmcIuq z1l|LL!ccK9aS`x2{JsFlt5xDa=vLMmfzZLMT?yp9l2-v|0v7=<2QCKA16~bm0HQn+ zaMP9mn}AD!tAN$O-vZ|V*8w4$*b1xx?gZ8X-vrJD?g2urWMUr>eka}s&IcX>t^}r` z1g`@Q1M0xBz?*>iz?*@^z*~TmfR_SS051c!01@}ZO~9$Z^}q{(F9Lr6>;V1{_$BZs zz@Etep8^BGyMdI)hE0Y8iwKKI;}wqN^fmO-8rsvebF2Dj$HX(BH#=QRxm(;IU^KiH z@W4F>v!%h_@Nip1Z9|Q#<%t-0{$nd+hPhiFGc38~@x5c1%^$`g50wq|04-daM^MnT zJ*o-X~gfi_v-lEwm;G;tNC9#Va9%lJ|Z{Vk$Yqs^(NEsA>}u+lmJV$97HEucKG zmJa5DlIzkW&kyO$NJjkQzW682Tx3+dLT=$u9h5z32Af1?Q#P#jY~lx1W=Mf#5&sz$ zGlU~MdmEZ(kP!?YtyygQX$Nxn+5lvTn}NfDpW=}jMO&K4MM+z!TshU1$~%Px|GvZ{ zTZXiy;`bMVW=z%?^8d!u_dL4pG~Sn(o(reRN4Pw@GDhwz_aZL8SbBoDLMRj@J?zb}AV zWW>i(27U_MXnH24i+z)ou3O(}%Cw};5;9#YRA>Li9N+)PU%qcil_@C}lrs-|lj2Jk zbQ};K_w9rw#W9pd@Hp~N@C#Ma4C~JiTy%>iwNl8)7ZGPz>;wWQDa|NeLcDSnMjLifo4UXlQ($CAD8k2_8pS z?1-#%{k_k`m6lWwls%2$afH%U#0G3VS?x<(hx z-fl@fuA~HyBdp_ulra$Y`{0>!OX@`>C3qaAbG(q^=UldsU*27ZN<(IQpFltTz61Dg zl+N*H>2xTckJsF#!%@ac#kl7d)ml=YDJj9@NX3al%3eB_)X^O2VFZt(bcTRxg>~um zI~G_{XDTVd;|MDtr0k_*Nlj2vg2xfoP)ArS9ZPDKk`g?Quuc+E_R_JW7Aq;i<0zez zh18GmpBZ*>`6HhtmrhXd9K?U4bWS!)=N9Gj$(p-#*q2*5He$r8{+85zN=ooJQgNz~ zGIFfX)E{J6QkKgzMZUSGC) zPjYz;7d(gX-zcvvv%L5oOOusUUYy%m>3X;7__HNu@JJNU;ZH;8UMoKg5zcMo9@CM=H(|QufwlNu8mj1dk)f#yY~fHS@I1mehGl zO7J+s$`evX=``LIKF^XWS5kt<5!Ts`u-KX`DPAN=BX}HPodc?~HCa+il$79cluo{o zx)1+ZCQoD>iwTIkbjArD6q{K(`DW>?Q9kDTV?^cpRztmXI<^ zXKdEzuUb;SQ&NJ*kz?mM!eU=%Nf|2f1&<@F0wE>FS=gEet_oRFpQx||k0Y#*kTTN6 z(y^ra@HGNP@HoO652~|tEUD9!l;ClcPN9(6iT^B<&#v9DH@S4ef`<$$%1|?|Jk&zU zQm6%7v$%+mGE#Br{@;9LNljK#g2$1HA|Yij9ZPDSk`g?Q9Gl<>i=|^pU8|%7k0Y$8 zkTOaq^O3f@EUCMcl;ClMRqP0hrDI7wrKALpBdm!+Di!}}ILEf6wks*Y<0zf;!Rz;N z)rxN;f1f<*+sUO96FgKBVU*7KX6YE02%Mi(IweBND4mqkroUoI8J7qM9!DxB2`Qs= zUannuk0sT=2OMDpk0ZxQLAA!XHDfP6U`d^+qytTG`L;D0>FjQrXESW-nwO7J+s zxxeEB+g$GsP^O8zhs)6R`7|}T1IengL`h2JIc`AIy zT7gXw$3;TQ$e-)3YM5UN=YaU>GmU2>aqbZ7m*jnT>~C6N^`oyMatwzCG8FusleRJ zMaqosQpU?g$|R@LuE5+LeDbLdl_h5dJ)C4*J)LC0W4e~|bdpjYA*uK#yO?uj-K3niTT;wTspNv)^-e`tdTtW!A(})P)F_d? zCQ)*_h*qRbK3i-I8l&OdXXVH}my2k0|)#+kJ*vQD__?j+B z(KTI?Vr#l2Mb>n2#nq&{qiQ&~zu~Hg<^_`+WSAZfGRU!ANq9I&iKGxz9NqM!uU)RM zIx5O;s`AZ69yxkUcED!7N~>>9p8bx1RH4;(JI3o{<(P^oK=K^{JOkq}9$J05xwFZ| zSKy)5HwcgZmWI=`Tx*Bnw8cxS*2AC|g69((Usqavk4OAZz4v)$H38eg|dlK2V=>}rTh`^ZbN(&bvK~jiQRUB%GYwrpvn^df z)FE^e943yBl@^|FDm9u|T38+_$IYjyeQ!2hLzAJ}3R^!?`#wTibZSwN(3aHoMGF5f zXpwT?`tUERi{f<-0nAmu(GQh;tHmm;>qyOFxaCHw!1BoDcR7L83$&bjFa-Lg|I+kbqdckQn~|KT?pn;IHt&GWoG;v0=k)eST18b;4x ze{|+qv(Id(ubfd?Rb5}du>R|7Tl)V@V-sgE|6Pqu+_=@jIb5{m7zxpt;y1T2@<0@B z$>fqL9aF^jZLUbBh~F55VB+wP%Yqxo1n#Rw`G_&tVLIXdi$_ z?%9&IRQ%2mG-J=!gyN!r*g6}iZ3r|jXlSgfTUZ~jt_t9ixxl>Y%h8u$<*8xef`$=+ zz?6mc^@~TOiR}5`xY0`;RYL*|W8VOSssz;3;J7$a!;9WVViMQ(SpN0*=Dg(UUs)wtEZ6l8~kGJaQ(Jn7>@p-*fvkN+n zJ(A6My;T>WnhruAHm#pzWG(ILtvUgo8x&txZ`JI$9#A|+&|bQRrcK6rlS<`XM6A_(!1FY?@@yVcF-T15zg?|ty} z9VlhZa6SAR37&j6pUXdH$8^ObePnrL7ub6n(zEc)2j8uVm+j3f|Jp%+5IlA2Tho#9 z?^f{KtN6@xxZ=lFx=!)HDvVeB4#DMF@U2tJNDS92egTy4d*Dgq{xO&%#cwotzNPrO ziXWpk13YmzpGSGz0-ihEe6IBJW9>8G+3Du<@b6RbbfW;wk>VEsPoA64!@mo`GuzGQ z5x)d@ZgcZ_`1cfeHoEy-{;_=bC?1gz{PQZ`Y79EOm+At{A!s-jd6n|e$x9>IuzB7Ppa^&@V+e|@!Z5rR4QU$_~ya^bxBv+BOyf+2^ROyt|~npBhD zM{3U>9|~6#mW0YGii)Ateh3_?OFLicu$M~HOG1;TOYP`W{+(-$yi;{H!V-%^Rn=6J zUSHkNU?{0iUJ>egDUu66>kO~v&#J$oy58`{xk|~U(jXZtYyld2;{(W{*$WrWtDdz0 z?+l)|#FD(#2uQp)R?NS=Ufed@Zji;5mrMvC)GFj) z1Rgb_)iCQyX#7!`!z6#jowi3>fBO&Xu=i9|KLCkoH4`K6Ghhxg^H_2shf#&O=sgs_ zr$Qn7sI$aRbZlK-y!&rii~Q%*&;JLODXAGhpLMDtTwETFOs*)Q3VhamW(~6Ek^nLzf_3^*0>3MelGj4xl z$3vAhcnKH$(?4&SQnLNT0V(UIO}eV-!&fz}MbP)u-tx0wwk|z=>vg{mypqxTQ=t+E z{(tMqYbyt~|L~8~w?0$+K+Z&LWjO``XZl(Xe!OF0xcI91NBQ14?{D2JvHMxj@6DgL zq2%tvpKku{s8L1VnK4bA^#gy$)s+{uTsYv($2xkyKcaEL55x&4&|fRR`Kgj)?*Hj! z7oRh7?UJ51VO>D@^TW=wSKoMF&C_K~L(lu9aOn4N^$X@=nZ83k8viY;kcA&LzV_!535Q6Sbl^H8k0=0L2ut|QjGXm?a!z6OmprbE?A z4UXzB$_(ir#VVUugBZ!#9$B>|q<4h%x1f-%SbuHlm}33K5`9y#{z`Gy3nf__GS;T_ z4du5tW@fDImcOB~7nG``Wae*-M~a))`J#AY`7bYdJ+%BY_S;JaM-4?U`S2b;HWdt~ z18kj{MXQ53<5v&Q8oxR>zv()L@1s%yXxEAd5xIFm=vk8)lXphH>N4DwjJ~D&j~@OK>`$ z4IBl;li(`ZXy7;?_9!L_fn$MlfY`R4Sf+m80K``A#P@*(z(;`KO*{?^1AhyQ0DlK8 z0`3P+0D3LmJ`6Xxbo-dH$)#Jy*)VjMOSjU7yfT(+)?C7Z--=3-s zj31>PU6rn7l=s$p=cZ{rSFrfoqs#Z-3OQL@SxZqv_4lAl<@d-Ltyq7d0{}fLoz3BA zvZ=X5DX#2;QpXP*jc(e6`qp{Wl9!v71apfUdjj%`Y+6@LPSl@i1uHujd3e(FZqFw% z+-e0GYq!3Cf0m!kOc{KE7X><$cQB{tnU^P zhE?fe2{nDusdvQFnhtkLHUCQcij0=hzM?nLzgXpWR|DAisDKk~66(7OGK=-U$C{!3 zB#M8-mgdCt%_UiAh+9jtwzAcws%GfR-zb}5ulx=1QZ~UT^m`TOZ(s6SX!+lbW~j1H zHbcMJ424n}gb`jHghnQWgT{DX!Rp~Xo0=FUC|ZKjmsLkYA26HdqL?moCZ@}rh~hVM zCaTMviUBDX)t?DIDe$)7UBu<>EbaAtn`Sjn(VjDHn3^ftZqtTB7EK$|Av6K!B^F%z zW2Jlzc)ZoL#V%B=7{-ZBn$fvU5zElTxDs*^a42vZa5Qi_kbBNA1cx+EB%Er$UyP#UpL$pmANquaS%8Wf(7i18{`CiD7Blu!9*| zpuL|qsA_KF7iX#;-+n-X)|gMN+U_r$sy3_{w|(l+0RImwE6xYyM4vo z_2t1gN7rZ0Tvi()0T~B&bF4wAQNrL&HW7dgvyVg=h%QU06vC`b+`e)<5M7dX2k@sr zG-9D?_AcNr@EbI7`wHHa#qBG%0(XG^W8i+^-M~+P_W)V1#^RARlQyYIMbd6luF1Er z&|TI{X=BZl2knk@`-h2aqkptH7R2O-Z!(K8H^duE4dy>}hwvtYIoC|S!EB3BRWvk|NmYAM z{STNE=~CmJ{DH|Brc6p>s&wAj!SJDtOg|7$UA0T9!z0!wJT%gY+w|ZFhNP+ zFy1Z22QkQ4*$=`IeZT#_DQE{arjW39IfYD)aj|~g8bmp!-xf>&bGDbr$z)8&+f!XC zW|VR&3B8=*VBXTR@GggmBwy;XHkM?)*yTiWsxgs_;(gAVNEYknoCO+;NHHVh|{eG?KuJL2AXtAjv@|Q^G9`+br3yx)`KHTnsXyuq9<}q$Q3E#@cx^ z$PdNMAXkX%KX5b1Y+=F8Ak&2fH-nT33oaO2A}nVwZQffCn=M=<;Y#Z#lW_SzoP>XB zjP|_Re;gj9)!?gwam0)*+ij(?*1G5IxSYj1@T=LBg8 z2q}vGASN!1`EP)n4nGb&54aY10q_YR-T^f%(})SvQ$VKecfjj_{{#FHuocLqo!5cu zfxCd4fiD1e178Fl0OB1naR|5#=tmr00#Zlgb|6&yiYov{0WrxEIusedck!F@)Rp)L zU23ftFmmrMl^vHm~l2o%I`&P4lV=HEfKrImbl>5dUkme&m-z3QA9 zyvsCs3pRHE%vf|*?u`0se0*=Ho^fSmUN%mr&(=OF;I@DfwN-TeZ;4z+)`F4!`Q&#a(R-EkKY=3yrl|)1m|zL))gF?&R~O z3vToU{o8UZsebeXM(}uS3^nT4Sud5Xv7}h5Y4F0sux#1^dXnPfx)S5__VX8@t6>h= zbAu&^?VGk#SUTO#g&WOR>HDkMvAM{Snka=tT}6Cs8Rr>y@Wzv%RQVNN^{mz;&04`2#jF!|uHU}8NUXJY zQ)o#|S5kt9`dsoP7vtmB=fW|{>ySVl{BV97R%ZlUM0I4|Np*aAGSve(sfKO4I@nC9hLnMaM~$jAlP<9BVKMg4?c@MMc?5`HYOVmx~O=OZkkH@p6$e zUdm^rjF*d)@lrk`WxQOZOmaHy*=5fF$*EosRc<(G4oSr*IIM}cUCu_eOIqZ#kvZ9; z0yguN=RwBi<;epiJP&f7I1iGaD_$B!ZMRQ8N#N9Tzk6!waUP@&GnV5y*Rh!b4=oFv zOzFqqwiG-x>a z%IOt9PB2Gf3|qkw3Fb)gdjLFZ6(74n5w2|-NqGjhL-Fu8jaU4B4*Gr5VaPAjd(NuKc4nW59EPo6p0) zh2Z&)o6nVh9A1B7 zZa$Cn-Tw85C8Uq=a8Gvwf3HX#g^j7+ar z{#AkRO7OgXlH@y5{&hPUUjp&abd`Usf5X93;O6s4?`7bb>*jN%m;S8=&uwl#5C5J5 z&qg<&%RiRy9`GD=^LhB!FNi$EL*vKe)gQ2Zj04X!H=l=pSAu7So6i+L`ga$2o^kVe z`1d+^{^I6y`N#ZA!Tf3v=U6aiIz0S43q0f9d@ldkZ_HFY!bAM?s(muA9&0AN!X_z_Z28=i%SG;Q7SO z=iy)9QBYNlhvrD>odBLGZa$ZP0r>H4@Z7BU(A{{}7l!i_#RID_UiGCFE_ZENN*#Ip_$_!gC_Xb^T6aGq;6)-)H+o{Q`n&{vzuZwOp3I&Gu;Us79Hzp!E9oOoc^R|cJ2sO?xhED*shB)rJk}}XA+9s!A+F*{ zWmC&5BBe#p6()~>`3%kvv(|Zo5aHOm}YMvO|=WvTgLgC0{ z({aDUu`Cvv6q$nkfzsCxEXTsqlCsH>DN`b0tldc04=vY8rR7+dlH>#aiRF_E8B0w6 zBQY%%VIEZDX)qqHYX@DN#xq_1 z+eg@Vcq@R)J+-1R8k&riP5i`=_KjYx|Eqenc)E;T%tUz#v|>tGs4ybVll{jJzVQ^| zAyHkED<+S(^+RRB>9(BF;-n?}7-w&%u};euuyW$PBgR?;)cua{;=^}e0`uq_nlX`(#LCiaqW zEmUj>w)TKr4$4T^*%vOu@)ai^&q*9&q!CNevlqv!#le?h2HA;t6*0DdaO^4dHPkMc zvk=pB%ws+VYk`fO;c%Y^rt#(tjzyZ5z_@~46!JXF`M|UBI|hsZvFAhV`{Amy+{Zzi zJUSq03H+8cSm=*wNR|6Iq>Zml8G`1+1tNX0kE55`$H5#AHFfy8zbBiwSLdk<=U$j|utoLrtwKA{ zI1s;CN|2IeCVt_rZ2f%PksQh_Se=WrQvZxd>OU>wb4xH*g@{!ub}U=5LR!Q*xco0O zZa51&8}~knq|1c;0yb<|{O2P2-$)zJ?d5-oawu3G@7bAg!^McVY798F!84x7WfpD| zt~s5KRA5G=rD!*pw%?n!k4)Pb6r<#;F>Sb%*VUwM1Hb#ED8C%ANxcd@#nq(52ODG0 zU>D5_qF&9aKXzK>!7Yvlr$^z*yy^vb(e2x}z@&mG4x%>HUR^EPA)Db{cnrh1u^F=2 zeNPdmpqVkg7XtY~VHS{48Fc z4$yoj_0mp4Gara^68*}1V%t^^v26>@J+Enev@@)aM`tOw_2Gy!cDqLPdeoEGqx$56 z&~F(A8~-$MV?B;8cb4Ua^$N5X&?2jL#q>-xpFm8<*@79tXuQDOkB?)_QN2fTQ=1=K zd($GfPq$YQWE%&C7QeUM0G1))sHW`c(iYPV0@6$fQL<^S+*VCR_}|@ZEd%7NZau zrxidJ!YUxglrfjSTsgpE$@;kyxdD}LV$yc>86kd+{SM^*ybuPB>PTpgv zVl@@DR-ALkY2f&&YckfR6*sl|vB4ZiDcVpsqn#ORCmseK2J-ipjk{!xv{%Muh^V`_ zBaH=rH6B-G9G&|gsEr>ZoN0Ir!|+)dS*$TdL{&*JPIm%HM+HkTLotFS%7705(d%iy z0yY941~UGS09m+P+m)4&HdzTJjg?T+=num-45_jZrH$d9D`-O%3#%3lV`lM4TRLdP zc>JPb&~L+d`CAA_RKS5LI1Aq!mCsqh>6esZh|<;{Ht9bsj>_ldzvMJ4pEx`IZ#RrlI~JlJkD}?Alyvfr#l>4~pp@V<&XRwYMM)yT*u;ReR$7BbZvH>V>)3-WTe_Z1~{_A^`W;7=?h}3-jC{e@iTF9s)O<76!-v-?)Nt5Eb`cU z!RoP`wKQ$$Y!ofklkY0pi z4pqUjrbDUmlbQ|vB0Yw>Jgw+YI~jnfUGQ<7+@m>f_m}w&5`h!)L1+2tvCeK7-c5DfD_E$JmX) z@xV>M3Bb)jw!kgGQsA>djP>Fez*Ru_pI8Ch4n(&vjt$%c+=1T@0qGz75XS}n0Njb+ ze**3T9ss@#v zrr9v0%GNAxsrbz~56?z+!v|jermxcQm*ivHlQx$7B0PSkN2C9S@$wsUBb(p!_h`l5 zmEZM3Vl)2Jf5UkBJrjB$#VzOGAJP9B zMwgl$(ZB3q@X@A2eW;`Df!xcr4Xq z|4{UGf_-K12C&8S5}cKNEVvE!jJ1yiTYyiog+yCo!GgBGq=s9@`~3&#s}3p%^2hbY z4;?u@nJV8~`KP3K zv1V*TE#cr7(dOHN2jFM4awj7i7EzAr>t$^6*Ly{VUT3W2i6q#D#RCi^j)fMLlV%_x z{ZD(}0vDrLghBetT?V#XvQ?O*OHJDh(>B|`litq)cOH@>f6WxOroX4gLrs4dW2eeAId-Bx z?VEy(lodzR%LB5=!p$|q;Sg@F%La6orS8iDhJMfHFDvjzk}=eB(U(cg(9DzVvlZoj zqaMIvoV{A}%4GVVsUwZ6wq)FR5~^^R$BHA=&C?&ho*c4j-vt}5Pz(uyg zjGB2j5w*d;4S9z`{D-se<0EGuTvhgcA{mi=hm*7Kb6c z$kPhnnm*_gS=G6;eATXHJ)hQ)?tRBC|D0%RhH@zkxg6Ceq=tUWNQCwEp%%X6ZpFd4 zh`vdG8RuQ2&5=CO5W^V{eICmC+p14_eEWV8XW48Qd$esR3|e$X6b)R6@+2@;t|F*5 z*2+~0eqrSboQq#=x~2?ilO0!M&j~HD`Px2zM1LXlX`4UZdkx-qe6%)x8p&x5H7tcuG^jV6aa}71eq|OL#t#3-tj^ z>ZXYB0qg;ulszPTTZk3g2Zj2gaPw8URC)9;=$j^tLuUfWV}@;-5KRS8&(UUqH;5r2 zn)AF!HuN2F%vgUE{@sfwMJRQ+N7&xOe`#BU*h`xaV+)r=QnYcfWeOYjP;d}V(Q&MSuTDx?65R^mcADYFHD{Y5B{+SIXA!ej8K#4i*%*G$ zQ*`hom^Pd~PE-KXfZqmUVwt!Rm=3%PhzVxme&Er-gFy5ci5~C^x;zu~a{w?5ME8-n z5QyF)u^f0T@Vh`vNE5#RP6s{>ycoD1coy(Q;8@@eApAcm{Af@KoSR;7DLI5DS2b zJAq99&w!T!9|g_=J_(!+dB7zfT!zh?m#;rBw|VqhG2HSkK{cYuq5OMuq{v3j3)7}x}S8n_bJ4!jn) z8HjcM#GAkt;K#sQfQNx7>%?iOXWs)3M?JX)k9_H%ElvBQN!zV#X&U3hx@j14%9jpl zOU3UdK^v-A_;rK^86iUOi)9bVoetVh@%T072mLmTm%q(|Q?8F4Cm0RC8LH)@w6Xt? zezUCTzhS)mz6p-%MJe}0jsEg=jixKVe*!m5k-2Z7@zq26Z;uJX@bX`B4*gDw_MNKZw3LJFL(wY5f4NE2%YT_Sc23&8{Fj`^=A>yk zdj@F3cMQ~q#gEm3l%F4}Q_r_o27 zj7b(Q6|iXB{W6Q)-Y<(Ud!l^Hg?85RJCw_%25!^xgu%p8t91vU|e#jIh2$yN0GktGcO*Fcu@ zBfyh@zX38%j|16*a7jdF8Ex_oBuQJTT+@JZSxH#%Z!I3#gGd_-^>INn6sEB<{ck+A z&SOJPV?XcBD(3f1#D8R__Iju+FZuK!Q|9+Qga5SASSQIXN&r;*)^C=Kb$alWH!gkB zlIkOTk)`K6dCT&X=e^0Yy(4R@B{f7z37)Sw7tJL;zmFfZXuE9Lx_gq-#WL*b96Rd^ z%~zdcUp(%*FRYW>=SiV1&#|*s(){lI&;Q4gDwjmmM8wB&wv$EY_x)VCU(_@A{p3`z zXZHIzgEGnj3)f0wuEO40z*RbI_*UuMzT)-Omef^BO7J+&cCy_3KKA>pH;12FKG>3K zQBs1(Q4=zRl!zy66G}e$qa}r65k~Mh!eSR`or^yIiD%!jq<*WU1dk)EzCy|fD{Iu# zODw6aN=ooJ!orLfVX;2Yj9RvOtR?lfBw~uqRNLDQ7s~uTE;7@s8F2f_$)zLm%C{fx zM(J25lMe|wE*=J4rNgn&DxK`tdKX(#oFmf+9!Dw$fNJSV*tBc^221J$B_((qIW|y8 z898>&iQk%TN#!aj!Q%*vHQ72L|MRn|erZXaucQQzBdlW`VX<^9Da=!a5j>8tIE!+Y zjwN-Kk`g?Q(&6ak_niZG*45Yh-g-E>boid)_hCkCmd^2J+rd0knB%p8t8`8fQbvxw z`}Q@uCG`^}C3qaEz)3fRWwf2|Z~rasBr@9Rqe@EfIC6}Ao>ddd-?;-f4;fO=DJj9@ z2rJ+StNV<`m?ia=k`g?Qu!cIq+V@i3#g^1(N=ooJ!r};P)w<(uYFKVbWpd^MBX}HP zp{dx?HD~KZlP#&!l$79cgcTH0qSRp1&%G1pFOA&zmXZ=Yj<8N~g!O54Fwc^js-y&u zBdk*$Vfn9r$yUn7yRP7Igms!Dtc|za*JOp&q{0$Bj<7iCv+BnB+VeMBQa@Hwg2xfo z>5i~296a|@OX?9NC3qZRoncDBqJ47P;MtbcMkOV99IYu!Nb#MDy<}^46|$LC!medt zxZvTjFr%-_GE3)=%I7RC;A%~03Mr#CZOeMFza_O_NeLcDDn#rx zE8rWg-=~7nMvTw8CAp=XBY0Zz-|*&av!zT{q_bs9u^o=f7g9_wW3_4hBa4%L9w&HO z@!#+{-}Jdsk@7{l>~r;Vg_O|-t1eEx$&#v9Qi8{k&)*VK#;l3Dek`fgN=ooh(+8`c zFieH>I#AA}tBQ_;$RE}Y9~B+xnT;&tlSGz*j1mz_;!Yx4QL^#c;$%^s z8zfYuMr8+GbQ!B;x(w)SZ}udz?oHo&T>4o{8ngB@-{P)lcvm2AL_29dw zm*k>I0rkSvSIvsgG9~%JLwiE;7}Nr-tiV2akv$Pvgie0Ip0-0{7vKKUn}Teg70^X08Cf@)xhl?@RV?U0tU(Q^ba3ww2Q!V4_72$ zO#ei6lQjNkaL<9~4~maNx0k*MPL%$tcwiOAOMe1i%#Xr)#z}Z+x{6;1+=hdvKWDKp zX8c_F$D$Yqo+8E9m4BPTR|X#5@l0d-=W%|$K=DXUSzk~$M}{Lsp{cR*Sn>FCPQt&! zlJb+B#L`%JQm7;{<)i?;{|L{Oc=G@0^XqdPivSsXeAeYM224aFQ)(S< zcX@;#0$Pp^9% z@l6->cvoOZzoc;ag#N*}=&9zjpOukkN}o_t?p7Wz!D`yfjM z{mqxJ)7RDic<6^Sx4u#_aSxVoZV~i@FV0=R^tO%H-d#|7RLW!b9zYi&=qG-dGiJsM zML+%J;_Tst6|3HZ8WKSte9DHDql$JvP;~8_!XIxwh^etWYnptfv;cjO*FBn_Ab+aZ zKXt7J_nY&g?&FA8;wq>)4PW!{Yr|D_IMf)QGop6Eyd&g3ln{gK>xLD_k;<>{$GqCv zM>>N!S6n^(HG`Q4wIcDaowr|kUQ~@1|M>%>nBo~nvcHFB#&1WxwOf@<&WX^4h&3?u zlj1uMnl@In_#IIm{^B$tfQReY9FjQm;aJIaN=`M7#>3U>p?HSj$;QJ~x|8s5%^KYc zE*zF$QW-vH9Gp^c)$?RLXW$uyhbtIdYv5{779RG&Ty^Gji!%?d*>gRaE1Sdd@CBUf z4t)R4#ltlwXma+adED z)>ZH~N6X|GY#Qbh4fAfCNJqw$e@&@pYbfui7N5c}gr~KcYYStdZFifVJwUjBNDOahU3S>532xOct0+NS? zB2!OWnzq`c-Jon~JX?kHe>gRbjgNKW{O_t=I3cnqTDgwL0z6P=DE^0U@;ULtbGEjLTd#SH> zL0x0KVpe_qti@<>_6tXqt`MFWE^`b%Q)(NOGM?UeGvS z#*E}eAU6tblCiGUAgi+2Az_a;y=AFl#wgk}Kto$g@C~pDI2yPTI0m>1$Qp4SuoBn; zWGS;|$Wo>)P27_qX{qp8(%``R4o$;8NA8r6wp9FP--Uytr}WZJ!4|PVRS$7+RGbrE z!JV1wB6@37f2p`_H+If$-b=q&t(=8=4=7_?g~}>PgTl~;+BynRsIxJFy}~@RDfm49 z4M4UsmTPQ9%5r0Y(ql z@lllr!(f+rK%3mrBx$$dx1_PF`ro+OhHEjL5Lm{(3gZXa?<+uEpxIt{xKi5qpDCgt zkMn~9UF1g)y0>iheUiNF&-`<4(Md6v{RdJECPj09s$l)```C-&ceGOzi%{DHug*vwtpRN96Z$mB#Qn)%2MY51Lfzvu(wO zHOcxU)aU6weoHDOWLRgwp;fm?1@Aj^eM&;64nbumdWf=8QQJ-@OJA6BGcj@i|e zGhO(2VOya|2gUDW8)y0!uQ}9|oKjBb{JswSH&U8zrj$KDO}b2}&1X*h{640IK0kWL zGfyY`%!!`gw;BHppZl0TuLPB*kMJ4kYCywPM$`n`x)A#yuTL;Hg6^@L;+%-hH76&@ zgQ>Binl#E9UvH8{B*p5y=b9bW$eb~11y!!2e$|R=&gksiT*1l}*UQC<>-!a$dBF=1GiU1{R}2s~dZ zKK2z}E0z60Kc4e?oAFwy

0}i_a^5Ux05G_%01d56$@5YAanhWmpxU%`#s89fI>C z0h}5iD*3wd?_@ZEuaS;wrB#FH+lsHN_%VGqf#*&)pND_H z1J4#WpG)&8qyH{=j#k~S8Lo$aqrh{no6qGR({YL7fmIl<{CgJpa=DAoEC0CBcho54 zGb=32k@D|m@Z7HW%yhWo$MStz@dyv`&nteff&Mo5p5ePQ4E^(pAKS<4;CVHdTt|-I zVeq7lk$hdnk8{gmibryK$B!F|3S4|%@#_HJ`mxaH%=dqoBjw-A;CWN=brnDMFJFSE zFV_-aOg@kLG7>!bZa!Ceus%-*PpzBJ!@ujm^IbQe%Rk2N5%6qq^LhC9Hh4aC^SS(E z`#5SGmRs=994WmQfv3{V=khNVek@l!!bAM?s(;6z+?ri{UgdiL?c;}&PH=jrT^$B4)3lB|K{srNd2c8*jJ`ew{2G6x_K3Du$zV|8~ zhD+m>f7tl1Jqffh$rI+>ZF7Q0>=JW9HJ@9<$=5zVS{OezYJ_ZjBlJA*+IJ&2e2G6(&f=%#wQaU{_OzI9ygyydb<^4hKq-$EB{#khJ&Zf&FA6Y0`Oez=JUwE zTNRH882`NLA5J`I4}z}>Ylbw;XRrKw3=Rvxb5f~bJ7WJl5j+EIMlG8i?-hgAw#pjiOd%$7e`kSbyyELBeyQ+grs9!4ddKe|9BaTgV~XUWe_rw14EojJ8DB2>jugMS;JH%q zbrrwC@aB7pNBZa;KgvJs;`55%{os2Pe3wj>zM1iJ&F?3po;HE!l?x>w^U2GF-FP6S_RUR?S51s~3&r2mAetMQi4a(zq z@HAcK^3Nl^zXZ<{iqFhvS9)0Qx$?Bfkx!-P_wIDwF zYi@=42w`Vnt&aC0!aiy54bm>xTGwG zkB0KdeB|FQw+WS6HDPwIX>j2_PrTm za_>rL@?^C70BBFrD}0B?70dNkRM%J3&8lwz%&(5uEUdyOh19;Y4UVd6Q}4Rc$WBe} ze?S2W52)~yABV`sO+?(1^9VzXPAw{`C?6jaX&H*VuEBns%IbOZjsGgl_WR6UxDYoSFAzz2(THmml3Tj~--8(EdA#3)Dcxc@ zS1zocV|P9V&K^6RNZx8hQ|u6^;QbBM-k;MC$^o#&Qq))MG5WXP_rNTA+=#KtB5vtM zNZh;h7_(khCgwfU_iKY&?C%yCw&2R@`Zy$vYF0D_*OaiDIk#i6pnu_%w$kN&R{`ta zDC7YPJEuzc2M>62z$hFZhhu=XdP)d)layYBk1DBsqeezH%(}9gB_t~(sx~8k16<=Z zOd!5f&6-zDbsMTiQ1})jcJdpetz>zh!LJOjS%ViYKvk^}Dx#COjU5f{6UdFypFe-$ z0#TP3{%QnJ%j{~Xt_T;Fs}^FmypbxYqpHMCGyBdnR?+X%OVMH*tQN}>Y%$_3TNhH@ z!17=;&W6lH5mrg0JX#tS9y1R`A(c)R#T>`)SZSd_VpzK2r4ik#$~eA0ruJ<$azTA< zWmPqriG5of+vrqTP^?J{;Gb|VE(uMDh<+wprFL|c_<1q}jH2;QdrX-1L(vG>LfCn?OaTK}c^p&(FTzf$kBci` zTRLM66t7Rz(_angFUO0ha2-1LLOwj*qHP`i;mwzmr*E25*pw3T z6=pn<5^C%<2kNTk6gH=XqEOG?w63%9f2f{4mjCjSpG9?sg`lY>o2q37nLFUtBBpM| zJ9mJ_7hWCDeHaOp;XJr<)`ALSmL_(s3^H7kka}bSpmHW{=watRpJAZcw{FdDoFn%6 zWSexg&xa1&ZS=}`d;9%z1AU+C+|MDL> z<-ROwBGSCAfpO;)0$Yz3E)s_!SX7yynneYNYGZ4h*c&%Z1xjFiSXT5W zMgmNKXa^z=1a<=+2c(b31G(Tf7#ILTlZGe*$S0Vdq3U;k*kzf}mL_xwO4|MSEonxs z29SA!j9g`YcG&XsJ!gJi59zaA`N=v!b2^@`^7G1t^BU(%Rn~$x`QN{mnIFR=dtNdw z?z|j^JYjfQK<4ELAoG$s>$u&BI_r)Djsl(vgq{)c?S2f9{;`e7yreBnyUV2At8Ca^ z+FXv_L}*Zt#wssP3G0*lLzDWTXytLxkRH(Irib%)MVspmMVl8LfO_?gSmkV}SFhU{ z*6X2eebF}6J;r1=*gQBGMkiUe^qS)QUHa!S{kdfe!ufxV=o^=fKVKibbxm<)Ye;`S zif*vj-yX?-E85b(aM_9Sa*8$RF*Ba%2Ce_y=B#RMJdK(#^PgS1Kh)F;jp-YfuE(Vn zKB!SI$$xI?1Nvam9ZuT^4eRmXH2qEV#m(Q^*IoQVoMX^EJSM-K;`{Jg(zNQZmrx&idCycJS3=s?Ee^6Zc zNyd#(R;Y;p-^jR$Q#XVc%m1K6->|G0kt%NcbN3Se^K+1F>p_;BucvH69!+fNA6+)c z%8!gycft!Jd|Z!!abe@qt+=}bne(Tm_lY|c5OT(icY!ag|B0R&;YI$z@cLWfHBK_} z-v|q;>-YI0`EOkFfJo@R2}o)f8NVc0*1R-jZx3~?&9sRANw~Qpb?-uhu(ukvkiHMp zbSbI;rN!$?@^@t1_dFS`htRIIlqFNRwxFiZGz_o#m}s>Fw} zmh|YHHOQi3eao`JEmM4=e3|}u3Tq=W08QsTU*mo>lY(LtRpa(z+%*9Im;OTJbGUiJ z;C(6K=Fni?Gl1I=phcFK4GiN21DM3%?g6%*0&yDwrx`QF#&8b39Fn@DHfOuKQ0^^C zhuf!kDH&%CNsU}`uCCyF^3L=2WK)A=;-peL-UeK^3sC`Xnh}%U#KX4k5ah(q2o*=r1faFKm!heJzRG;!26jh$y z1;o52@uZ@+0cYYj_a5B?+zOlv+zGq_xEnYRi2TwP0I9-gAutFe{Y)VF&H^$$=K?PV zmIAARGlBGXu5zckT)Hn)^p(Iy{B8kW3H(0rD&WJw#lTkJ)xeh&{dFMu-T{6GNR>DV z;77paz=OaQz)aNRmB0XS6>t=g^mBmZivX_$QibjJfTh6i11|vn09XV3F>nPCN~{uV zfVTl32HpYWw`}U3Yz0#HbV!wN_>xP;uqXQ2uLCeSJnt zJ0eir+|Yr`2@c?Lg54#}l{;}k!M2w4<2lv9B?X&tJwa>p4Z#EgkG8}!(?j`NmgPip zw&ZMCwQK3*Xv=ua&)1_5)-yx-FD*T)X%Xh=xJ@OxhpMxiTID4Dt$o7`ks%Plv#`T`g1H5XyxH4B4c zZE9G*0QPV959`N<^~ISXy&WS~C~HF`3$vIHLRlY%TT*c6z@Jk>ZM(a*z2lGMZ(iCx zqPOL259N0}iE6B6lx|zKJ)VQ1AbxDq-+hhwg)J##f0VWEr9;i3{un3_*uK*WTf(Pk zikL2lU+n7##-kN2MbHj%D5%4k5-3OSfY->n3qg~1UFK#OxSCFSd2kWNAk0T_<|u%o zQQ4hw!y7vUmS{M_L4$+5MaENC{Bm zc*N_hd`CJS%*+N!#u=pAdVH)9uVcmw)W>i>gvT(9Gn)?Ii}owxFVV=chgo|V$f4&k zAiqmL4rBvf3*_MN1n^1VZ-H&V-vQf!=#WL{{v7ZO`29R^3=kc2q7b+Th=E3X2Z#Yg z`wMU?@Lk|Vz&C-jfV+WJz&``gv1@Mu(Q#|90~>+6fQx{C1TF=>2fPuu4~Py>+Yf|Y z`vCYc@IxRwFTU%^&WpA*afyqhJ+EBTL>V$~3`2L>iAY;2esjMjbvR4IH#i#hJQk0% zrGpm2;};zw>xW^y{N)}-_B>uP7LaxP!Ww&A5LJ(7cWpGBL^Wvi?E$Ml)m(aP~DF|_0Sj*z|! zuS2oss^FjyC+e|aO}IHX$m4=|WkM+7U}nZmn-SNR;qNm;(J4mqU(C4aC$M88imBAk(jpTn=qPH(Ais)O%xAYgjM6$rs=9BKBj3-j@ zR?%(MmiV#yhOqy&jECC%J45<9;voqKn%045ub9QQ7lfMDr4-}-gvNVgxE%w%B%`h8 z;vEptWsfq5Zz)Y1Qe*k8F(e^14>3Inpv!0&n6SAj0Nl1+hEcg=cE^x(@+wV z-g&{Y2rh(p=}@R81q*&Nf{Sp_^mE*Z8d{ywSBb+3oJ)cQ(&++Rl4y6s{5c+sDz{9! zVe&j}Ju{G#=kMZiU!sM!Dh}vf3>@G9MFpLxXqzn*ND&k+!b~znS=_dQ8p1^DI`w-}qO~vn4U>a~Y zus4wX*-^kxfqj67ff>L)@SFUTfc=3jKy1(zcMuE!Zouz>K=u_ycw}EeTbg#iNqbP) zcl6MPxA%l@^HeQZ)k`~}JWV?`H$&@t zw^;MVa3n9@M6-Ea9J$2}Jz@~&yQsW=7jL~7zxH-!=HM<@tb)7{)eki1Z7N6^g3y{5 zrEV%nKTp^)Hx=|Jtpg8^GEeY@_2;6zmrahMt6KG)OM~Wu1KvROO*UuV9gER4|MMm9 z;!+W<`S#WDMMMR6D9whQRQT0A4cFDsCZd&et!%V&W-8w~I3G*VuE2kGL@C%cR6Hoz?^CGkMUsT z>;)`W^b=57*vRl^Ar^z7_Ea3o9RcLPnGIYB91TnWbAUerjsfzm32z{xvRweXtZcNU zX}96Oq}`=#va&G_hM~KxY|@5w@@O|`zN}ta76yz{F`GTce!DAH+LrIHL4?thqYJO= zKsSyqeCAGcsW`u8cXpPQ85w5i0WhhWvpt$Bsh$#byzl0UFJNBi#H5WF(z-| z$rE^Qut2ap6O0OcELbM+!QeDtNPl+e=`jSkhQyZgU?6<R4PC~% zlu-VQOZH$$<#j&U z+UcFQ5wmHy+FLtmtg5oLVtD-e2s z6B~fP0d4_43Va^;IB*wmEpRvR3E(?GyoV(^fKLHA0zM7=4EPN2bKviRe#8OG6p2(| z8?ZNU9q=gNdSG8*JFq`+GjI@a3y?avb!lU#K3mY_)tc7|MmZSBZ(oux9dv2Sgzah}!MM_Y!+7~!BRGfRKmBY` ztf=hDH->M8z?R|{T=d&8Uj8l+oI^3$O3l5&;kVOAE6&nydo1X`m*0|8z9p^F2JN{P zZ%NnTEon90lA3YV=JmL0Qx}ml@+n~Y6f|waV3YX-i-;kS#w$$8>BA&5&DSEAg~V%; zxirLArRDph$QHaQ@q5*7{qG_DwdhkE|M)~(Qi2hEbLc5%K(rYPN@W<}%J4D0wV=53 zSy*@C*^LLIav4VFvO|qKqm?UztXeS)tC_$^&ZoFzE#pS4TEY+X*&;l2v4ZE`U_ju5 z!9fC_2_pab1{KwBUc*q)aWA3^FaeBYtR37Vs&@! z-xu=_WZdw!SR0c0#4%9h8}9aFKJuD8<|}Wi%L8&KV;S%gx?uuu3ldhuf|nU>qHAcIZGJgddTYSzZ8(TA`tE^^Nn@iBgOD27m}-kA2R7!2MUw+t zok_#q2sONNz*_{md%z<-VbU3I`7Xx~_l$8w41}cHMndtmVw){N%nO#^K+xJ1Jp*0l z8L$rl)&jGD4+BR4`E3p>;9{s72P}Z>xj-%`eG6CwJP%j~EC5acVhfvCSQ-zUiQk1l zE+~b89D1;lo~Q**0A2ws2I32WHW9c4h!yq(6%&>KuLokKT?{>CK)hILQ-JK^m*J6J zJZ)(rU6K}rl%%oDnP$U~D!X`TV}Gzp(1t1&{-R+wZ1G4NJNldP_=ODpHjJ0Q>;|!* zG%QUUb}*y`b`)xZ+QV9ARS_1GCI~?ztU>rCeHd)o0Wt3@$d4sZ2k+lo4F^=(D$)k=|AQWxvzTt}B{=v+DCI=Zod9?=hk_4gwB zXT>c|_oLy4+P>@-(*GK2JM0g&b;9~)NI%^6m+ozEcW-;Qd&`9>;g<99Oz4I;Wxh%T zIv91nZxnEKD?8e9L$DPTvXL;1yb$9Ht;vnX&UqX=15G60LD8w=&Qd>KdwxY9*>QA$ z2i;${;>tJJPwb{h!v-n@C(=PviGS5k93KhiQ(4+BwNk;y0;S7ZjjY3~5B zZqk?CvFzB;`;m}s5k?6@o<)%TUI9Xjnf;aQ$JoEMg8mTZQ1*$wHKnhEt6`YF0G{3; zR4L*m=ogsgOMzv;MLPmWFInBhv+&xFfiT9kyxJ)acNo^6@E3bZ@v! zRwz#Av?|YspMnnA_~>%=R~Vgk_=C}*Z)Qh#VL}ze5QR@8{6YV&^2UaGY$bQkk8a$K z*f7c&nxu`JT=|Xb(221Y-6;E6)|y+P>}SaymTYS2 zEidkNHLj~z%l^tzwAb36!kycwZ4yeaGx$H?iv4i2xUOzw(Squt(#miJ{t<*dwgM1u zC-2_~itVK`r2xPoP(TJ^*?L=)<6Y0(}JZNzg|@F~%By0cBr&9GB{g^r;Uw6>pOcO_K6s znoP%V)fbg75%+9g_9jvm?&#PTZH)4}Gg z*ff&OBW&={Wy!BHq^UG;%u>Dpd@3%2viPH&S6m9|8`#+xhz+YFwskTN!)8@yu(=JQ zHj&iRpW_s|AvT!9e5Qw@4{|2Ueer_m-h5cBE{Nt8hVV-B0DwU*7?MVptw1T}qPu1A z2|i1&9a1^kJKmo{_)I7o#M&Vi4#BLz7h6H>{N71n+y|4d>V@|iXE%P&oM3Qbk&f@E zug5YO9^a9RgT~Zo%E<-MG2x8tmg#NTEAisi7KGvJtY6`2={6mw9JU1ahy1&c;;fMW zvz(UDbboehUJ%oYp~3W*cOH=+t;)(?$*NcHGa)1~D{nc@=Lm1n%|PpCHd)59R$z;fSD=2mfVau z#5jdW5JZQT+`cXZEPCVh5p%2SQzD2pxOyMHGspL0*hgQz7lYe|V6;_y$Wu))nt<~{ zv1|xrdE>aCQ9lkF5!h_NYv1a97$Em{SpAbf-`wZtFvw5!U=5rZ#_&f$$u0NP3h}*q zFyt@Aj{kOF_KHp+|C4Hb#Ec69bCRD<@D15Tu{$BgyO!RghwNoo1@EG7_;(L^KlyL1 z{@vw%%=F5e^9+Qgu}1u@(T)DyExpI1R0IB>uLgYN`f?pE#2K-LYxaUN9UF>s$TD={g z6Kvh?=L9qE^_*b&D8B1C!4hl#Il)|;j_Kxeq8}I^X(o6P<^=}6BTs<73AzgOZP0a~ z?|{An`Y!0Fpzncl?)E%5MkqJ5*bR1|g=qaH5!fQMzpHDC0 zQqL#))bmO4*e(>0^~SO=9l7fHqZ8|T#oCo9i z)W4h2e_LOp&$@niM)k)t3jZ)WbD)s`!_{@pIHn=@OOD)}w$sWu;a~8q(GA_fq*P{5Y)(O}9xEA)nk8+g@D#JzU zzs2Q5c$wq{%upvq^I+#q12?ww+V4qoV(^TQeXa}WOwB(7ZIx+&rSb^tdoJj4pe3ML zprxQSpxES*{n86SSK)p>DAQdH%C=73s;$$PWGuIME3_{ORN=&<{i>}~Mj46UCO*>) zG`{gm<$qhH$?m(oZ&u-04$?)+DlmMDc>e@P_pEZ#n>pW_I{#M*i6rS0h&d1$I z*Lyz4K!$&XE2ceZJ54osbr>OSDHY+~?!av+7$d~E*p}FK#%Vsb_2i?q#h@wRHGm!u zdNC;L^%Br;K_j4SGdpmpHbb8>9jDKCyXs{#>Ij|%Y{zm znouD0U9Jm;8CC^DpDGx|W5FmMyGG;UQcSL;d+<{a^)1RX>=dv{AB-+c3wM4gyOc34 ze=CeHRXf6Gv`)&vR`euTsh3-Ld+c}_{Kh4v9Za4!WuKgjIsAOi_#N=*!z+mY)pzlL zU=;7uui_h&lfl8wOIbsaH~QLoEc?}ff2ob(M|BFr0KqWQ`uu247+-;5;*LeQZ-R}N zWEu5`2ctRYz3X+yewCf4c~Vv|It|x5+o1_>=9d&2_2^Tt%5Cc;%>DUcY2=a&BYb4~ zhrwvKPo6a}u4*(tNc}m`upI>ep#6ai%a0xJBOiKV)e=xRbCU)5)O#e-wd>q^iIvn&? z(2=0GfsO^e9W(?A>ynYvK<@&r0lg1&3Frf$%RnCly$tjr(7Qn&27L(h5zto9M?qf$ zeH@h2geO3^f<6h#*X*Z3J0OiKLAkB-3@CTTp9Sp)`XVUvunP1j&^4eZgRTQD0Br^3 zkh2e$>RI%u|AkY$dv$0M|5wpqnV62@YRFN(MBH;?U@sZW(@>U}jZwaC;BimiZxBV@ zrt{Lvb zeAa}8tvu89fMH(fxX>E&fLTzsQ2)az7LgqdSJ0k6?GBi1ooO*5jFUCXaWh5pH=;J_ zeH)Z%*{o}qEke~UecFzO@U8?(@nlMYnZdK*#|)miEfdbv1L${Zw(x$i`7#+w&2iFi zj*iVsFxKYu4K^<+Y+Tyl4<8CM8!u(2j-bLQwsGHR>k*7jR54_)G!PMZGLSOhTgax_ z)5lmO>XXu(CrrVZv_3JY#!xIQ9KW~Woz|QTUslG_+Hgg5!TiQw6FK}cI&1jtgyEO% z1nk)1S7X%hON>eqFpONSj^swyXSbZTU!w2Pd;w-%If0$nj9C&GyR=k>RXj^3%Cn?# zX=#V#rmqoCbYeIZovJd*0X+If2;XZJ_*Z4Oon~gA(|9P$VpPHC?dstqCA1N%4tjF` zEL*ag+rOIKJT98ojInw(=JPue@a1DR78inoKAFpp#av!qXb^WkHg_O4WRv6dfYCGV+-Ck8 z9j5ali0Qn?6Jr!o&7PJZHhtK>>_uJGf1H+hLU7lre~m>b0vWC3E2sh+p(QNhkz!64g>81Is&vi zXeQ_(p!{y>FwhWaUr=rm_XFj3Gy_0~Lhs?=ss2u%>hFrj{;qh`$1*V8@wiu`x$?2U z3=rO64OyfqOUTA3UpMel1x*xno6buwpG3~l+|yuKA?0{r-`KBOSeM$0-cQj zM)N)x%@5V1In(|BqB##9^zU@BrXM)I`+c`-z@K-Yiw4KyjWu$?ocVp@z^0GRk0z&_ z%?W@TYmb`<+sMV*`;+hugDG{GmKKb|$OUIg%1%8Y;oVo(*iyr^lwceNEcnd!`#3|Q zoASp#Sle>vf_3lr{eoXJ&7H0EOr#hbYL&T&IWm+pQ@@X`p6<=(_@Cr%%}EIH`}X43 z)ZE3=%#Wbyy2NSb6V&fJT8rFy>`A}IYi8B?eOIEA*h=ZTTAD9Z3~&OjlJAZXyX5cB ze!9_?YS2=Gag_WaB9*Gc*Y$ho9b4)u%@vIJ@4_!W5<%?hWfXHq_`XJuw>fLUS?=I) zB;1JNvoT+SbGn1WdFQ*h6ehMVlEL-+_`gXUSbiybXH0yFv7BJ)1sJm~lC2W!3@%-= z;V!YB;MyfN_|>XhTk23PB^XDE9V${1BYfBXenF8fb*z>WjH6%la>P~j!O5An6z9%# zf^o#v8(h^6*<(8yU7xn4_}?6Kf^o#ferD(E;>BbCVN1=`Qi5^Bb+{!(tv3~P9%xJP z`&2r?IC=^{XY%`A(cypVeAl4(+UYBp3}DRK>0{N-$=U-pA7^@Wxaj3XB)dPtey)z&T?`BQu@ z0)p9&u4LB5AS)N#d!ri^my5yR+PQc%{QMcVR5x}@IKen_aTK^}RA;GHR{VUpEyZtF z=mg_vy+?y<$5r*q_}gu%TrDLSM_ef)W%kO;t~>7!w$vOgB^XCs$2j7OR=xMQE!Ci< z1mlS7Sdmiw4!t((!Pjl6o3)f+9C01zi0k}CU5>J)p43u;am2-zY>xm1Z@m_>r8a3P z!8qbN-VxV^0jsXHr8rvC3C0oE3E=vDi4qEv4A*6?x1~C<3gHCfXmvxtg&8TWb>Fg^ zu8wbYe3JToyU@PORyV|Ib%V9$A#tsaPky^4++9)nf-N;tO9{r2i{T<=wuI@$SKe() z@!3Tu7)Obn2(BI1`CV?_VM~>3DZx16N)sv7u3(D2b@@J9Dx#$XwS!_b&h2x=*|rq6 zdBh1ud|0g4E+DfSZ0A`VHP4Y%z8FmGjEHLsFt3J)7*~&ev#yP=({X}{oxNvTb^13Q zS7uzDo+45*|AcSF?9R8@QZH#K!8r1Msz{l2>Pvm)8e3|smJ*DkoX0!jI_05xU2Lg+ zT1qgExUxhlg}=CN`s2lUw$!0~v4G3M<$Np2CdX&y>zg%yJl>WXqNN1mh--pKah#{y z`Pw7j*isX;lwce^E(ch@kK4?wokiM1QH7)MJ2R=7)M-OLs9vH$9U+yqkm^heW|4c<5%sO5?4C~B4yUj@Y0)l*;0peLLi)A z9J!bZuKmot=YcJIY^h_llwcgWm?lzt_={^*WC{e|G<{&*cpLvf^oz(8(e!%a$ZG6KU->$mJ*D} zpR73sO4Vs7_FU1!Ql(p$P+4*rzH+tZb5(uCw1gs&;+iD>jJyB+ zna8toj$kTcT0)Vf`E0GZNToT(tVgj(nJpnZdUJs-RimW@<0!GYB4xIOm*;%mYD-Wz2X&EMi=j5fF zGAdJodz4f*4aurRT(L-$v2j6mYU6^;2-$`6-}BEEM8Cw+cY^9WhECFMMZUGCH1wH zVIIv;eL-cJgF}eP=Qd;PzmQltjSDdI85dyYGA_W(V_bleh-2&gx%uke{(9M!#FzkQ z5@Q0KNsI|_CNU-;Hi&p5A#P=@onSL}?F5?{Y$sSr zr>C?Ntfbos)H(GIJu!XE=s=A7Pj=QvjvbSs1ZZcyM(nIt;hiH3lR-K!JL}i?RAJVy zhn@9bFfUvS+>1vl6epiqw6k7|LwY$Y)Q%soy{$1OFUu&*ie2s@pPSpC4#K2(utMS1 z(_Y@q2dvPYK!ewU+_F7wyRK42dN4s+qW>;rBC zE*H2|DuzqICFzTqvXf7Jg&MhE7 zQ(gL`Nh%(HIqm-(n15+pd*#Q8emAVN58!G$oQ3nycQP;&-8ff$@D;lh82QxqKj^z1 zxQ7lx-v*6g`slps_db-%HW$vTK4t^gj2(e5hbmoG{d(lLJJ#-x;QBqBRW7dlvi!yX zGs%tf&{qb`g>IZnAItA*U>m7gz7=`w%4(l-Y6#(!)Gj!>xf(zh4Evw@kZ-{20E zz6M}cXxxF)cRw&syKx@%u^E`HZk($=0!ZI}V2kJhrV&Z1l>57zP`{=t}&tz zKVIdx9{i;)oLBwwL!z8fIER}%BX9>QzuyCMhsIg?aHWs^xNDO51_T z?`mNFpmA0{Tc)BK!?6br=T*P=u)w%;6yv<= zmmi7Tb1IHH=FSh?fy&RHg)tQu-GRz)SQetjMQ7nW@_SAe+7&K33+Ku&A8Son_^)_e zbQaD--^MKD0~eizbLrzeVqX>!w(}}K9DZkX%*H4AISR+(^eVsW5wHfBGx8MfK;^d- zm@71{z4WpDJpjx~H_ju!?*j9=8|TVzUnXlJJ~G8cXT|HGZ!|Cy+&GuM0CddJ80w?* zD!(P*M_f3s^4kpD&%kY*L`?^7e?J1_4=S9M4_Eq_-@zKAklyKg0QEK&xX6;4$AEd!jq}j=F)%yaI1hcD3-Eq{i_R(+4}B*AlkLX2^s#=6fLZ9qdFZLv2tKK}y?{r|w+&B+?jlf*(#<}#d zJ^vY)^=_PpzAu3J){S%NV>x%9sq$+6O8v%c`H;`z9q7jW-?3*u;{Sj>`-?jB+wIOh z#~}YOT%R+eX!@iHFs0;a;l8hC`z#Ch)28R74Ag)*#^jmPbBa_1=|xkue19EW92;x~4l=s+JnvAm zfy^z2U2k>f5^QjXYbzJwE~F>H(1YQy38`T|K`H|AfkvzhNegcHAprn5CLYoR8fM z34YlQE~zdnj}4}=Z7gmYHOkm~)!Y)X)K2zBGnwk_1e!0W&Fr&LiLs`vYtdX2d!7OA zG}B^u_RQ(|vx-=UEQocco|@X~d6EsPqN#J9c_OCHRV}d`uOUn7m3HdIW;cptAy$)X zi^3AqQ)Xs#>Cr|#@=1Lz!{;oSM@_UGgePUm6Z&ZM-E44T%$_PvhlN{^H)95phgOC&uL$<;eGi&tpzBk&85Yl< z%%G~Ws_NRsQasdusac-&HFd>RH5@9K$Mab%MH5b+s8Yf%!9g44hA%n@sK*^1RRwud zXXH&U|s*36o^u<_e>(X<7> zt@6729$vNd_>Gsp7koMS5dNtvFDvP@?xv5<+W36_L+O);8FIcw58tXiyEj+o z<}a-3?)!55j~z>J@C+jE;k!3;{`!Ku_y4fr_ajD3TrztW4&)I2p1+^|&eXo2);~4- zkt4SZpY|7glO+6`+QzQ9>i&x73L6KH|2}8%^W_w9*0U{h%)^)A zEGR4m^zd!}UCEg(XB__NliRy~GrWGmjrg`u_@BOgd2~(ft%JXvv+$JDUBD7J4Fr)P3+1Tz@tP|`&o?yY{I%}tX)j(9*xF;$(60x4bo3X!-ahf$ zL7(0^=bFMt=HE8^o|50sc&z%4qQngudlS};+SB#b%%3~IH0H+@!Ig`a=RO&ZPI+$0 z<&*xlFm-$1_fxj@-aKSy{|}G*XP@^TsJMC7y`|UBeE5Ptob#u7H=WsG&B)z{ym9J& z-|7+Hb$|VoUoV~TMD0~mUs$><`!5%^6#V_-qdq_Mt>OPV@{_@z^?Y;KHv>Pud+v49 zA6;*9WL$$jAEwW~f&B+3n?=U!WS{~`ND-#4SjCtfV-&C#VaJ(5#vtq$pbWwFJ zXY}^zI@@EkGi?D}{lNQ3^RcxQ=>`9bpo2j-fMN&9cm;GU=xd$2G&MQbV6=c~SBF`mzHZ z{Dt(f*)W;0&4%ZmqZOG4p;zLSp=VDnWAQa%n(utfOO?GMb&pSL&yQ(5X#kmy>0{&J zoFzpw(a0n8?q_9yBEwP%j6hWaeMtt3S@BkCUy_0H*$;I&E#120v@B1QvWh99`v4s4 z>Ras;(fs1tc{G=y-t7M8OG-|$`cFmG$)}16OPo?vT|n7hIk>5!qEDGRR=ia@Gzn+c zgkbj!wq$T>ISk3*s2n+*61Lg`u+avSn>AZQEp_Aaqwj`j)BuNwZHFw3pIqGFhY7&k zl+^l@@}s94%@c-ZM-OS9oEDvu)jWArbV_dXA!SY|3OjS9FgqVT1f%#ZKkjRK8Ss=)$)@D1E(IvJrLrwp@=5wP+0pg+C42GE zksg))LvD1hdFq=Dl=CGc@Q+u2<8#(Vni5^4&;f(VIoi(Yz_vRYf^W1<_Sj4b+GS=qTvH4 z$XE(#K4Jx7wC;&VOvT!C+;OK1aCpc zU{F3Tj|Y7U^hD5Ypg3wrY#)pS{Ra2xpx=Xz1-+Wkej8{W`0Qp!;ZogBv=&0Od=>eX8&VYX}~G z;u7#{W0a3IGzyoWk4S^MP3NU|I0A7z&tW_(y{pkZj8%Y{EMIxR3gw-W>}~ltrm8py zF;hdoR~!oId!noH#GXXs=xtqa?roCMzqF^(1BOPstzm=ZK-2j3ES%84TF3gPc3ca1fmb zL*?HDOJ2=yo|Kk5wi?4ih$BKW;G7B8aBi7V(6VqGXP}GHzu_b=dTMrb-7P<2)`vsl zw}!jrM<=BPmnEc1mxaG2G=4wKpNFCYQd=&^QwX-OIEHX^*aZ2!%r#4o&yK#_GJE{~ z%9okwWveCWI8>`;`B)0v^5f6BnX3T5WE&1OUk%HqIOA)TFZ+kDgUj|a8Vnalwk>^% zT|9tfgfpIj8Ux4qwuxm2KM&~QOjV!GwPJz~dKxL2y<&M+MzQpLC5(|`PIlvZ8BBPh zT5e`VL-Lh7U(e0 zvq49Ko&(CJI2&{{D7tk7-vk*YpyztYPp(+Oua zCgEhS?nalp(PeoYGCIAyGe$p<4vzx{kv%!Ou&u}HFS>+U4r2t%c4A5iTL`BZC^0_o zqZ`mQ)160Q=fKunhm}6`7u8XRtX|v^eRHQDKYVy+H>2P1RK2}D8s3J@q8_2l_Zptn zC*k2uEgvQZcyj7-h>-932{JG$AIlu?2L_f0<4!-lS+FYXoI`P=TvhP}WkuC`mrWMv z4|Mt|s+(OV4YILahVN_{;DvEb^O^5{_Pg0E6_@-n9RZXNTTV#xThJnzc6_!JVLQ4N zGz%0DzDObH?Vxi(u|^uX1{5ta@_SI2Vv?3jjB3gBDFecacPH)@4<3VYn~q%7l9i9? zIYW59L9jlL^WD1h9cKb6R3@ZB%tCSeQccuT3-iF!e_OTZ>gra}p`HGm3CSSD+ z@-Qyk14f1S!iw-#%wZD?TFMLaTNaFqo@>C`MpN6;WAa-jj?3&DPF4fzs)S(X#)fZq z9#RmU{YGIy(}&4Ti=c)R&X~5wiE2zsQ;kctx8K&nc)liTLp8Kb4Sy|Y9*}}Z1J@ET zbfX!rOU%x!$M8K)hHuz;;82Z|CFj!~$!t6`F`CO5j&Z#KBR6j6pn(S0UX5I+X1Ue! znGLiK9QQ$|{PvjmBSGVbbhC+ui|1kuS=wk2U~k7Z%36(WqtY5Vtk=ZIFitkcuHcnw z{$J3jdcprR=tR)Jf%0=KJPxHX@_r`nQ9F@&pwEHM2YnHg8y~AcIm5$DD1zCZu@;oW zEr)#7Na<4tCo0~RIy6c0&NP{h;i{1;9~)`0@CIuL=TmenSsSB#-N38Dg+nm#%W^fH zmtN)t!)=d5%#xCfZm?*RxDFj)Cd)=0l|#ybR!R4@d;{Q9@xUW-k zB#OxcFBMI{ueJQ~B#OYjZnhpgR@R?z#TXA!ThHd^v9xa%u(xCT4j?GDebdHNDtKPD zL((k1%XUZx0`#C=UsY6Fy|7LeMc7T|;4&T4%x=Qj4x2t5PA!u$`+ZRMwGTn(fPMs8 z0{Ss1yV@t9Y~Wi#Zw4iP73deB>=w1SRJWiniR*Hj_nP)4Nm(%srXx~y3*}?CSR_2N zTV!h}OWMXLAG^hJK@-J#FrAm)r3lpLiH@Q+On2p1J;7{^%GU#7N_Q-helOh$=}Yfw zq;K{aC#>sW3=VfT29#n3GP9$RaFn|{NZSrY3&k{p>J$0Vk@?Z{6QyfJ7o$U#h?ggC#x(~Dz^cT=;K^guGXd5WoelsrB_UTi` zY7}pi4ow2ZCyMf`ei*LWzVfl{^HGcS+Ecq5r=lI5gmyFx?PxIC(EzlgUTC*$OUe}4 z3Scq7Mzb4CyI|4EaDH>$_Mn=`&^#C#4Q-PJqd#e@RWkg-R2deu9)LXCVQTVKTxO?9 z!Tce6Y1J$kT~C{0LD*?xN5^VZGK_z0hZojBCx&3u=^A*O-omn1AQ;_{d=;AotY&q} zOMffaa$aFx`iG(D=X_hvkfC{UG+}%}G#Mjy?%3rLZ+^=-m_C>YYiUDq@U=hGGRk*R zUa(}h8p@NO?vr1#iZ8XW^mQ3qb*za_Uj76`W{bK0G4xWYvlNWih)Jgk z3t5se*o9)+(aO;!)}W=Y#S`IcUvg75rav@#!qGpKQNT78w6ZHSPYg+cMAs)bCF+-4 zOp7o<;sat17sKS$R^~=Ed`jT$_qLP>bH8jI>tiifkT?*bqVUTpJe!GoS@;hqZ#Ia9 zpfO#>d}we>B-Zv6HG4ZgKUf#;=LfUy_58Tg;=7(7EHjVi2e|Auu?b+>*=_g&*MN(z zQwJl${PY5?0X-aa31}bCOF;XAJ`Q>WC?BP;7Zv#%=s?hCK?i|u1w9TF+bYHhppy~D zaL`$xCxZSSbOb27+x56qccU-K*ktiGYhRL-Ez@c`B2{-&zC_$}eGiWW4LMy?)|`z| zK0a#h$K^MOV!fHpOYfZsgx*6t8Ha95GP-W=Y9y?q27DtUzxeP1R7v)>e0||laS&u8 z>Gz65A$=pd86);|F;2kDYf$MSM&FsqM(ob$K} z4kUB(L4!pVX?gIWTpdN!nx_gvZ1gy8?C=o%Bdz4_7yhe#@EWT@$ z;II}tZ>j%bppd17q!KDTP`qUtxc$;--l9V0OVmgMaK|uKuasPzy25ZPH zO*shI80G5*9-rWTv24S7F`Wu`%B&RR;A0Olj@^T2__jpjh|OJ$-s_U^n$*=u!fR5; zncYQ!8D{`@N>hsEONCFx36I1}O6L`)Li&#K8%K>g#OU%lN|{|)O&B&nNWGD*K+@Hu zp>BKhLQEP=OXXq{Oc^U*f+gm~4f!Se3ZmPC(GS?m7jYLUwfV^uj<*~eFbZIyH~FeV zF|_0lc|RYP&uK0b{o;KfIETR8p};UF4|z>($yad^GQF(;=F4lcqc5d@L(8K0j)RX@ zj3HT6n>IB%U`PSB|3dzcvm?(-Z#2TgTc);UN8fu6eXK3II{&3sdhpG}OCkUJ(bX+e zeIfs*{HX884?-;oL9W91o?{I`BozIgcFxk$Urzr4uZW#ttaLjYZk88F#cb zx#=*m3i_lTI3LkAIiHtNlWDveINJ2Q6O=YR9}xOv%Hu+BOIby_Y#p2E+7sMyUBr)SdxmzdSPBoN3I%rl`j$ZFAHz5hRoNL!>El>zHZ>XgUfFaMct!*L@TzvWF>q90BiVNZI$XT{MfGYX{S7bqjW2b;1|zJ^`P;@;HY|nJqShLFexr=I zy(Ejru+xT*7o-Pc`Ko#1-pmUc8a`n^#bAKB21f*p4W>0V79n3gYH+zb4kzXepNlJI zdA4{yzQty*Sy)|rL0wI8iTZda6(|pf+GEE_Lr`qT;o7YGJ)7~d!FLAD)vDe`L*mlx zX3#;P?}Hu#x&?Hk=4XL^i2I8`KL#BN`T;K0@aR)JU5d9thpP8%#%Vf+tA?k1YvZ(QGj6YkVp*u(OFGj>VC(h*qS*G;GVnt1DfY7=)|Vm_W}dvn=# z@P=Nhmitqo9169fes~3kMK04!pzI#BCT1>aXxO3WuJP$_T+(2f_p*&2rnkY|7M|=A z6PuTYY)gZ|u}cf{}XXde=)q8FyN|d$lh~{^NpqHyx3x zXDc6jHoKnvN`JD3vgT}z@^u5RKeYJ`y~nPxCekUx(Uf}8`>-NMXX<9GwnpXa0iM!5 z05MR%=~TE=Hy_z5&8!iQDs)ba9Roi<@r&73>NcI1-d_=@^it;y8rq)TE~1wx*1PGv z^!f!kxOall8())lT-Qm`Z0cvZDk+wN^6~Mi^v9-zad_!hNM*;dyFA0pGD)-~oUy1f zi7mbMbSvb4y&hTH)NeYkbRVY5r6cT5{+HSab(*b-elOjsHThuN?U2$$e6`!nNVpV7 zgQ#Z0#(5zw_d27W+O&&#)W;lySQI;Inb3I3QHy0CJ8H#zdzTs`!8kcMp`&2UU%5f( zM&TMFOe4UQTr}KQo-3d*z$)A>Ed$}fE?zlz8FDxS<1_2(&RGUv-)c{4)w9ApdZ zYW`q837Z=^3kc%HO+Ol&gFP&74Q3BPeBe-1hzDsxj0Isn0x<`H2}_ox%tn?inQtIP zF`!Hf!~i{IQ8t3jXSSFfp3TWg2Br=&mkmar)AJHeBkCHKrsGYs2HUdgb5_#$Ns0P8 z0khdjdo$}~HY;;jdrE80W{*Rf*e4S3R91zaVC2BZf=e)Nhwmr}<&vm+&N~~6(~cy2 z62tjI6w_GL`I94fqNsY1<9|bclO4$j;xHZK4B%p;;5#DSXfzI{BNLSA&jOtWnhiPw zG#B(N&^*w3&`F?tLI*)_1)TzVHz;i2h&AAupiklcbWr}E!5N@Kaeo5*s=D@}%UpMf^37RPCHl3H=(MoT3*n!4e+_cZdLx#SW)@e3~fz)N3N?_tLMBzJVQ$ffzYWtG!J3|BH4WdC(~Oc8rTXVw8gotU2fs z-Tz9?r#6r|q7#hxh|+61$JxhDwwbFYnFVH zrMVGYx}-SGY|nn*4k)9(=G(9QDqb^33BNA{fTr?YRDM`epanQe9byaDs8nKMpE&_}cI?GPwiMevonRdO zf+LIHcb^XLeQxf!_}V#4FtdR%Yp1tWJ13ixM!;1&T<)`T@%?jMueGIE({zGyeYNeJEj3ci8R$TBHPY>>OvMu$dmJ*DkcBJL_ZiWO$$a6+)d?LPf_@79A z-yZy$wKKq~ot;|q03+b4og+oc%th{FWxv=``?Zu{9J%1im2I(TfIn}rErl&_ae{H= zA|O&+ry!&?dnyJJMiD#q4i*ds9V-_BD;McnbHH%t;wX_abFusJ_q*Ft`C3Xaj$9lq zQqrU0TXE~dr`u8$T1qgEdQWl0H6<|dR9otDEhQL7T*ru1fWNr@xVNFrmcnARIKepL zI+l2!nXl5CU%s}b)@v!jIO5{0(YCpH+xX}1u%$lNQi5^R4qs*bzV(t4tfsuZ0?S42 z+Bse@sbHIJEY+$V$r!>@<7(#wkur0!u6OFGwiH%Z#0kcciy3mJ*C3 zt`kMd9G`!H3u{-XC8(BM^ddET(qStlGIvYfg)+oslAC z*3J#<8rIrUk7y~uIC7CLQUUzZeQ@7LFWFLSwUl5Sxflhk-}eWk5P!yF4?W<~#!eCp zKYlUW*eEL(A8O5`;&L%sq|97A(0g^BE%mLI5{x4kV?@eqV^jNFd#^3kO-C;nN4;k_ z;u`$I$uUyLYbn7v;up)woL`wV^*tuuD^iqQ@^`?$X zFpjt;JL1~&RPN=r)Hhm6Fphjp5vc%v=?)9+Imwpl+(~f-&SFt0m_mdjd+ET}`Tfzy(5!YOB z?Y8mMwC=rascbDJ7)M+sBE_~rcj4~`FSn)6(NcnOj1r~5{wMpVWrBGezvd`WYPFw> zwB}MZO2n*3m5Y>_o`JIx2gQ#+^8~XpMsvBP`3kMMJWg|kNOA3#t@yOBw|p3{xl%BR zz?f;Sur%MPHCI40W=%0Gf#-{qIkK&I@~9kJ>S-+{7)QxpAW~+poHFjNYFp|ZEhQL7 zT=N}q4VpB%$(F*&0pbMXh^tDZ_$=Vaw&J?KJ!DJu>LNnszum>;Yk^3a`TEnlKfG&8 zjnq5s8d$f*sQUJlV=)Jb8}65WM%WqO2S3ve+KJM;M55=UZ>i)kND7L$TCvm0+b0c zj{qrpn7eF8!XrRQ#Nl-o-2B-4N;zu4Gm$#TE13={XL=k`o8(@j z6{6L61nG>s{vp?$d3Ug@0NlZ@+HwagX{#XI!H&Xk2RaMH73%u8OP!0+DQ><>Ks;Z? zd{R63c)m_)_5A8uYrD`$F_Y+IJJXPEcCk3Nr*yjE^>0B|EqMl-b>tan){tkQSwEhE zO42h(C*3Q|wpVC|I{tMbE+@`VcUGLC?z}id-I;NQI&p^bS;#V-Fzc9j4?m4j|_prsT#PK+Zc%$(?inIqxtf=dd^GDpKz-C3m2z@D5XQ zUbU;+f=7_omqgxQ-FSaqp&QO9Z8+5Z^+k$mI_(ClB%5YO+mUWJSV^~&Fr8=b&=W_c zjSR%N|74XkedLHyN`O{L=ZRI)L3q>VzcT44Wb_ zc`azqDrqY)Z)qH-*qdg5ga@S+=;-24+1v|xO)x)mkZo`aX46sb>;U+;QAknpBU$rj|m7L8;6V6mjT?8 zI9zKELU}C8Xjf z#(9-<8p6jM1P)!pn0F93wyP@+0>@>{XX0@2<;VWf`FQ-qIInyVl64R`ZWUD?1dj3E zaS%8*mG=(YFu9Way#PlKkR~q*+Jnt;cBm39tY-mjcc!5*pxre80w?*8t<9a z4jkNKoL771<7)Up;Mo2O4g$xG-nxUp@ezIBLEtzZJarH_6tnSu94@}SbOr9?I9&X= zmIU1PgTS#qcgNx4<7GSAdyu$a4g$yaAz$*6YUkAs*kAoQCPGm!9GbI{6o-p1mu|ov zdJs73JMtiL#~uW(3-k>?NZgo%z)3%h!^PJd+rh**Tzt6@S9p-PvkwBt{FWXBj_tYX zAaLv-i{fzc`DMLb9EXd~FUzkf4i~SF@kS2<$8qSII9zG4+6)2`OHD! zSRa3n!+EE#H4f*UzE=+d$NJqAheN!s=h4R~m=A$lnGXTDdAPiuN6Y>ApJnVCPvD*_ zob`N@S31SxFZ=oVz+9wp5L3??*ZT*z0Imn-5jW05-z&hp>&ChC4S>Eq!1UnGEu0mv zhrZ#!ob1NA^zk_}3z!Nw&O_g2z+C6Xx%4r=j{~#8jq}j=4`6n?aUS}5;AJtDFN|OCRH1cn~k+vM||sv+^eb-mT{$93jNf?AC(fsxo}w-K{50_$h~tI$Af9 zkRu!+rLb;k1@%FYN-o7pVE3}RCR|y)0RPF?t>-Ao2Lsql>dLEYt8}Q#MyHoiP8vL% zi&Tp7zIcYfNN>2ln|4k#3|H)z`>%PfsJ#{6;3t-!&yjpB1y6lw3 zxAX%QQ9F9Qx`0QEpl0@3Y13AxRY~(~!t6%>Me~veio?T%WV?2LyCQ1V@uYkQ?eR)r>zIGbUlnw?g3&0<}jSb^zg-7 zLOe$J@s=oq!jHE^*&_USOO$U5Ki(20|Bu|u66M*#kGDk0FO$72NUj(DmYLT+TX5I| zcb#|k$tOPD&>3qy+l3!*p>k*k>M8GE{NlY6kE^L0{O=FO|M7gxq4}@9UY09yoDlfE zmrvZerTL+;cYOP&?PKcKV6E~Q;m2F9+%Noi%au8pclGdfymD)Y-Nzn&SHiXZ@A&Iy zxmRHNFZ_7Rl~)Kq-g4!m!oTd@PlrGE%VmEXyfQie+OacURF*3@A?yGK{3|c6Eb3P18*I{1p+vE8U79(Z6uCJ;2 zjS>A%S;@rfguFfc|8FLXFtI+`?3w=q(VeqvH4~NZ)FNw#;(%>6# z{NFkHl8njlae(h?Ox3<5qXfQ-1UFCnV95-Jcx?v{r`K`S28R(Hrbuv(u;u4}nJAb4 zEfB-AF+77-rb1q03*wqqf~-uj!QzBE{FaH2t44FhHyFPPmkM98@J8TQg>th-g`NW6 zc@jF&3Y}twa?yq#l_$urlAU9PQo}3>t--Gft+zrO;NwUA2}Y9@iYKy;_geUSN zLVtoUM?(E5auqK>T2^JngMYFlw67I9&5#xg7PGAk73bi@irf^nl2%6}VF zn(u~hh{!%{g+6YD{tZ61o&+%@tV)9uLM8hee8))WJMgK{53JD7;5$k}zp_HVwL*V@ zk1J{kJpNwGCUh`0cZH8F8HYo`H&=WdidDP;_>K_X@m45K`PQK)!NTW7`_yIxLxAu5cBYuINxj@m)!MUGcmFo?{54Wlu)t`&yLxDv&#VSi{!=x->%_ z*n;|s1aO}Y$`7?OKqrG@7hKGMp`}E^xX%P_1|0`_JLsvPe+A73-2j>k`Y~u8=x$K7 zY&orS5-9(DH3$l8gX|A-#2Vs=oP&Gxa5=pby(rRzdn|;@>7AH)M;^m{A?P~L(?GX? zqNhgw1v&%Nk9^Gp<-ez+e@BLa;@?#w6F_H!4n;aJrTeO8i8S$iOsF9D+>e=5Ev$Fs?eKPRT&Pb z8})g*VD$o6fGc2uz>J!*lFIVM>W+F9QpX5oFe_VC29w>315=^0pmq9_XoOb*Plm(}7U`2Zwnn`J0d4F6mlxp_ey zG8L`}OmOA2xb&jp1tn#rjH*^;7%7Q$A~uZccP9s?mzkfX2FOr_jC9sj*VmSm+4+LC z^D0|ME};vm7Ywu3256KiP*ysx%uHK#t>jGrocW^g0)d%a|5JAoP{UfNtU_P2!NRk^ zE<|m07?wW+=ZsBj!18MYR$9-sQZ-$LiMl{)Y1zEmGE{yEi)vwIU70Ftw32fCBZ3y1 zSX_y+Ef0h%%4(62x&!A)(pWyfvLME6xd9}rh(XLTybkoa9>rvb&c$=SE%?2qSdk0F3 z!^KKYYH7%|2 z)YZ=|M!#~kr7C>C5r;~K2=cCM5gMbGuCsxNx2kMGxK71TyE z5S%KTy0#NMe49~IO!fHfhx>Bj4aP60dkMw~_?;`h6Y!XT%%nN z-SOZtoKvHD9PO3U|2iZi12+l8^iQf88b@jG3XfKUOZwA%wv;+wa5qANF*1yk4`${L z4_0wyhI%kpfHE2LLGe`+|94C5c2$jBn!qWZp(MI9>Z4~;DHm)CcTEJ`ryJ4F_C zG{UeC^=3h|%g$%BqXybam&h}7pw$R>Y~1Uw@7;Q7Z{B4$X87tmXTO9bR(O^%CHc+1P_v|IjjCJL{jIo0xayu08oEE=T4vXM1$yoLvLg0ssdmA{ z|Dg0}YLbPhj+CscEs+Ita(jTwmE38*QtrZF8NCm<+_Nr5MALli{(9rdZX?&kM8dSO zjU#r(BWPE~ji9XYn?PCLH-jz) zy$zJQ{|E{lJcTfFJt$s-A}o`;K!<`Z!KF^$qc2HLt5duubtu*t#4hC`7@6D)qm#RE zbmMl|r`!tTldv>iu?a?qVWM)wOC2E~b5vNQghB6NyvAc>kdwn2X-Y3x@)C@nv_>+Ag^$S2Y)iiS zIfMpP{Lp9YxRdv=tfbdHvR5)1^LWVRtCE|}LHt%Ark1gRVo?F-N@xC>+;Sfkm3(SJ zm7Z>&Y-cpfSA~;fA{|0(wA&{RunS1}9UTq=$TaQPf}(3rWAbu8)Trp$VRk%1uv+}d zUg^wI_*|WxkAR7s!m>B&`@=Mic_wGH_q#fw$xWryQ}U_Yhmf6i)|Fyb4cd#fUdMW; z9cyw^nW*=QdHG}nHJ;LqsY`A;MQ(bln>6028iC1FBoFo94R$=_Ve(8OK$6@Y51^4* zsd3kN=79o_Y(Fqus-xaU%z+w%T_!t3UptK&FWwP8tswVO?thG;)9?BFnW+;0GJxe!8KAjx{56V^ram;%L1CIvsl(_bQ$;&@R=rbH` zRPRiRO)2~_DGm40wfHnKB`<}dLtA%zK!`b_x$w!)SV`LPL@bVJi>c;hIi*O&&&Qyp zkK#5id3g>ZXzj=%@a-(kMxW^bhHvLttsSY+x3e(9KY>H-noW zeaGbS0k#?}0VtTq?|*F!Kd`R*Q7lAy>7qWaM#EFTMvfFVT1&zF&p+3VweQAJ=#HiSM5lF9EUt zAiQ4iDIC{mRjRla_PvCTvqEWlK!tL1e3yilS)tWdXd`^zNa$5o=xtW$Bk-|lB+wSL zj&~z`%vDDk!qvI_5Z)wzJBm=nwel61>YCqOM_44 zEe}2w2S*S35{x4FR2)@S=-d*s$ zD!j)m9v^KRg!c`6>%}(}4~%u7_W6~6TndM|t&3loed;8VDb@Nt(T!T7}D zeGQ)~zhB^cL_&E$mXbIOJ{5Wld=E-!niV?13Y`ky{SrFc3SA1{J;J-v;_D;u{DbUWJg~RQRqJ zA73`+if<%*^Tan6zH7xd!3qt+hd=bFg&!_tb?yye6PZHrT8|(r&9F^e5wy_gHOfrmF3%I`F^l`zgWHwiKaxNpqIg?(mVq`m1Z_4hX@>~7>Wy2yh4%z+1$bdx(|pCX^Gfg~o3b=}KB5uU zMc4!C*%PnB8a2PTE?mUrtRmox>dML%;DgAXJ?{h{fNPo$OF>0gnw*dHbn8i$ay7MF z9WO27ax%X(P1bSOAQB zsG&?yJppGln8cW_$-qJg1>{FiF=Ghk+VV9fbxxCEhu}) zI#4VU7_Ff9fxZO#IOqmYjyA7>A`Xt0k#|Ag2j$c415l3eAA#~%CXC{d6F@%!%?14w zbOz{F&??Z+KpQ|m2fY>a3($K({|UMV6wkE?C%1U|MZN?57L+@4yFdql{s5W*x)(GD z^jFX(P|VLF*MQ=g9Jw8|Bj}$&apZR7pP<-9jc_TcA1I6l83RC5LGiqfi~&6o6s8D_ zL7+vTM}yuDIt27NP_*aB8=%-_jr;^U3N#6IbrNV#(9xhN`hJMMp8}czeiP^f(Az;# zCXok0F%yV94;lo02XqSPXP^b3KY5aP&=Sxkpg3MT zvI4Xe^cqmiDk8UmR)XFIdI9JQps0h$%b=KRME(I<1Nv`J?D0mDJ7JL!^hnS;&~cz) z(21anKw;P0SOQuNdNJq{&?eC9K`#fr2ecWKAJj)dUj=Oe-41#+=(nKPg7QGUOweCI zj|J_BL7@leA)tqXjsV4sDl!oiYk`ph(8EFJfZhzc0Q3)_b)c9PMV5fx3A!BgF3_7m z?*{!N=$B|8_kex~`XJ~|(8oai2bPi}Q(DOi#0KEuw5a9`}Ye9~lCA9q0&9%u^x-pznY# z0lgpmOF{nxIuyx?;8F{5^d-qm2+@Owo+YDb65Eo-p%sZQ31O%U=rLUc9<>mxd#)Dc4IhlH^|Ezw+%a{>B^k0`qTzvy z0%^lX1d2;b%SrjIO82SUXQ%J4q{ zl~w8=17u@RdAaRp$hNP+|EA!-THxO>)b5|5cSntw{U$^2>lu2x)=)c6P-1R98OO{o zJ*LF4_Gb<3U#Sf^`1DqsVeaJ__Wqv14L=5O$JmhVVS^`7L#G_ zB^lfv!d=Z`!>&TC=6@7i_H{-VzWHJV07+jLgc)p_aSld1z&vgMrgnD)n^py*KSg&0 zn*|i^7|Af|579;dH8Y46q-!v0Z5K5#mYeqMsqkj6oQ0v6W@^)P$dxHs&|=+i#Ma2Y zXu^!0EJt`=I?RE;6n&=^3nx0H@f60xMW*MWjmsb)LEPR9;ZVu@(bHhQ8rElk@QpRUDvq|0HePGd95X{EjRQ1@EuwJiAM}-X~S9{P)PZO@?ca_l>T9;`QDTO z6V&u__>$N~22@ihy0w0&)+zAz(lJG+gVk1;7*pQ6kQ7JFEl(j!r2=5y_?}R41;-9#V0bFyq#DhK`Qj8j26AEbHvrn)v4@m}iZ{1; zAX0~AZO($xKH%%EeQ0>8@MgeX3$&h{i^}I~aW3>d0IC`^Y#NuM9n8sI{h2>|^;SO` zVn9;1d{zB%;;~9dCtZIPXfNHqX4MPwLKDJ$QTQS%Syw)lH<(rq_cpVq0-8IfA$h@; z>!n$XLTCMtOy|ilW#Tpa=tyZO4@mA5Q#ZvD#>W%;R`^=m@=j@(f)wlii{eK+T z^Gu$3p1D5r%$%7y^Y~Elk7YxQFZK1JuXrE#Uh2z(=fh_Xda(P&eiGHgpdk(wA~ah+ zeA*UB2{;}VoMlXgZxMc3h96JNE8(k1;p*Y57TgN>qT)Lvh5HeFn3;m(PWa;ZWy$Io z*Dm_YNwZS~_c5L-4a~!hO5qrc=Ryg^+)ls8a&=6tdmIa21%6qaNy$tm%a{$HiVw40 z9UtF+%J9qL%vHx1gHOF}cEhJQ&Vx_o05eRT1HNCV9Q*`6^(K8Ce1810j9c;Kn@g7Q z0DLMh55dP-RhID-o+{?Qz^CY5flsCJ7JMpKTv=0TdYWrGP-&d!m>{_ri7)L;owm+dh4R1RjrS1fce`DSqGKg)>1 zr}E6LD1~c*PjQ?LAKsHdcTNiTBlz$R1>8^JQ+c@!KD=K6_bd36ywE%a=HS3>g-^B7 zlkh2y=TdZkg-?~^4frMr$Gh;Ua(oP*Y9kNEjUyzKdvkFqWeh&m9#^M)Pr!G$&~YuU zP<*>mp`XIXw_Tj}L{C(uJOIAK1UC`B0`X0O?@;m0gpW0ZZ++pz+Yfl>!Z$&DjVavH z6s{dURmwH+sd~8}<+}_%72j{+Q)Szp@-d@45-|X=f5XVbDFw^%_JYy+&m>nX#APpU zY~}Z}!}B;Xba99&$Cx>clf+t&N0vMM@OOdKw)PSR%C`2xa}t~%K8n%3*0Ti1C-Cu$ zoT>057aEJ>6DF3UCO^Ne^_V9uxH!Y9ib;!ku1Uw#LP68`y!itaYNg|Tj+58{Uc{sEA4&W8bc>;kLp@p*uc0d@dx13Vk>Pk=uG zd>N3dC4UFR8>g`g@Lj;y0dtWS&bP+*1B4!l<4x1>z`QVf20jdlQ)_zxPX){ZJRR^I z(0v#1J-{CWLhHz?NjAc7#@|B#?*kkP_-DX<0RIV?3y3(4VSw-(!vXnu$-aOkfLK|H z2LSg23<6?>C4M|0R{!ITfD-_@u3rGS5)h}LWwiyL-o?4LkF(J6O@PpD@jZaY03L)s zb}ZmTK%@~b0W1ULntVARS6M0mTLGhh-GCLeXbaN1*-rSWB!q3$#;KoLwXvZ?=P{b0pQcj3;oOrvu}+hsXUrIG*k35eY7#SEXFe1k%cJ5Y72`IYTfAdbym?th9`c=?mhZmmM#ax~&79Eh z7QdoA;LriapT3uExg8#)fw9g6d}SjE5+g*pk2r4uZeJ2?d0#na?GC#)7yG9$ryG*?}6j1Cpa@>pk=IutIa_g1vy@T#0c#aTYb5pjNj z#uV9S{wwW>@@i1Ec*XjpvtJ5I`SyC&2|oS760K#p{OnisFvRPrhFY3Knk(OaS-nKs zE!VNXc|FZ&I8xJPVQ9wognWr12w?INyWLj600dZ88ur^faDw6@{ZWcZPJBA;Ne&b) zb~C!iXFQN=aUG+Ovasjn0uIMh?edL&hW)Bd#^CkL(4lv{I`Kvf9QrQ~VsxZ&azRGH zwLb&l&K%5@8Ivoakd)&zF1Cr+bGQxzF?m zoMUl)thq?zqWpBaM@b3oTwxn1OI_+<8EU#g)`tq;YbM1jeev zldrvIy2bUV<|2)gi_-4(Ou>`x&f~{n4a&^nKDxt`#>vIu%he;a~na?R6R zq;YZ`0F2i&o-A-Dj68CQ#q}f2MH(m9fxvh@W=~nV|8`r=^VNfnG)}IAfbn{27znrh zgZrPh(&CZ;9ci3goX}c&WAdQmR#;rMnu|0}E-u@7J%`~*S2yg0UW@BO%|#j~7kif1 zGYwC=mww*wI*ZG+^hFvc*CD`IIovt5?NW- z<>Tk%8ViiqLz$ubqc;NN<7FQks%DJ=0c$fLf&X4=V;+VR}^>gO~(c- zuKP3>X`Ec7w=5ffv-HWEEUu3=7ipYa92YE&y{mA{=@!?aoC?8_#>quV_VQg)+_(R5 z^fxW8R?S5kCsz?LUJvIybi-~L{SS+4t>z+)lZ*P(>*4&0Zt~*s_gY*((_Ex+a$#r$ zmno;oBVYNx#kE;;k;chYEL>*4dH8+*wHDV)nu|0}F3v)|9+T^kF*n|0aebn>NaN(1 zDO~L1bpP1-$$J*pNL^ggIJss4SzJpr7ipYa#{pxdRXhC50*k9hbCJf$MGbFpU2xeHbW^kE-lVxm z#%&pz-Giz}hINaN(H5H1~TymRy~Z0&x7Mw7VFn5E+*Fm%|)7i#?qG4mN()K0{j7&pBB#? z;H;78-JhRmE2&?{LmCzLLSPsXb+yvhZNRiUFlPW0PhsqHwt8YcT+}=TzU#KWi}w_C zL&psE1fk(UY_s<3Wo9M&5D25ISEaCB_j@9+*39ay?>=^m;v)4qx)eg=m|4vgu2FpA zS6cnX!4}u0noDRLt3C6Ci_J-{nFpU0wYaX)TteeW>m=clcP{w;Q8n?07T0Z>OK2Qv zVKQMW*X8xy=UQC9*IYv5Nb6g|mB%N3@AZscXmLHPxrD}%)_g}=H~sqLfW`HU<`No5 zTHh8fvkpsUZok{&+NrsO#*x;^j00~DOl zh%Z-Ttl4RP2BtUzQ=5Tl$-tbRfw?>b^YaYM0~wen9T>Z=TYwT+^YFFjwPTuK_U@N7 z7ipY2p;5Tl=5%kZiVd*14#j9fM;g4t;zEkf7D3>Vuj4M!G!|xl2Ilk(%*76jy%Y-( zw>6{w@i9%9#F?eIMRSox;dVLVVcvMTrE+Et56HkAk%2kJfwAYO36WW~+W)s3@DgC= zr$Td)2KB?WdY!ha4SPJz5|3HW2i^I5;Zfx0>v%}xY#mm&wSsraUE`Knsb8(RNTYJ} zqN5ay`~3{e;9b)a7nAU7HX`N!s~%e@SV;UsB>c;;#(3YGZ0@rQI||ss1V{X(;nIObS-|Bhf&l zI$R$1mlWaO3^|)wQp9unf&fz80#Z^W7xR$9Z)o242-gIv!+!I+3-GpeloaWE zc}k{~Oe^sP0x6cVYJXJ-_ga@%nJMZcm`sg~%!HiARLS%5o|2;G7At}}e??VwWhE{F z(OK3|tS*>PHof|DFs!=KGyM0hzx$mc>D8(HD zcO)9Fsj4c|-1@|7idRx^L55QS_?98XUs~%ARh31f)#d56W!~*mQY4rAWYk)y%pWX` zl!u~WoieMb&wsoJ2%$5$Esv;*a2HT255b5(S{n$~)mE14GVq+PTUQo$P zlG12pd0lO-DbcBe%T_+rMMB6yTS<`wTkJu9byam;U9`qzmv%>mltt(9agyrJX78}# zRKB1UQ@~$ZR#jeGXSNK_I+qmTh9P@gR0u>fCykVJTsD-7qAcjItS+mJ)>hV}%XsR} zA*n`GBCm(C80)}TR~rh}mggWsw>)X`bUQDdHh-D*~Q)FDc^rdT0h-NR;9)tMr$bmW3;717?>} z{5T(Ov7^=`0zt~fL^j0|tngRVmDi$ILY1>y&rmU#r^`)d-Xv2}B-m8y$bA%DqO?2^ zb@1{)x|O_2d+#{q1xJ3151GSW$X{6=tgbGvgaVV~kq<1!AnQ`Y&8R1-K9Nz# zE0x(IzxsrM5mCPIX`20V8|MIQnsiRb>WrnKb+#}zMoP;m#qd@4eLQaZu>mI0VzMN@2!&pi3iz|kKMUbd(1i0^D& z-i|N$%r3`5o0&yh)>MUR!{s%8)hqO8CnZHIONu6yOg$P|=BFnmMU!Wg%)rMdB{Ncj z6D;#rm4?d8BH@7F_AyFH5x+($DU#1oN{S&B{JVa(HGRNbCmN|Nt*fXD_@^yIF^VQn zFPVYQQc7m3|1pte@f&CFRlsIR!1u< zD*e{zZmamHKZ@=cuEUUKp9|P1rUol2DnihRewjAd^ESPzG*DevQ(48h`Hhkz<)Vu6 zvS0*F=T~!OJLl9o7#|6RDuaIM^!A|AI&_JuNJVuu2AT{Vp@#dt=!hjLP1>L|7&#g` zad)Pv6{d!&s%t7Ek)U59v!^{ZT2@vL5iRq}z-kYgQd3?Ps;a1{@^g5!hZNUUlvakq z&=;w(&>lRstfCw}c}bB{qJG1cSFKm=6^_G({B*v#VKE*p9ceAl+0qqjx7Ra{c;n+rj_+NV zH<%e?B_mU{kx-SDvA!#r5pdGsoYGCM4AxcnJ9G`3bAuXxd3kvaW+RnW%sfhIzLKlS z6;D%QlCT0(1VNzGESQ?-mpSB7;esueK#~&0X%HI^W|4}k>+tRo3fK6}^O&mT8*u+X zQw;4&Id5Cq+G5x->^mm@sHu}@ed=_frzQ7gV#)odSgQ_rxU|ECc)lR5 zOf3u^1>Ae7WhWuQxy(#U?o+XcHy+D9a}QE9T)Owul6#s(@O2zuFNDL2vTm8*LKqqMaFkaE6+QTJ( z?}BEJrt7P`Y}PS86_@#R%U@1E++Pm5vWbccf4b(c9r>FJnk|Pay1nJ^P0)O->H5ka z+xLJ1dj`g6`TQ6jfjH zw+sQdfaX9dF1WqruM{*jny#<>QT~=`8i^1OxB6rL)`RY-Ns4N3`NItY#&t(4y1nJ^ z5zsuX>Gqbt4>gU7(LH~+BcXk<*|ABl;tvF|TmQ{Q!{0IRb643lOoi0sY7~k(e^Kd$yOMHI^%?IgpF7b`Prj!pqx>Pw_;wuGBO*&m# zeC)r=KqL1xe@=Wq2HpSs3-N6Q&2#B=F8TWiGy`U_6t;4>njuM5J>2@oUl4Sqj>{xwFwhify1w$q^3DOx+39pH<-H0tH>T62 zm6z?i1vF2k)49a=K4?7EsvLdgkL`O1Xr`poxx{xoXuh3JmzKZ75#Jf0xjvoFCB6qh z^LRR4T6}EZH#LnaiF^CvRw&~`(4ADPsL0IL52%1OI>0IL5rD<3WI=B8Ihr)20jaKC8 zSY9{%ycPJBpgE2w*5LM5e~UoVq3QNke-~*Q6{CCpl4!RLpetlX;fCYqmcJKlYFBfacg{VGIvjNuu^=)ZtP zdK}4EeoDtzGe|GjHNaE`u3#8A>?ZVQm{kwWp50Iy2sQ+wSafWtKdCMRLtiQs*43@h zXl+?TS@?vSDltS)<~%DH8~D+NNYKdFoTIFu6C<)q9?2>srj^RG6@Wp(x&*q3h@0Yyh1m?XN?Am#l2< z=xTsrDC}xs;d2Ex0G6fdymAiqouVPJUVo9Z&e^{Iis5s1j7rG!oH^KnX(+1=hVYrH zn}B@@^WtCHgg7&PAv0ErUR))``vHn)6FwG?Im#4Yx!i;{)-O&)5STqXaFWF0VlbQ) z{nJ!McRDNjJqY#{7`E^qmvUxW4fhE?(`tCD;4`g;-zxY_tKn}8zW2R%o@fh3RxKau zd8OpT{!QwFpgd2e)$p^Cp*+uf_nh!#&8Qb*ch0~0;HQtQyiv_RN}o(>WN5F&A^QKF)gr@;sSVz%LPerWNp~1b^)Fli$oQzxus_Z```! zn+@KJaBa5Wk6iiO6VHr3n|01k?4~|uS#SC*RtnI7E@i{iTm&o?iS4`$VWw9G0f9Gjhl(-3=X;OWOo`C)PZF(kYT~3ySdv ze2KcldEMcje7?|7Q=X0Alr)=W+%%(O1lL0IYln^MhPFj|qJ)Xna4X0pQ4l%gZR*VE z7|`JMay^hJn`T|W*LqehZpD{Ga&y)@Kul7s@?`qOC?Ay(M+Lg)P(Z>RfXvs6fP4ub zil4dwiM|}UieKTb(4k_xyg0IE_s$1@I4hi(@AHQfUB0?-0`@+l@a0F7r@{`(Tj8dU zaHZr*UI%H_*B1Zb$Ovn0PoDq0KX$)3aOL2;S+H>7#<2ITb$eF#@7~kz%u(SaE|B~K z_*f_SBe5Fw?A?m{3r~4Hylz_*zJh4-&942zGdl8eySEAT-^0n_2#oCt zuY-lNW?To_vuIRoShzyTiE^yDNJ}9J-UV za<%Sbu@Ys*gRvhsU^ z!$yU@e+(bikrxIL8lo~Ac2|n;{|(}rh+h`(kQdSSioFbl`x9_X&MP*rCkP$y*;77K zoPP*>x`{sS*)p7KB3*1B<#6Vvt*Jq#)*{TT6BmaxDa?KZ*@c-G&xL_g!Yq^c)@Dqj zaG4yi2SOaf)tzR_M@bnaxUmwh?2pjPnzd+@ZwPQc{JdhNgmIhBEnaNvgK}*Den$UI zO84HZ$(gDZqw-PURNN#oDd~5MTTyy09BN$nM1Nyl{UGBITn~95ZcpD2x1i@u%{HIw+!AA(8COThqIo;$$de)XE;0lq@LPQ0S_(&1|D|Z-fIsh zzJuF`k>_wC1YHu6o*79jd#{};C!e|j$|8i+kd#<*T@TjD_~BAaJUM!~b@va2LJUM? zc6WL0k?vjqG8cy?WOtv0p!Due1(Dg^{lMXq)^1jz1=`G6SMI0ca19b4$q-IoHMkH68yq`NN%yc2)ZKtL}bu6v9>02l+@ z2DlRN8NgM5uK}J0_zobh!ISRCoqIK+(xGaLw>X?^#YO2f&!vXwW?x;j z=_QzkZF=l(j^RxFDHy9I(w! z^#)>$B;OAdZl3j6ZrNkuWJPu``B6d<@`m|17$Uj1ei&Z!8S}XkePSSzP0c0-V!TzI zZ=maJBDC)1)dK?EpY%HulMv0xUV%S?i3R9?U<>!0h#v8%WEx$MH?t#|+*H?tPj|ij zLB_6kspKmPQ;PXLHKRP|u~?PK;C<~8ls-F>$nr(D1ZjO1yV8l~``UHMBRxUisCC-ve@><_|z|gD@bHDrN&-Uzzs^R_t zyX7@Bqn-*lEU$^lH4azo6IpV7@MQ6sef$^rYjWBQmB(~A%XR?9djarvK#XI!Ghg-n>4-!1efn~Yt#~Tj z!`hc4bjLJvBP;uKS>354;QF_kFHO_(Il4D@N~*TKPhHj6VplZ=wYzsUW)=q; zEa172q90oKU{x~sCWZ{m9ul!^a|ThBSOz5K4T0o?T@%8v)X*MA3xvFHtCt}>q4S;- zv(4W7sK(x+8e1=Q74@}?4toYVERx(r^@Z0p)HoFyOh}>u)RaYDT!2HvQv|v>7kx^1DI9f|!og#(45lMi=`Q8V#^3dV^Q;+Wta*8WaporKg8s%t*wGt{ z`O9cb!}qNpZ0s|2h%x9s^snxJgu6e2$p~3j;7pYrG>jz$YJvipj|Y;kB|i$~-n9eM zalHA<`T`pqKD8dRCoga}Wjgtk`39bZBvR4}(a15saU2ch_dB$J1 zPt>ZuNM;yh?v9dKhoE%HoClm!GI^u=0$}s;tM%YhjE2)&I@)kG<*;Fkfl^YLIq0^h z!puQ;BsiFF#eol>8k?G0I@MtO4)EkK9m`2E9t_A~l@7O<%QT!fm$UQo=JE=_0|4g& z;zU%OIXW1SMc|F*=K|&fa!4Kv_V( zVwG4bUpD@35S+(1*zjR0eMnb-V`TFHV;H8^L- zs1H%JDakORaCcu>6sbEGBkn$Q=NFSi(Wsv%ibp_n*bOHGQWU2EQWU2HQWR$bGDo}= zpQ6Z1@hOVO0a6rsIX*?v4@gnuCHWLZinR`O(Dc9ib_EuVRA(!ySP!DR2c z-cWAMCP8r)Ru@g)83%Rsx({Shmb>}nvL-u_tjU|QEzlF# z^Wodwy`I3V-m?dU5;Y@sjSb}9x;2z69}?*~aZ&&nWF~}ys=RD2pXdoC7Yzv{S0G?j z_LOarriW!F8UFBXyq6vxM7|5u%P%I8dXt5nRFkEq5SLqHu0- zyVPcc3)S1PP`w?C&EutzvU;>NHY5D_u5kCqvP7Nn%8Xi686p?rvoXpN_2__S9h(zr zV|98;G%+KZI1O?a$cqgQV#-z!NmMW1HAuYSL^a|HWQPwsH4iq=dX{BlEqXI(v+;g> z_`2TQweKOOAYYd4Gv+9&KTwFb|M!BkdNEz@4J3Oh2>D^omA~Zce%h=2zc2?@ukZoS z1uSl8U2h~=j&&2~{5O(Vv06=kxAM(>x4gMWtT*>f^5)Lc250Tg{qDFud|Q_(3nnk< zk=2PKld?DxN}M$szx+U=d{k)tSre+0D+^dLzLdbP+wW8Lsy|Qln{e`~^~e~btAly1 z+_m4qU--j!QMh}S5o--5tFn_-_O38%^VtJ}iK-F1#s!mQLvnBZW4LF|B>b)W0Zgk6 zl-Ax{Hqis_5u{RUIZ6l;UX|Bi;*8Pw&VU?j@0K=Li9iDzT$IZIl=S$sI0n&aQ$ ziz8c{NUi4Ns$C}UcL4Px{IbM`6PFdUID+flg_BdhBcMH~l3^z!%d`dE1Rtl5*0SWO z_$z%t$?IprsSw3u=? zU=cM474A0BlFBd9Dzv0>H{iv9wB&^274gRaX<6k1Kw46P2@eC79OEMae*jnj z2x~KOu9#g3I0^77z{!9=1*`+4rImWX>j9Sl-T>GRcq3pJ;Qs*fSRJfo#cu|@1(1Vn z8-8lAr7y=|&rrDYwJ%3xfo)_uhO5C=`Lgjh>)cvOxkZzb$)ZudA;A4Ws0SmMa%MWW zc)3%g;$@sWG-+S)@`cT7upSw=>D=O7Ba~zD+=1Um_|f$hZx6z}LdCdE=N2y~IOfvN zU`O1nC94LMj~z_Ky#qco7w~FIXMPl=?C89lLrd7H`sgceRUdZBzT#GtYPX0jB$l=X z_7%5kLpvq?Zgrw4Jrf5T6W<$TjO!X^9Ne4-8@sv6#xA;HSSDiOaAIC|@|z<#7fUV~ zZOy?J?2aZDWBp^vkSUnNwC{vHR!m7=U-vBDR^N&yUpy<8tQb}Jms$7cMz<#`M)wRE zkgUir+&F7{ZZ-bS*1mPmo>dLD=R<2h=o%Bn%5~FbY!gkYPG>&;n|0S#qh9w_3L1+xT6AU-}a9Uw|8k-(C3K zJ{%9_n%f%mxwO`{y}iVuaopY<^6)aim)Of7V0c}{$vG|oF90SVKb&e%pX3{sMX>e2 zn~r&+KHdlLOpUw)`hxGFzX1#Y{tmDT@b`en1KtbxEx?U{Er9m{wgPSfTn_jEUG zXM*z_m1`V@Ws(V89>G${n69D50az{_jwO=8_?Ua(cim*rE`Y)0!XXsGDIWwjzC6$r z!sI`c1iqGg>ypu&wzIlq0dLVoUqB?E>q{gb*_%k}!2flTd>v(=NIrny9S)JyXHvhC zNdE9ki6rxsE|O0|R49_q0@eXO5BN>M7XTLk?f~RF;7fpf|NJW;mtI~0WIMeIxCZbw zz$*d&4)|lh*8zVA_y*ukz_$P?k~iU}M3O!wk_vaT4pkz_yqb>TN+gw!B6+*uJd<*b zNf1e{*c}X!JP;x|GF>FC4M#ZzguSVX9$&WX2Zoc+1ZOSG4#_HgFmbKyaIG2=oK=~( zYCyPqrV+zVBaaA;LUQo!$xBv2rE=pEZ-onjv)-0X!;T?d%vWc}L9lmrlrCn*+Ts#N1U}hSvHFMY!`v( zqGacYK;iqdHs?m)N|ucd^hEoEk&5}P+-hK`nCV;h!C6N}lioBJ7LMrhgNnTNo8k}WakaQ_vfL&c{!UdW{R0waBpd4p4rGyy;jDYM2Q?Ox1XtWtNwZj{y%Mp%>;H z0X%>;fc*ja5;XvD6(Eer#uI>p0Qqv312`6O4F;S5I0CQ`a6dpCOEN|R9u0UPAdVv$ zFdZ3ZH^f=#__2WF0kKDF90tfGpKkziU$hW#Ga$C<}?v@+oYq!(dFZ(_Deqxutm@LevWe4@|1VTeOo!>3&Mi$RW&uspbQ6q=K1p8L1io$D^Aq0K|b>1ICHtJhr?9kR#Mmz$t)jfH){?v;!Uk*a3)x zvc_t_-vFKk_y<6kI+tDWI3RY=jWvLO1N<%^N2GHA-vm4t@LfQB(IW<%&ja+Jd`UoF z&T>9rK41^vQGgc!&H(&A;BkPL1C|2*0I(hKhk#hZGcE=^9qN@j`HdQ>7`N%%;{AtE_BB#jF)ANNDiyaq7mVL6ZbkV;M=BMQTRkxyrfWL4 zG*yk-Myg`$-tmB>aSy~h(f1zQJkB#lM; zE}wqQ4;C+-*tHK|Sa60ZxPIxxJ#+l#!v0^)t%k(UO|~(6rH>|lzMkpyMhb{`J( z{0*Cj$it`YT}P_ZjmgTqFg6;)$(iAv`5tT{{4tume;1gILzarPsN_9OxC}$ zpeC{G73?hV`vydV7lKJ$)79xJbKeMGLHuj+rQRg)P9c@aqa^$w;%`WF7-TGqN9uXp zA3nCx+xT&7<*2kbhJ`|bC4NBLcRPzZTGVI8vffn;Mt8>-1wVr9FADCTIoP%vcG%)# z`qZBX0LNJk-A|z>nCBY-Cj$NtU1fvw*g-Sq<;GpKc(O3Q{NdW+!Z=B$6$P{1Jf~F={M!0e)A$+&5B9o z=L3#4WYH)ebxp2N`{85UrgMvTkc#)LEaR+A1C0Loc!16?Pj$_p;-Z#Oz7g=L_(|mF zLp!(l6{W{N$nfL1$pM%NkHAT&!S#a-^MeF^1WNYW{`p&GS2owB19k86oc4A&IX63S zH>)ePiHntpEfuU5poCG0e!*)*jmD2z$r59UO8k$<-`pj#I>J(5(m!B3LAda`1!&uA z!-eUKknCCF_j{bWgLg666qHBh6`>Po}2|{87tu{6x_^-=4= zalVGGwgy;>`N)h+=|>Jw7VhBn}5I_8VzU}i7X$o^SId>{C+ff=W2$p;(@I392^ z-~_;#fD-|!I1UBm#!E3^E8uKEZbY8|SP6I{;9S7DfZqa~2iOXDG9bRa5&UY6KS$%) z*~h`JIy-$ivhAX9x9QLvgXypgraKOP)!CIV8v&%@NYYQO;{d}^gpQ$#Zb-_P2On48 zR4n8*om<@a#E)?g!vRBR`W$Hb{!<4DgP8{7Q=A+}ly4M#Dh-mFl=Qo$p(tfGxe&F# zta(C{LAwXI4@P(^js5m}Y1T=*N(*zUzjxLXN8VlEehA~l-2;7mrHv2d=dYeNb$$oz zUo>{M%wO45Jn6{x=7q-FyhgqK$kygVH!nB#>|xpL7ZkHHyeV7h%&&5Gd)TOD(C~U< zd%5s2r0oJCr~=UB<4JerPh`TQ{z!2Njo?^stVM;fUo^}VEX&{9$39T5Zq2aghkDTK z*@UN=pDcqoI-ddv$!AGzSMYL>@_O*KhzwU*r7QlL8S_A)*$NsnX3QsajO-_L160hm z%bX~4mfggEj*YLfxTxXigvMcqk20m~E3+1k8g*yT;+jJiIH7Ua{NrF~rS;DIc$vku zSa{g4K;uYjuyC=~nbt1`{;tU4`VKI3LgPq_J;+My{&!yb)Z)5Cc+~95nHI-EuP0xJ zXN^C7p~ZEb#tM!2f2}dlN$kyVTT>X`(`0W!YA~@gJIDg36~Wna{=UJvyt-G#sD@3pwz zRY=jotaGg6GppiQQhT|E0}G4PC_Zao`?ntgNH5pELep+5*YH%iIFiu~H`2=`EuJdZ ziM3}pSzKJ1p;J;}FBc~OmSlG4Ty~Yk#j%o3XdHFO$(|)G{@TAUwzz6Fm(VyQbARD7 zCG+~@mV9P$nI9tyjUz2;TPv-$9ryVxt}}F6LgPs50O2w<#5+IgcdW&Aq2>}AN9!CY zT>Nr^t#i^3@4hOtbq*4m#fZa{x&u?KbFGf~KqI|%C^=Rs)*V)LgvEug)5HmlqZFJ+ zS(fZ){ObL27S{usOK2RWI9Rx@$CD)IZCV4hMxVX!aE;IF;pggRDGpAR;u#(D!A5#1 z@`cOnJD0t&euKsJhUO9)M=8b%m)Upj88q<~i)#=o8ct{&r5Fb+bU2=jcyQ!TXdL?N zr5GdRA0dRJk|V7pgO8hNajno?LgPs5Xh&MtjXG_$#f3F)aYExri}M#tHclzs zf4IeUgXR(%M_N-HY1Kb-%XJpl1DZ={9BEB;r1ksvx7=%Sy`;H>#*tQ$aG5$GFFx`) zi|bR(B{ZPJN}Jg+&+I3t5%O}zIv+v2G>($a5H6q2&kMt&n=P&u%_TGry}>s$ujh5mb=T&*p-7Nj zhxVH#H1<-=OqJqv9rMhLQXC^(rVhVt(vzbsu5&e)&^StQtZq`8E~ zQ3}q8y&mq`Gw(ZJ7<+1FDR>?NdKEM}8mtsxz!G`(}&le$6E` zj#31KOKA_R2mSMk0T$N|%_TGr2`_b|mEV5W7K`gs%_TIBw916b)JTVfjXNx^19Sm} z#*tRgkydQ|En*xxQ^FcLgPpauUob{eD|8ULoKf5noDRL zX;lc9S%-HPuDsdeN@y;jaikS?r1jB0m1`}o>ok|pIMRv;S2mt>w>RJOXN&7z%_TGv z{*1;LkQV2xyAt7E5BKCe@SQhz=1G}ySS2)eIjl^{;mbPaO2q6OL88KC_NJE~ys60I z`cQKTjiX%E!e!PW<6h9a0W0 zu6s0>&^Xencceu*w78zuTteeW>jdGl%b~^fuI3UNhxR*BxE4a>Ab7?VV}FZ?DS!4E z>|CMg0$M8)6?__jF0kFD-GDtI?Uo~ z)?7m4NDBkJP759*-d22%#TCs%3HJrTxjG>(!s3Kv_DZrjenM=h?0G?&mw z_>MlywGiQ64_97?!*_E2n1?gV)g&}g(3s^~m@3yBI_8CjXjmxeJa5dg7S{o~+X;ta|w+jty6?+G@tkd&-=y2 z7FV_A5*kNZiydiEZ&+NXXfB~~q}3{1I@mb+?Dbg2(u0C=wnht$(Mc<@%&a)6RojZ| z5@5X^t!RvQw%z`y(kUdqLdQdze#R*&1oA&z(wJpx+J_oXC zabxQWUm8+m5SBSzDASON(m|)qZrX8Ts}QxRZ%%Azh|r*UDc0Nd^-JoCHJwAnsZoyD z6fPB;`co&QE^ta29CczvN-t5y{H=$fNICeFd7k#4tT zXlBb*P;nOTjkAwH z#W{U%oP7i;&S`t&>?2Td7VV9*k3hxgTD7T$%4`(r5w!J+i|TDg29%9Z+(X>ZxU#Wz znVhzFe9NXA(}~mRIFR^5$pkFSoA%nBIE%|7v>)cw-NO|%bK}x=Q5ui;Of4-6V>9w%?Qdbcug;jCcwAaR_X`qQ1Bc)2^^>bDZp)*&UjTc=4mdEZ^1s65b1p8KCK}-#Pdy;CHbX%=nG~O_8SS zE54UOR|1;x!{CA2TYOcZnWO3YijVpGHfRpxdkoy(;yWHRCuzFA;$!}>Z)#NRE7A2C z-(Uo{X&Oc8UVkHy(CMJNfbTYNedX^$gxv+2(0)QD6L2?sSX}Hq2{Z}ruEM3_6Zuy- zKKTN6J816FbbQqjJ5shSZPGDY&w}R7bUK&#hGK8_0PfGi^%Y+}!lr{}ZaSSyd@<0h zNvBK8ALZ&Nng(8RZuZVtf7gR<8dn_P_yW^c{Z)eI^aF%!ul08gXl~JTeU+E>_b_O7 zq|>>S_cPGsU=x$BulVv2RsfoCI-N^=i$K$nPUlj87ik)%OXpU9gMhyRbXRNIzWT>j z(A@-@PVR!krQ|P7zkCN_KLX7tzGuTxCAqan9uletP4gHbv*L3p@A;s)LeuqCe^ftr zX&M!yF0bunns}CPa|T_WKV45U-&@k?+{$qq=pF&xcewWs*H^tT-`8mxA;iNiz8iqQ z0d#fTr-w_$=VG^QwWd*&DDRiI+qN2U9Q&p0wl%KkZ2fA6+ulanFQVTbXejGx0c8cP zzC03zk*V3CKz#^T-K(%tdl-U(sgN>z$ed8fGUXPuhs>QFL3Cfl*i@Q*DK~3T|7Lq? zG*6a~N;0jc{Xeyh_FruX&8#WY*4dXdYW5|}mkmZ6wLu9{X#27rh9-Ouzbl}FsD{3_ z5hj;dp&q`djj%J%z3$!hlizF!&h|IYYaRLuE-i(Ab+ZwM@63VEv=P=Kcy}9N3F_*; z58-}oBdoP8zZhqa=WA0=^S`zc=5AE$|9>{ZWU&8_8VN&J3@0CY4M3(sIRZH;;;i9Z z{HCUTvB4JyI(Fh7{n7`oELT{o`g<|%1!8`$!FcT7M)8(hPBO>i=Vtln9pES7XFBrp z3k~MOr;!s3BTnx`K;jPtJRFddaP`FmeK}$|Md3E+P}umg)dKTjeYbKI{wmr_E&L{} z7Hq3QU%VRj)z#p|1i99uO+T@2`2N*b-Kg(=Kd*KQb?u-=q;_z!PiluN6{>dV%Q5c2 zQ{nE`K4-{x@V~hOUK~x)x^XTHyMCss;L#j40d&{H<{R%QEt1tKr`$ zBPF_a{JM4mx_0>Xs%nQmB_j$)8BsW1i<|V%3lwgYb7E8=f5fjit?O`whmK-&eOlLX zZclu10U4uv52M9LU#-{!IjyUuvtdO`OLI#zY*VX#q=WHIm?QXL1m}ZO1vf6Eso~Qa zWD~Ek3+&dNeD+x7*U5H`xr3{xOu?Qf_AM(Y(gFc)B>QCzFZhvw5X+{p|QESgID*D zLf~Qqss`mpU$8&9sI#TZ;MalesSrv5>^a9)Xe)c~AjFh z@F>7Vfaom-(u;QjwgR39xCD@6kPkoA^z`KzJ5#uSXkU&&KBi?lQmXImlrI~9e?xHU ztG)h0m?clO^sMNH0Hb_)@J+){#lrYar^3mre2kl7jj#5~vyF0m`nw-Y1mrXiF#5wp z03B)RxHPADMx}hL36%~!DN6bkC3%&P=_pG1a__sSX;{Gce&&K7Im}TYs0~cVJfshDXQH7Q{vAN(Z4DqB9)q23c=~eWlX-=^QisYQSD>#HI1``C zb7XsFCqi*YN^ck!u*YcSNqF)cW)}Ve?PB%bb%M z+f^&9M$<8`Y*4E9phjM37;!51ivY&~UJN(~@Djjp1AY&1G2o?us{t6wJz||m}klgJr%{5X}N;bumv?(RW zWjgk!-=$T2YAgAR&n8pXb+8>w$F$OW!cR~U4Br6AJY20SW*PjdV(3%Xawyzd{H<{J zDVgDP%B^U8jWwP9f&_DyTuujkg`(L7kZG}K{Q#-o=&sX6yIvOwqkt|FeX2+b$08|Q z7JUDWAK!Bi-|6hTQY^hX!ig#{4&U>aS2B<8vSeP*!+6q1=M|x&&%)%R2A9ig1Mzgk z*wdnrd|p}j#%>k{pg| zgKls}%tL|odZ6h<%12DT<+IF~_YoTV=U+opF>@548;Y2nAFSj8YkfM66E139%HQ{2IOhY4Ypv!I8pomOVZtRf0N;?GKRwps+Mv0F#*r2^qt}zq zCw})vM}A~+{SFv9p>d=|S+mN;1KJkXcHuD$p>d=oB}yHLzWCN9Keo8u(Ojz3klw~- zjZxBzH?$V&LgmusnWMMWf&*uCG-bBnNTIQ};C`tV97;ig+b^R9c^twjDO=Fu8mqa4 z#!*tv2_c7k;>Q-WxOi;|ozOUHmB$*awAg|c7cYaM6BL!jf{fw^V?Of;3G%N)^FPN(Tl(i;&USK;@;zN-2 z0mNfH<=@Y&u?a$R8=hv3`BF7jqf_^(JlkTPC|v9lbVrsJUXmH}p$PGMZot!w+4@*{ zzK)q6=%X!c=Q9d~s}4`6;|17h`w;S{Z9zU2tkzzwVB6o$MM#&0D}DBIDvxxhFKX%2 z$L?VwPrfO8;d2jDd~T`fQ=pD(=|xv-Yv}S z?N(aLZG!ox|-5JxXkZ%5LF_lWXOd3sHw&3kf}bI`gx~P zr%#?fNs;nY>QFhA`c0^J_C7kdQ>px5*5O=ErH;ZBsVa@m?{X@&3Ei-XQy-giI~`Sk zxHdywy}@Y!9DAjlN|ihM`F+)rzfK9^8>CAC>lvUS{b0TY_!J0sIXwJBNM*lW`tMU61 zr^{NKo4Pt$n!oz#viX>I?~emIykmQb7@||h@*8O1DD8X~|I9~zD{IT@L-m+%W)Hg< zY?YA)3K*~4yUis2K=%Ny!TqnMp#4;umu ztXelNYvHzn84(XE-Djq=T;)Wk!E;)iVpo>chRUV%J`zeYIyWr6d1A^uTgIIK(ac(N z!*YCZhn)vzaoI9tj=>LF!A)%~i|oPwTPM>-BAG5^J~Ag-JGY@4;?_`qQk^=tSID}V z6R56Jjlt@=h$v~G*|l?}NMpgg3TnTjp$pU0>|uABdDfN00SU$7Ilw!}eEbQ48l-{B zW(jXGshirCwRK39tytO80o980)!D=D0!Os0Arh2^ywOQ~YOHZZ7YrWKa8~xP>5ROg ztTtLZyJ1dUpe%%)YseR7e^LZycQg=TkclvKHm+=8tt**A`!GA_BeZKVvusI#Ze=oG zVrHOqMSHBv-W&%a^yg;O6vDO@kT!g|u&7PM%!{xF6({OxUr=*3ZwaDUzPxRP^bV%K z9tpIv0JcbrC##g{ z&HzuPL|z@L57!1IqNGW0CJudIP&9g(0y|%4Tdbq0rD6Fg9a68j&QZyGUH$BoWZTaI zQY=o0)YKn6O`3iM5|H3Xb)X_7nqWLAI%%)6OJZbGcQu}(TH8fhGCS+u>ikQbD`b!Q zu2~PUc4a7B3GNc+zM=Gl@`mc#U`QmB!y<||WwP4|SIXloRnL+7aA>y0manU&Sj4T< zOs=`1y{*$BP|Qs>qG(TvqsY>G;J*Sx3;ut7su5#0Ompt#RO1JCH0S>Lnal6H`;x(< zKD%n(OkA5R^qUuS47stbA?te+bGzP7Ou1I9`naBIJPz{(w^NM^1@C^U5q1;4KGm3C zu)28KVe^-_Hg&Xhwk_()U)kCjYh0G!*%fR4`cz|c%lyu+=4Gu5k6gT$^RNGxPBmh{ z*lStL8RmcZNMkhlTzJht?nZ}1WHb@J_dvdPf1dO;-dt=-|CuB?;=@9s~ta@W$BN-+0V6}K%4t?P{)wYabw)+SX zEp{aS-gX>bxPpa`!4i3E??1;PiPm24Y@oc41-%;s$&IbO_hGybwLVyf5h+-BA812` z8_Rmudij-OsBrtn-9rLv?&lvUUTM!-Of*oG!e;^-KOTZG6$F1Uak3w!KRLhqbq_4# z^^0_G$_jUH&RX|+?uA!>wr5ZBW+_RyXS8q12ef_>Og3djlE-`yTK96SIyj>#J63_` zkXQiE5wTf#j*1oGIXZS!(%ape7v8wL|AakIz~S!u^GkE@T3ZlDxz}eMwLW;12fu#! zd0+b&I9eKVH6xT2@fjV8bD>DhRS<}91tvgI$1SDRg$hT)QHrf zs!yr8O`+D8S!b#OgWeZ|g)gE0P^G9$R$HiWhpI-9qvlY{S-?Gv4DTx$wr4ibvxdPg zVaPq0(OhJH#+ASm=;?NFJF5b9fEq{bf0mVd{#B^+Xz~spD=CV~UoTKuhNPMEEAV$1 z;Tr_r?7KnWmA=~u*KA_HN^Qr!j6c%1W4YSEeV_4w=VG#>oy;hy5gMkho{DMt@I1!k z?zsEiiy*#J)q0v_7DQ7bTY(EH9H!fx`0^yzW59B53QE2(EyR?2sRV3C0N-bDk~Y@G z$vX~+Nx%*S#PCZ6;7tTmUwNZ5wqcqFn}ls0OFP>en=GS*+)pqa%UF!R#{=Qhc&y&W zx%!U!j86l^X&5nodOqMu`1>Nja{w;^#839oF9XC+ETLoRRZKoz4tN#tKLET25Hpqd z?*VTDydUruKrhn#B_Q{|P>u2VfY`%{Hv`@S*aZll_?dwB0^SPv03cUT{s6cO5T`T6 zw9}J-`(cXoXTSpiUjQ5f_&2~~0N((N0KN zocuMFf8e)_w7REmQl#+dK=;Q3a@V4U4EUh!f2(}`a@XEYU+%9ecPv`>V61RaU`9@C z0-lxmv4aWxvHhW|OR1GTQ1qpVtih#;;NbjSX97JtpJD!xCRnpW;=1+X4S>+#p1{T( zxvjm!v0~J^ZTdlw)yH!0h3bvuV<-S;zt#so=|nv|4%7mmS|9vP0f-)luI2mFEr&r)65WIC^;{y zCOP7dAdMA=X3QHBn~dj(*x`7Nj!g_C4ZD_&bob^%$rdxR()C&UmaY%(>)F*FNcv&s zH9R7a%nP+X%Z#`7GQX`4O3}6=eDubbba|m{y?^Lg3+<4N0zsvX5PfKmw&%MHOa(bp zMT#gJe*f&3d;YN~9M1ruWzpO`=tJ|~^Y*Hwxa3IjqKz|GB{g~VWKmM{K;-VIq!u73 zT}dqlE>lUh1M8}!RwKYwNyQP+r;<9M4<)q~Or~QQsiZ~%0p%cWI65VDaz5aGfa3rs z144<3vN{xS1^zw^@N~dJz_S1k2kZufWrz4WKum|?P!vWPAQXiW1mqp+uxugrkZ@ah zoHv%w20R%MmM-F*fb#%jfGvQuBd`?k7QhvNPXM+9_Cvlq0I58fN2NUIQ_4f(s5}%7 z9$7*rq#KQ&QXa~ejla>mfb$#-o6cR?#y-t7ZIlo`w9Zx_hm&ke&h|Td5IH@00gvO98s;$%1MdW!}vRW44eTRT`_*H;&t@uqeZ-g z%Jo6gVW3;~KeAsj(jt;$DoX|M-m@)4`T0R~A!1JekVsRa+u|mV0 zU@Xij$5J?Vf(HWQ^-yKd?fd5UIx@>earAmPhhPcmtaC!gDuj7X$hKp|vEDlCFlp2` zud=wRG?&mg%B4;YVYNqGPEB=^DdQILpPx^m@$x_|$dJ)nt}S>fAHR zRxax-(MlcjU?Y7WTAd}T)8Q6a3$JssYu}+v&47LOeaRHoV&njn!6?WKMq({Ss+OaQ zCe6^BlLE{g$|+OqSnJ-LqT(5vo;#ESjTr9D>40|KR~O4|hY~}A)Ag}KX`W{>iTy4+ zl&3sqo&4(^yRUcbzTUC>ddIGDc{_K`xq0~Yj-BU~k`Mbg;R`zq z&3T?{XDxf6`kK!^*!sPrk1juB{ybR!7W{knobY7Ls25^)&cFHKr;n_~3dc2qzkJV( z^%wkX@o($8$CkWXHuh4(cvbMb2gIH_aDCfzN1QWk&#dV;or4z&48wVzou@a=?KyGe z3wP`s{Q8lx72n5dir`=P)49p}I(|6z%>|D>*--g1hSx8*W4GX<9ijcc@%m4%-yMC; z_~tvyzuvK%IlsN5?Uatj<@sX5@QduXbv7g`)#2S*ZWvy=k z0N+@{i7X#?`a-$Cnwy8+yKS-6i$XKz=EqJYm=s$=;Ey#C)Wzl#EQp;z&>pM7GVDOE zqDHWBWu}3(-oPhV?8TReS&6_WiNNSY;Fv^Uej;#YV$GFEF|p=%@_bHGR~dTk7syU1 zc~U-BgDbc$T(JQ0tmy>_mVyIZBt8niQ`!-<0&WvPK7chIlG^ zMvM+@d}U~B?*qqinf6S)e_`cz@FXPJvur;sFaJHT@ztSaJ;w|P6}}bh$vPODfmcr; z(Y7gn-LnUqUl-uL9k&q#3m*()E0gu!`fU9|N&nNI@7dG(!7l?CEFKGapALB64tbvm zc;E6qgXQZ(xPTDwZVwcGym9y7koToETZl<`de)Air*Ie0L7*QHbRa*_v$lxdVBs4G z2`K!=J%bYg|He-T2k^rV*+e1!^$t`(;>KP)8A;;C4e&*gJ&H%D@V!J}L14{hlA7%r z*!bCCwx!v=!NjR&nsSs>a@4)kv#vLx{J9tY;!~`qU+Rk^!e}zfHwE9Uu9fJcJzc&$ zSx~RZVvVe3lItFfCXd+|gkVx4V~ayGYO-Ss@f;GHk7r)&L_9~t>hK&DtHg73EEq@* za4xxT=Emj_thW!DS-L(t)5AwUKD>Nn@zI};0elR6?Jg#qEYA)k%SQ#0D@F&BE3q(t z@{mw+A|mt|pa`J% zErLyd-zY)CXOk_`k!T|_MFnu>2fYb{l4p|w@}X^Ym{ zfGGH=qQ#2UR%*4yYFkun@zKx!?>95|wb{h2+Q;|(8OS|n=bkfXvqt9ZV9 zW!=9CI1X?lAYYGs7jPcn_W&b+n*eVCd?Q%;9mim_kO^i0rK7I7C^pB-4BTOyfJ>tlkZfWfWrYN0P@}HNq{2(y?|MO z^?+jlF9XCWx7dFJ9tOArZ~|Zsj9`4t;{rSlFbs%36I%c{18^ZAmi-34=iSd(gs{mWjZjfEdcgr6`=Cmb4M?iYS zvB*(44R6DE-0g=xg9A4lFpRIbd zuz&Eh5RWw&Ct*rF^Q#Y>gn^8VqX+6N)Pa*Q2TsD^$4C&n9Dxy* zpLp}$P<+v@P`nw(Ue2!x#XGl$;=TPLxeGcFuh}1ncf!SN?{0XS4fW;bdLE(G99B&E zABSH2G@JML^x$NR-__GjP|&l4z}>TmAl$Q%U{TLJg3g}u?4S9u3;Qu_Kz=L}Mrr@Y zJoMp-`*J_#0voN)ODZw3`#sa!yFw`J2b$AwK(OJ^1sxvwyb0g{0QRNRWNc z0vfw{r(%&OajpxeW-7vca|?5OOUK#SzyH+KMD5p%+a2{F-~l~hB3SW z7P*#}VPnDW>kqOve}rQtFX6}L{aLW8GNVbmm;!$LGPZ*?$2aLY58g(Ib2OPpu^1-?mp zy?vPnqfJJ`(n=4IL~W#@Vl({Tv$C%`NSy9@I2RT{VI_77c(<||-zludv=Zl0Hn1YY z0tk4wvKrqit;VaiQgsYzC8ni8oX7x7Z6$8P`Ey|LDVz_oydfPH{-0J$Xt{>ftN0o{PN z0|o&f0W1UD3`pzmGk~=IJ_mRv;7fpK0Xkp`;--F{_@VXpG(cK^%K_0)u_i!Te^&!G z0^SDL1o#jj+AH<~AjW6x9YDx6=7pSj2p}Kzl@{Crg^l7#qm))%wv8U}=sK8HclIIL z?C3;odgBS&lxca|iTfsK$G?7@cGS+}wZpgOYKK;z2&?W%8WT&kADuSIf2UQKwm*9q zxF21Y#DtZn{ADn!E^U6gz)VZ488ft1cf*I9VkQ?%nj%m(Ls@mhAFaFAA(@jv&(@Nm(i4cT)&LddVb2dR|PZ+zPvFW!TR_QJ9K(smYz3h|w-}7WI zEdKbt>>Q7{98GL4FSWd^#6@iBCWN_1BYXw$O`Lp(8QM$_r9GLOu-(TX)m`uTvlq_$ zm_N_ZGx^F~{yYyqw~IXKAY`*IJ8wHV`@vB2B(T~Yym=+FBKfJ=dCxJeVw9`q7w=`) zzC?cBsU+RY*?I30mZ7ke!qb@DE9w3G6dTSX;K?$6Fs$<;i^ z_{&(S?7Tf>+e5Z~Pj()N-eB&JBlAb`_Zo8fBdLGQ%T`|Ak`<`!$E~Nb^R|Kt)U{9J zZy#jk0DKehzTG1E&A7b{sn~ zT8b+txCj)hVz|dVGKn&-2xeiPPsA9m07qh;XWB+yr#n`OMkcrV*o=EUWYvc#CD zkc1O$j%(R|#C>HE6lC`vZTV9Y7)44K095B+2qaCT7a=qk*!doG8n;-^G=VejR$=@mcD*or6T3=mlO`rN`!{8GJS<+R0J%RmhBUB+no94S zM~{QJX$8&{pGCxR3t(#g_qMU$k}+ z;Fkcu2gt8{+zm*p_xAy>0%W>30p1UIFCfy0{S@%$fMa0-dj^mnI^O{}8Soc?g@8K& zO8{R0#b`8Chjqkw4V*aWoa9>5a-{|Gn}@NK};0b${feF(T0 zFdy|u*V;`P>Va~SdzdB0DO9|T(Hxf?rd3|JB;5I0>NA@G3|e?7p^evF%N+n_no$RIYQ0isL?M>|E@1 zCf5z2F;|&f4YErqy9l+S85C=BgmRL^64r`o;FL z@8V|jrrO258u8{XZmA9j*!xxV0DHfTud9P|?^gHJrkV9K7dKAR)bD8pQ)WzUoKdL% zp4t>?m^rmDV*XxSSTL<=s)qLkvkJ^T;P9FGN^xh14}Uyy|%aw7zP+Zaj6o;TS0g2zGgyrN_4 z2|K&xOIA$5g}=R^apGMCgF$EU2E=$Kb1G%>w`E-$NhcyyBXaY|M9x~qh}&VJ=i>Q*4UH3@td9Z zG&Ez4B;pr-)HlE4`D4aqZmFqUzWOh}#EC=^|9Z={-~L|zB_}=m)t|Xu$R3S%@AruK zGd5k(aQN1nURn6;!@=)PEjvYicf;xE-}mm$4qtG2+d==gJTELbeAE@|OO`z8>w5b4 z-)NZwb#fHOveR+&#K$rZD%t(rk}I0Lw`|{c2DT80_;GbN4)0%I_NQlVYrEl`N8Vn6 zSN|gZfUk5q{XXD%;WIg``2WjSx~}d2#dbWn${o+Iujhs0jk(Scu&hvg8XV=;Vr$}0 zx!9x+-GV^k%}`%`mOt@6UFgn~&SSYj)C0%lI9VRe-S2@1){i|2_$G$~R&1plJ7Usa z-gRP^q6;U+M@|BXFZXS^k&@^hZ1~IYaZ}}3?u_*IjmZ)lHT{#e!@B~0=74q%&ZG+u z=+ap?_et*B{2E;2%Jb^|^fTb;yIi=F^h|of-#2C|j{UFN%tgK@UY)xKdj{#PfQ-Ab z!*0&z4@P5aAdj)Pd_rFZ9{8Tv3oew{(emVF?D1k=6 z23EIWw@R#8k2Xm3^d~Ofoj4c1%CXf|h&Hh%h8v)Ts43fozg9{%;h&pAuD+aMlb)ks z_YWf2xc^}|3?3*}H>$0RH5+2Z@68`#bEOb!-2br@X|_$I@rsoYXnet3t2~8#ZLTJU zlqvJspB-OwD{3i(sv`WgLZteyqlG}_FAp5d$NdoJHX%-QWqJjkNw2`@!06+24eWwz z;PJ-J##W@BeEyxQXRd^~)9nSWIb;wIAsnT3=J|ITeNqR0SlxwNQ7qZ39F6tSdOS(V z538@Wa4;|0MeuN-tyJ-Snie}6IL?>H+<;#PECc)oAZ#V#Y&xIozJ=cnfX@S7hcvjW za6RBFfExj6r??w%H{d;huL1Im`QZ-iE=0aZ0Oo_APkC1V+%Y5Wa)pi3m@dnz2bNFT zA0)-g2b55Vff3? zCY&-xI|X?hgFFsJ9tXdUCr{)%oQIbYSStqdNnV$MeKvy&O)qE*213`Ppm!|Ux!f-jp~ zpJpR*kr#jM`7duWxv;_(ffa&f#gZ4NBr~s#zr5}mldD8B!3VA2vON8<-^jD(%quqY z&9_XhI>jYuYW4 zpRTMda+f8oCZ&gdeyhp#=tSvQO^!sjxtg885>i=BxWjrQl-*`*WMSaA7|d$&CTQMQ zbZp_ltR{zIo|&rV8iUT#>zNOG)R~|;H<`}T&q1WC^frU$=gD+Q=`r88 z6b;j77|d$&w`971i`C={Iotmts`n$u#k8XPtkI)-!o}Dh-c6*9!wpe9(#m85z5VNd4ey_aV8Z9A<5{8 zXXYlh_+iv>wmhG}EzhKW9J$0P)k-Y&c|i4o{>8ZR+i(4_kGv_yQ}WzrBdo(7e%X3YxBn&q1{%Nx38NQ7TsQPoq` z@}ZssYv#*!$*L8kS+&|+H|sZdkgDZdssCwbuvxW`S+&3rRg)5% z$=U^kH$${58ZcF@+_F~Tv}$Fo3oBR4##_X`&^T#taP`|Uqvf8qRPSL{Zy&3-lg+o4 z)!T*YDa##ve)60&iDiCaPo}EgZdtv(|8Vsz zy%5$l(F=pZk`~QI?~>>F0p1k27$$@RspLThoZEq$!1OX z7s*CV_}zmyY24qhchig~<2aShp_-@|Fa+a%EwRNH|3(ZMr&Z^~#jhvM&9pYGs(IYM zNYy*;-lL|N;8ZFJf1_Rz-%u6V8eibk>mqBBmtw@l{h6X7 zOh3JfoST)ncu&fTG#V9oJ+Wp35{&oB>f|PRpxI=LthH36S+B^@gDmdf9$zrj0E_#x zL?xJZT9vRCKXLKfiF0v;y&_+D8-PlNR*d^=jLPgv2(x9p?`Br1XMCdPVL7T2{*`h} zNoy_7#QWzCKAvEcMSH-GI>cCl36?cEcjZ4^4Wm23qN;`w?590P!-N{|yA>tRUb9n- zq0eea#5ThUa1Y=P!21AS z0{m}4>^{;kBgb9^{4wBg2zV1<7U08xV*q~&m<{*{;Guw<0mlJu0UQsw6>tLJ(|{#_ z&jMBf?f^Uo@HxPxfX@T22HXjF1>g&SYXMQWSORbt;5xvU0Ivt60s1hs0}aplsCPPs zW!8^vr-xJq*lgT{!S{0;mYJ6xQsr})%;$h%SvuF`(14+rCQzEt>|vl`S#QPTANV9N zm|>ZwGjtRYOrxk7Gqhnj=DzGtCf7gLuJ1S&VVyiFkDT{~*J1 zp(-;w{bw>PTaVV;?8ov(3d6FM!)8CWa-_I1z_2Xo2O5?|{AtstP5Vde$}^`;nV!5G z@5Ey?&7}nNS$E@IjzN)*U3tWzn0nAp*6>9V0=s)EyE5Nn>m`vT*9`Qa8^xIz5@h1Dl9{DLd~Oocvqr#9_KO zv-4gB*v-4)4LAW9bn={C5T`?HSB%98M&78onb$>YdCkuSQT=#aT8<{Ahv>qwOjm5N zATklf5r=Zc9LpF!2x%b1IZU43toa+y3GUC%dkS#j-x0whiNC{9M4(%M;)G<)8`*i! z^7b1znaT5hHBSIJ(}^RYC@>F8Iz23lIOGZX9FI6>`7A4*m!0=GS>HqLkQ!5bo3&)z z^Stm>Y5h#3QR|rrbT9sJt}>@(Jg7D^8Uo_6(;N?LmJ=Mq?1C=b1i_mm2+jpX3olIl zNs?ybA_X^%?U0Xq3#SQL*8~edw6uUHLM=jI{Z-XjKgfee8ihPk2?0l2btxbvQwlyL zVoD*8m1PN^)rBBxj{4S6Gy&f7)Cj@UEUX6c3SPD_V?#8CJZ1`cP!v)o&ZQyNbQ*r< z1oLrq2Hm<)AdXs+1$lHB0-<1Xf^(Gs!iZdoOO7YkA_a>CSb4!yg9b+jKzZ2mIJJvb z56gqVk1-+uGTDDX$7bE3D*AWwpvj+Qxjc;&7L%!g$4xXn1klUkd3wQSukH@q+{=4B zUW!sUS2QC=)>#P3xwI8bE24;9h)a&A8q_(#5HkucGDSEgE*C@C`5={zYICJLAhG*k(&7L&216qv^>gmQm8>~RwH*|D zc!Oq4;5?DfgWk?n*NceS{fOMf-?WAS2Se@N&nKx>F(#!3&NWO|mltZc>Q0%DF??3B zb}SY3$b%aM^#D~OBq%x+M7b5k+>1YSqMVJaSF$u^-Oyj+LPnJ7dXcWwC8o@D3F~eF z;Rw6vMM!WxlhP%~bgdHHD)TWVNTC@L z+%Bm90SU5-NfLD4_q50(XO*ZfB`NAlN%o8M2S`#jt5Y~uK)b|Y$V8#3)JwspiP%1aysL$XV4d8UKdt-k{v}qe8+91Ai_2JEW(S)T-Ad zr71khONrVXx}vL5Y3coPkEBw=Sn6`A#Lx#>uK^N#TV#~8O4N}O6e6VrcjJy4&M2=w zepkt6b*}nYGR9vKWOfPe7xyd@+$SRp3GS7@lO>3JQtCUIy_owcD60QeyG0T?*Dxu) z+Zl?EGaYDzI8bwz$ENNEXgVc-t}C#dpg5Bxm9t9JffAy~%m(HRubL|-E`$Q%eF@xH z&Nx*mWp~8y6)x$o!O7Xnxpa{jz@UX-r2bovw1NMYH~N84V(`R(6^Bx|+3-z~T?@Al zaDl;=<-%zX;L~P_#M}nWLzfsi*Th7MTtmIc%1I&8WrLI?{6st^#fQd_tA!_|^9#%q zD5TlhfOF#B*v|w92ylS7){_k4f&&c*Bna0P$%E13qJ(5m&k@}XB|u%AD{{%gxzQPC zccXwPH%P3JfC?AvZVvz$ZDi~RIQ*xs0Qh2P+rwY%xv>9p0DToqerJcd7 z6cWs(Bvdbtzbd2K(%{FQ^B@#$* zz*?Nrkv$2u&Z2y{8o!2F2z4gpmM^3vd!JaRVR+KPiasXwK@ma*qK}Cx7=26%l@n>r zUf>u2#*#!Vz;afJ8d6lvLR9p!0zy7e=z7bOM^Pzl7vG~qC6t|2RCgzd>Z(CSrN&>1 zUiCZFLJl*CWDKRjROI-B?xJM%jwAKdMp=v;Plz{#Z?oATaI{wxN zq^(z_p{hJi%1I<4`q)3Nt59`w#OeJ=6x!%V>^~GxQXk5ZOCrjoQ*@uP6h0qioSteW z9?DXwATIWeUR6L*$=NL@zE?=Z8CP?uxvITCNmSQ=ny6CrD)cC5DD)_lPOcvI%5f)@ z7KFz{%^^1vRBH9W(JOiln5*RowGKW}&l)K)O7IU%R`xE{gM`qK^+r}~fbc}+C_FwK zID_L;bf{^Rl3Wzz#PpvEXGB{R+iJMhPxQ!cia@{v!j)hRDNbvlDb zr;ryK&s<>b7h-XWg_ccTT)QGdmzVxjkV35wuB-H3b>yI}BW=uZFTx!W ztVUuAKxN;6t*0YDm;FgsVnSyLJp_T(N`XN%By<}pp1*2tmc1-zBNvTAbc}|12?=i{ zx@fJGU(y&w5op3ve$gnqm81@Ag6zOxj7GGbT!X=L5@(=C`*7jAuuSbnT*nIxdnJ_P zB+eQ`mX`rz`2Q;46@c#m z#sT*Oa!fu3M5k;wxf%7`ShOlF0|pOH8a+L?)9to;x?()(j&Tt)Ln=Bd<)F)? zA(o1c6VWOcE|!pr?o`~r)ny?9nu;zL@lU2fHyLz)PJ<2;jdtt=Tr43~zQwqI&H%db z0QsE&x^E1i8z^Ts?W1YXQJwrM4Z3Nd`*Rv}(?NIKakyAQs`}2x{hBoBD3@yo&<&K! z5un>SfNr2%NcX2S=s3xZI35>ENL3GPMAD8=gO2HW(xA%*-Fa!yaj3PWK}R`Xl?EM^ z@WAFL5EpW zdom3=4xx9_prgJzghI50RPv*Kai>AY?Sw1Sprc&wOM~tp(7luf9re)f)1ads`gpThgFA8FY`QK}Y?!cL3c${dWfFrm&Ef zkV-C2-0w_-j^ikn1|8e&jx^}FC*j9w(2?ZnH0W5q_tK!Fo*c(cZ3(I5!uBXkgO2lC zT^e+p7j8(C?!VKZV||}XgO2@gUmA3$fX;OiE|xHuTq@F_D?mES)1YI%-${dxO}jG< zI#%_gH0Y>Lk7pxWLaO?*-Ofydj{2n|4LXwCk_H`@BwN##JxQbQPex zdH~(PbqQ6~D+A~TK9{*bH-eqo5>nNd>&X++pql}@)6=Ajra{N~_j_s3u|1wigO2m% zAJd>a9dt*M*b-97h2!$ra{MgoS6pQk)Z2LgO20($~5R)pt~mxIzFF2n+6@*H){$mmXJy= z`!isN1Kl_-Xb~>KpIbwFL?gXX5hE{LmkgT&$IJL*7>2)8r=RXe{7lfit>`lGd$7|_ zW9K3b{4t;yDNjFTA^r?SLpla=N-C**XCb}>bhj$n;rN}Ze6Jw>8PI%}0}5fN@;wil z-zd7l%I8EHAA@EL7bpl0{E6}<*+rSpI7LG`hE(;So#x0Sx>WVp54vj5g^HNc(DjId zCZ^~Hs|V$Lo1zg3;*zR-uOj{~(5-Pxs=@jJU$p%fXrA*(x}oI!0ceI7OS+-Tcf6vJ zl&Q;ycUsz{B)U}cdl+=5gYE-GYm_gkU-8Al1TS8+;g4Yi{!*p41MxdRv))H4OM9d^ z1-D(%NJ`Y>v!8-nhBW4Ac$J2Lk6V|tv_`sXJG-aU^0mb&(-)u8-PIuQ+TQ8YYUf2- zBlX>p+Vdk_T^(Jgb}T+0-@F-@qb=g0@q>}XiI2-`MN30hM|Ve4)Ri~yBv(~uw56@( zLVV)P^tt?;ZSIIt&g-wUIgB!#KD^E324aS{L%nuLks1`TW}P+Ce$5ut`J^ zuTr|Bjdg92?(X^}k-BL8;?{`9&#Lx-!19U6bU%xG2w1N{)@8+^DsQ=G-aOC3Ar9ry z`8*|6=B@IVpuSl-F8o^D(E+KncLT+_! zOS(iZTlMJ9u8t*LsFS$!nZ6Qhcf+5}qM@gW56#Z2I$QgP{qi4*6u!*j)irdqwRN=D zbw;~1I_K{|WL-$>Z^y6RU5K3!6xI3d4C z=XgkNFem?%Bs)Y|U4?)Cd{3#rPIQJN5WSJ<^V_MaSn5Nv{Cenj^jmF_wvMh9LYAXd ziA#dWcBs>fF{m5-{}23DK+{q6KfAN!#Ln&s@Bgak8|ROKnG6MWI`&-HaJKz4B45!t z9XEY4Ywg$WYW_)h^@O7Lyc4d+yLpT;r(^$!o)?c?+wsaNSLA#$XU6xgfEirGzxs>h zZ+>1U;`cps{-c-N`uG*MyQ>b$y#LO<@be(z!?*k2yJPWdAOGOU$9}fFCcaqHJ{0i- zzX|Z=4CXuVn*bgWpZc2s5!|C9YD%q$8ampWTGWRU#i03&9_1S&P4a7tpE;3+t|$`e z{+y}&@A@XdvPf5VOGo>V->H-{Lo?g(Gs_k#zNO>yO4jn(fX`fzR!m#b&)vqK{&7z! zw12V7fALL|RnQru=}|@_HcIn!cDA-O)JM_Gu4q?%dv_Dc7HM=vJ33r#_3bNM-3|5a ztu5`5ZY|iptiH9S(KWwnzN@potG+D~MgMR$b#%G9BTIWC?a`L{R##crU#fXKy1IHg zqvD5)PS9tAtf##ZNp@Wj>2ekHPAr(x>uPE5j$-C?bu_u=&99!=sD-;CZS~Qfu81oF zVnj1F7j=Vnc70bn78J8xJ?$5?cPwvrm6ZfbTwRf6E$pJM_MW!INO)r7sYtmoRRIn!uba7x z|M{-^?(Uv8F60(^7kj%jA#~I@g1VsavN>nF=9Lz^qRnW6_WG7qS4$h#YWc3#Nc)m# zGjkt=tFyi}5{*Va11G!1DJ(Jr)*xWm@ahYqWEvXWYG&N#oyOy^!Mp2%gd{=X%Wl3{Xphn}d+}ixMj*e(E z+pN7K>gw+4M8%^J!SWWgMmu_86y2h}tI^e6--f{tx-O3YZcUCsPt@LZ^D)R8IxrQi zKqZBqU>`GXlmJ50iX@u%bF$>P6COUQNuc5ynuS_S9wVM`xWE`xYW793gigzMHFDHNS0Do21j3QMQOId3T4L}& z%@1vgUMV}Cp(6Y#RD?aw7ioeram|aM&!A%m+oAC>32;oSTdI-e1X9h%Gl~%!F47%Cmoe&O)sX?p+6qcDX!JjvP$hN3iu=@O(= zLpDmON+EP3&Dkzf>iMpw*7_ygq6pJ^709>fTvW|l-@_p>+hy(fF7cS!?W)Htz#Su-)gbgt;)sCMOfPjWFT-&Nh*(N^E> zDm~Q|LT}d2hM<_L(C@Z%DJ;O!s$#7(zEdB z)`J!m4{s=Gd$g;g70>G~K5|DIT|J$Uy{SXgNV4?*Ay*Jhk>!>Jgeqr@nNx4xajMD}Z zU3m={1IYO#trF#`HcrMo0<{BOKAqzatsbu5D#Zu_h>@YT(+SZ zBY0Y5m#)V`6GU=hqUm~Q$YhG^8!n*OyQ35qGcX1L`W#lfSjl0~p;K|S%0hJD(SdRG zQ6T}0Oc$(R5m8HH(Bb}yNYrRSxr(#tjy5b!UGTBijwJ$D5g0#REm%q$vxivoAum^b zYpa+<^tKZ>xUzLM_Q-bbX^pmEw7c*uVFT9OE$y8cg<{d|Z|lT-V~MD! z?`>)8X)}c(Wr_g{l_HjeP%&5(ceeCKTDv(7i_WWyT$E1c3=Pz^!e|R|L(G!$F4r5_ zC%qgCSGnkbiZYffY>i}zR`o>nQoEK59Vwo%T!Sc;pixJxZlFB{vF2-OY(FuI6+PD! zF0*T6NiNiwseL(34$!`qNGUkc7sYDWmFKGr*}Kt6T5-n`JT&;utcHXeBV2#zQGtO` z9+7>wm+Z1ywfnli*Q=(ZUc|12`z}` zG*sU}MJb1}@uaErvI`1PETCq)^z^vcy`WnzvPAdGcQqhs6hO8ld!!b`!$LAPAfF0Vvx@}f48+M^#Y%lMAX--cX_n!J^h)P&=?qRCsFYJR!WJ zsPhIERF=CS+vRM6d>8aN=g+2=UddKAyh zuuzFdIm}w^xMQrn(LEqARW9|?#ppAz865}*Byd0i{~t==5*Uje;$YrI0>i5}tyf?? zU(q8l7qBjYaW77XzzTr13XJEnS_I|>)+De1um*vJfh`hP4X|?swg}i)1lA1fY=LzG z<1tx>)(h-RfyIFFb0!XLEwFNdtpgSi*v-KF0$UHPSYR7~6$$KKU~>hw3D_)w^#hwO zuksOUx!1x7Z`WQIJ8Z` zUJ_V8uwM#nJFs5}YzHvP(4p-D_H%*l2KJ=D_5j-^u)V;x3T!{H%>vW#y73W#WdZw% zz?{I?Vh)Y2#UBuu3)l|@mIv$}ffWF|TVOMRZ4{Ur*j)k(0J}qAVPNY8Rs-xC0$T*^ z7J)SbyGdZ3!0?6@`St?4Mqn{uUlZ6`Um`Y1-1)Vo4|GhJ6~XXfGrW&USN#^+YhW>VB9Kop1`tz zog*+Ouo{7l2ev?9E@1NnmItg#U;NT+AEo7Rv@iOU4cd ztOO*@6`+@2046p{^h6mKQ+FvJDRqJ1!u#?Nzr?Z-#}990XpRvm*OXxefmLs3AtI0% zPM*Njt%3OExqFF1tbNtFu1~__g;Ya*_=Z!UFR&=k$K94vz=6b7l6dOVf(XtdnA)Q( z$$B7}qBnd~V1i?UwUrK4pMu_n{Y+I3xyskrbO`U_&)Rw{Pjc%upp{rgjO8)@X z2&N>p0$YvZphmb8{ab|ytXsA=aOrmjz*M7S9OO>fM)6nWXzN~5*BV(CX;q@9y%((9WxEAc|LlAClOl@+&5?Y$|J$R?s93)-*yEWwg)qw2qeZn z396ohRSN!iAU}|BX8&kZAhG50C!*Pb)%}jx2NR>^S7u%QM9({(ggf9*1PX$QC-Et` z0Dk%a@qsnB8*nDzT)+arnSgnK)BFi{K5*9_WQ-5kZ>@PWHnY3uN5R$o`ACHkZ}QG& z{Bbdnsl9AqdM8?inB<}SD&lzmm-u_!>_m764>OUi8`Xd!bznDIgj>nOw;6HV@s?`% zuE#w+ung=()cn`0$lK5vSgvmZvYFQd9t`*$Kz61LfF}cP1Y{@r9$*FF-GB=L?*-(v z{X@W3z)gS`0zL@125=kTV}RQMp9Fje@L52}FGg7~p6T9)a>-6eOm;#U$4)5YfQSVh zAp>J&CzMzg;(jdR9GMO+^LC-jr#>HF7sCyx^>{e%QN4}Y5LK8o&<{Zz1Lb2;x3EM+ zqIGgAh!5Q&PSql(q1CD!;IQb}ut;5A zm=~L4B%n{l@6ogv(Z2vv_r4EU28idBSS{dwz!t!d09nS50ohDjkdAC7VxvSNGVXG9 zca)Y1tV}!Xu-E1+e5-iUsEX?@*?H=w>ds>+%fa^=Vwb7d^xUO3JuhpRS%5FlFV^01 z^Oe@AEsZBW-ll!>35SN&D+-DMH#4WrDSC#Tiz7Y5k*n?}ZvU{+`57p$-IfM{7XN;C})4{R{G&Q)Bbv2*dsEyF=A z%22fTc@#$#OoPWO5lCa_qV!Cz-+nUg0h8kN$6y z>ovti8ao%Im*Kzw7GciyzkI>u8byVHKpH#Ok%%!{`D;_}2Bj|f8pTB#I~Vm#hGQ14 z40+ej-C=Uws<=pF=Q|AUqQ%7w*Xw%~+SAi-5Y3y8-UWS9RW%%fgpRF~yS``;*>|8FyWH^q;mEq=+7hg8H zZdY6`+_7^_K#b|yE%NrCmYQ7eC@#|2xsDTD`bepG@|l??R|(ZQ0%`1AEL(=-MBYUB z*@;mL*Gk1j8ar1mVlo^o14H-lAKqZ*wMlW2#?Hl-GUt@cb<58(xjt50q_K0IAh>ir z|GTfPTV!(0;$(tA8ao$jl;J4kO@!s~zt@;t-HMAecCI|cn38{G$^%d>dXKtaagoN( zb&}wsCTDo+%l{KMxw1HMA&|z-buwbi+2N&zZ@po1ovOG9k|=%dPZ@P#?HkxLxzK+m0?Q8=!Z?N z(VUPGNMq+Z4KZdveD%(+zi4v#6&GpjTm^!QC1?2E+t=5cT$d>>(%8AU(#UX7whZ6D zGSXslZB|^Qv2#s9j5&XuKjWf1O|D^FG9Zw~&NUS=8ICh}6XEK{i54!8;v$Wmi}QGf z15=#{Unzd!duCo2DlXF4x!BuHZS&ToFJEYK-KDrlW9Q=RZ}zB9{4d>Ma_v!Eq_K0& z5L}1h%CMoeVxP%%_!t>W8ao%13-aQ)WBC3_4?S*jl`1aM*ts~HnDu&S_75%d@+!qe z8ao%)C+4izUr`e`^Lj{ek;cw7M{wzV!|Ba{>%9$SAkLt zq_K0IF1YlSL-B;yt}(eTP+X+3bFnX(>y0UQ4f~17^=-vP8ar2!;L>NJQ%b)JZKi9s zR}~j&>|Acam5(dK*el7Ra~;7&D1sY*b}kQMG90Ji%5e1^f2uOM<|{7J*tv=kV~)z( zZurX4CRd;0B8{EPE4Vnu8Sc&fpGK2Q9CJl1Y3y7+#F!-%p2{|1w5w&Eg=(saeL?yNZi6cCMh{nuIIE8}*M`dhax)gh*rODnpFfUN6l5BZi>fH@X!UY3y9( zg6lY38CqjK7JYb+;v$WmD})$xrFZZ1$8R?C+M~EgW9O<6Tt7v>rkeoX{51posAfiE3x6H5R9IeM{$wH&V@xJxb(4n)cdYllj}moMH)NTLcyii z>&@4;{g=u0L&ZfJJJ(kP*En1mw*ILR!(A`oUd2TkJJ&ggG3#~Lk#9X{a!pX(lQecN zR0CY|Aw-$#AG@YnP6j`el=Azv3c|ookVe>yXWtU1f5eqzXb9E?pY$U%U?LS#RY>R9>X9=Y>fQ(l`NEhVvgf ztlQ-JtKuS!ohyPEQ;XjE_X{pCxe8TBBaNM_NpR^}bi&fVuQ9pW6c=giTuTJkBwQJm zfB)cbm|S-%F4EY!nh|3@r~LJ``mH9{Zxk14>|9vBgNvG+A@_nOZ!@{Z9xh`^W9Pyo z2d! zq_K0g39cEqGUUu#bfd}jf#M>KovR%&84jIm!9};vH@PN{XG-FO1xZ{Th&9*PKkOds zH@R9A7isKybqX%MZ}{&n{kq9@yW%2^oolJ!f|?fLmdUf0nOwhCT%@scbs;9hak^yE z7N2(0i6+*tsw;z@-#~c75J0=tX*ag%uZR>|9a7r8=DU>)DT3R$rGWF4EY! zdIXnh810FBmsq6n1I0xeI~OXC5*~{y!_jN+*=3gSRmDXbJJ)i=WH{WoGPwWz!AO(q zh$CezY3y9Rh%x6c&k?I%G`Y@FT%@sctq@#LxFWo^?lp_qZfh5;9FKvkbImylHxWo<=eig% zrat^=^!tA?xjGdWY3y8=2rd_{3|Brj`vH?{qv9fso$FG>n0C>dqW@!=iGHuRNMq-U z2`;@KW_|SdH_g0UYS@v+&b3N#?az>YzVO2msudS$z-94+bQxkY9LI@x?5gM;_Ad8j z@mm6s#XU=Mp+z(e!vHk*VbpYkO8JTbHC-#X^qP7;3|?n){aA4c8qHc$3=EXV ziK_#DPfh#zMJCtJ6_=pFT}^vk#mIU!b#~$02j^b~*4_Gc@=C;+pWwK<{{A^^bs64Q z>5xXo9jXs;Lx#r~F*;3w5hL=l^q+*tYqm=Lx|e_S;6SOO)1y55an+@oFr*q#DJKR< zwNG&AQhlK6ps^;`0>ve0Y*PK2;Ij4~ldDB>2^!ldxLR<%iYsOE$FrX+99WBWf@UTf zORvS%MlCK;DPKLH7FZmk?s_fmZ9M%|ldDg02^w21t`%H*EtbA{;$0@!9g0iPXx#&Q zf~9q?6X_g+E5nzIu1Qg^>v1Q;@i4A>y{;PKw(x<;TUu3K=2nM*iVAVMr>M|4y4GD(i0w#4g~Hc| z!RQORD@!VhJ-(`dTRBWAD&&c%qC%>!qN(J9(-h`MuPH@^25WK1?F*NLODaMYZsYuB zQ6ZeB6cu(f>8bDtXHl-lW3YLv+*LlW*Y68ex|Od2=At~RfDH%aiwbq0Dn*6uCa2#W zE)Mys!sW$-l@kt)jvPgVk5;4wqK=!=-`B!C2ufK)QVqRWLbGId4^|x4dl7 zOp9{8B|YFWe6SeIey`hG>@BMbR{GH_I9#Qiub^3!^EDhDQ%%xtmeyP9F87xPyuPXm zw{j#4K2b<8;w%>O5G*i z5?^U$!0(o=Z8&o=x*2)|{JEf>bm(Gomb=SJJz<}>EHo6S^63I@gA*;`5BdDzsmDf}354)us7bL46;K$%#_ZIc*w)JvwmHWJ-6#;Y*7MA}~6vB78!@S+t73c zf*p>aSbX8wMo*=usKDq1zA|WmVs8k_&TY81fo|$R{f#sE&Zs8T%j?h^~l1c1C2y6@Vr&wDqqM~3EiZ7=1C=5Tg?J) ze;`oittj=lZEkx~F``XyfY`{VlZft4cAR)l~Os93i*Aq9j;e?1vT+-aRleNl!%3 zT*?)ZlunOLhoMiGW35saEUz>e)kqUgZ;A@5>8MB-EHqqammz}U3U`Gs=nsZ4JoQ|S zRgK~^bwpA}E)SNKmWQ$8(m74PMn!)37E}w2R#!RU4lb9DAb-@ zkK}sGO!jhjz#A?psl+1G%5HWjlUvODVCJl5B)~~J5XL$r;Bl+vj_`|Q&gZtgkrCkvtUktiXu&g+Yj_jVkm>qb^jG|c;^<71? z=>N#xu0D6LqPQH#^`Q)PS4pB3gI>s{tf)}1pj^^vQc+=P5yTg&H**tu+vhC~VgXDq zAyVy%Rho3?Vau?%#O*H+m6nuNR=DY82|68Kmed+81-)0S0Rvud!0VR7Mm{gl1CyE$ z=!1zGNIGFM3Wge$Vu~vxr*g?eIl-YW7k0W+CNzfd%4BJ`;;_3oTwYaN6%3={E%Tv1 zpV{;lrdnH%EqD9Fc>ciS%cni^z!{JwS1cpTJs}@kPM4z+MaCF`C!`yOuEpF`;x17pcvEQ;M7PkkmQbZIGOwUBuJ5S}w_&t-)+PB@P;IWd+i z%KhH5a(j!)Z1MC$=O{8eJgr5|CsCirU0MbWgaua`g@qp#Gs{YMFi=)j<|(l}!wyKQ*sL@R5o^#xyl^~ z`-(k&zb6HAifr-xW-y~O`O3l}e+cEada2?N11p9dwJlv$>7}NEv35tyGNqNF5?=|B zN>;nx*1qTt(w&vQG?jYaD1f)z4LwmF^j8+^3pzD92{mafH85lg;a-YMTa(x8E-nwF zSBA>mvXxASS5jZp!{ZfM zXx^mNxJ^z~?qYu+SXo)cVXHi6Vbn|4S*mi%c@~6dJ~v`X<%gQU+EB_@SDJ9LRa6Ks zTK3k!Dzc=wI2?vt4J(X#V7Jdg^si!3WzgA`!D3%!Fcfx+N2x;TaEptzh>#(~p!?iH z`OGeaIj<^Q87?n1`>x@F3*0?=|5skPta2>(mseC&V!@lrcq823KtRdX8%(Vjp}}%g z(=Gf

gTPDg`N?Y4FgANwqTURxZ124@+VNj4~>(T}IKco(`21SCoXIVwLYMt4&8p zPIVXIz{tjkC0A)>xXkQWbT*`~d=;1O*UMxKqNF~bF95R%9t(w6n)+67DW5&+K~Hac zlP~NJ`l^aUrKLW%^!=s8P$;~A!6d{l7GUho68{Quve(k+#ij0IPsm#ir(EbQrVR1G z$5~$T+B$JD9%P|d!_emR5>_-5$;l@iXbg*n>u6_{@knlz6y4ZYT83qd- z&b}%^9wA?GF}h*M#xiK3Ac8U&#KM&riMBP68vmvrG(OQUHEIuAU$GxUA7)=S9HVim z+b-5y!pvvb)5Kg0F_tuP#oT7H;|b2=F9}q7V84|f(+2Ig&{+l_^k}#otMxKpz->BF zQw^ltsNqQpPMho+4tBTlKrmber7!)f(ZWmzYtT<9yli#l6Aevh&hD@ldyA{Eb_$j2 z0#*Ljj5Vh8xMs`GkB6snkH0hs%ce}*uxF#1(XO5b3<2F48!3(LYl$Pcq2 z9+#okzHSLnKvZi_ws<D=@=Mm}u&DIFe#+B%20e^*|RAh$}<5#+YwN?lnvbfY2EDhmdNu{nP!oe6Y z9afc;akZv1B(Hw3&}nHG?&NGm!_qQ{r9r?Ogl)?-u-jA-Dz6U%VaPM201Hh;ahazQ zW=Kp{UZ_dwU!tf`c$q_=7Dgf2V!A=o;4ZFoSC#q8%FBIt*+XWF>p78oQW1@VkyXNPfy&w`cZ zMpH{y7jhvAZ^94{d#1GoIcfPTL%|Sjes))P)Ld8;itYw=E8X20LVc&Gan~gBZM}y)^j#afvica<&U`Sm^RU38M^jXtgmN0qpj46`~ z3novUVu=Jgxu9VBbWj$~m^M@1Sv0EgiqTs1reFIf9ts~`nhe$x-;6m8e@{E)J>!bc zL0R{>Fg|NE&iEzKx$*rj>n;+~_2Vz&ARPF|A43NIQhhgU5z_iCXgt}1OuPjj?0b1F zpy^R`Oiz5D&9X0sDP-aAIz_|Z45_~3b|LcpI_M6|ku-yqF95o!pt(qG5a3(-!OC|B zXzo#TLzVC6ibm$F%4d1I&v?Gue<7LfvwtUTIg*?EkAEkvQ9J>D&JU%%gS=N`KhaU@ zJ82HB%s+2loo8OKI#5?xRUL%I1Rvj$A5j}8Z{jsb-TZ1#wO`}6z;Z^w0Rlf-7OtMB z@he_eI}stic_x0kkV9FOx7uF~&qV{jh~`4vCUA%`B`5AWtb@8EUGS$8ZSH6k-xph~ zQ#9iH5b{$Tb#h&Zl4s?-h)y69;A#!l+B%Xo;!AK&+`NzF2`nfnsjDsy4e{{?#^q8SNRpX!x>ReM>u(m~LSe6??+G%{kY4 z```M_Hwxncy=+Ptd|-u4`3<@IDbq6-cq*%fP+8F*=+t6iBt%1(&~Wan**_r12HR*S zR#p>`j>XLxOdOwO3sudln;*uzOVQ6<>}T^m6=8mJ?r4w&^tS4z?_fxm8&||P;XdVy zbY#9(FMwFhS;c-N?tWiS+ITRl6W`locgn!MI(Y8I2W9G_aQT+vTXxKUEiz~kKCvTp zSW>CZY<#jVt#8}05&HCk%ASvE!W(>-$aj{I6BDoSR|l$m;v;zponFtpu^|cARNoe?5b*=Q6?mrV;w{76@cBPkxLocAJ+-C1b!hKN*ggC?3;acY2#_}P6rZ;hj|iW$ zsQ;=@1*#S0zxrE&(&1z5!IPjj;Nk71$2~QUXbxPxZFA?zD90zxw+@RvD1Jpp?g5$h z)^GuS2=A%VZ)zxUP8M*_C-VyeiPbLX2>cR$Rm+`$HBUt6$9^LDzm)LK?5lPUd+TsT z7wdIt(cy{tGv6Bi5cBg-?f1dCS|V{degzU@z6+dlCQdc#9>)Oe|p+-lFJ|#_HqfU=6gIG^CM{d z0>Kb2T=9IRJE`RQ)at@jx&hsx=K$D`KNl)-IN(Y~qI2W)7umli?abjlzUIfTPkvLcqLz>zuK=ANDMvO;qE(g2< z5PvZq75FM(0&p$hIzVjlkKF`_xY&09uL8UWun&+jyBaVb@JslUj@pQgqH|0Y$Iam~ z4v45TAp>Kj-$98%cv#LbPIrDO`{k+?xlbY*{W5#aCLpSx{_p9e+q}8Yq1>x35}>Ds z{Wq|tKRTS_1HIW8D^5gSyn6qz=&6B(95Xvt@6U)1U%lVa^W5xo15fnkfwtXh>rq(OmZ2-!y%tv zunsf6blE-BSOVW*W9ePo>zC<@EA!+?It;&f$cW)obQG53G(c8$GT=7ADS*!aP6K=q za2DWhKpa4cy#a_(6nh8obinrkivT|a^a37)JbZv(1}p(Q0Wb(iwN?&z8sI#@5Nax!+4II!|^9a4zW=jc`6QLO<dXx+X z7I2Lb)NoH;de?;}*90blAZTodXxM-3N6Absjtd4sBQWS@6?h3w!n5Q{{ILDAiQ<>RZ{S){w$p-HO(EDv2(Yy_(8p2DPgtq_S7{<9;>h#!}-V za6k%su;ttr}t>~Qgj?bsqEil5zlkj z*Cx}YNbg?IJe*9IWKZY(_AAi*F_|t!dRa$8F8E^@tbF5fZwhG2lIc>U*9@9yGF?*n z@{r!Opm`{nE=78~K=XPsT~c~fK*Ns0#S&7zKVUnJN}@~EzSQmqgYIB;rqpQPr2fKu zrz;vg>s0A|jGJeGZZtsRPe`O&?U8p3-|tv%fS{Sjy$Po_&z-`7F2H<>P}zSLI- zp8)@x_+v2gO_81(G@)d=r1aRn=PMeKATFue_xFguEQu~v`_jvD^NDzTrJ_L?N`7yH zX1}5{>XB4F)_2@VA}QmNs(hCs-;cnc^k5Al5AwM_j}UxC3vg zT@d?$x71w+-cslMpL|QrxAMO~1Rt+kQD?sR<)}X%{r+G5>N;g%_-cP6brT=&vCE*X zqg~(7!k6{m(QnCZx8h}e`tP%u!f))=7kV$nd+yY)vl;su63~S=S+IW*FS+-j0b-ce z@gMJkKYAu|)Pv0b7inOkZqm#_ZIFU1=O(7)bt z?YFg(ZBEAogKd5 z^0tEBNYjrJ$Zo&3GES;Q=qbEL=c~Hsj@0MKAe|qM& zwj0iQMRVy9A5%aYIe>Jo2R z@m~0ICeqLq{UTm2A9%-I--eHQ<2AJ_uXpD3lWN;quvNReqbcfI*3#XB&vkc4dm39h zTr+EzHPp7WH?;ONMrzT5*l#ae@c+U)ZnbLt7r*3AtXc^T6G&X+#sH3Awh1FI;pvTE z_An6Rb7o8NV^-2DVr5Fgt18vaRLI0%Lz&FDKz7WYgT_`S} zx6~t~c;Up9%b>px1q=bQOcj8np&8fu3U;j#ca_3MX`#d`_~dD?ltnOp&i-Khg1v#n zM#>}@@7@!PU$lFcc*$B3@7`V!zo@?=u|Je}H;{N|WoIDqAj>rMI*$KKA0Hc$-ZYyZm2JFdm!PH>H z)mt-zs~^h>u6{f#uzK5~Ip@t>xh<4v%?*SSjk)1%B73B!CDyQQ5|7AsyES(MeogwR zXt>d##Ek)z*_RO1bM^=N7L3m>-JiHT_g+$Mp0gjn0{FQeKSOx!niVbCf<+s8vW%^ z$RqhXm$Ys3HOLu&omkze&>iWtcN9MKr4H;UG2F6t6n^KDEy~@1RSvml5=Sra*p`#C z4)HxBWPDv$$MU)*T^&80bq&}M>%#4uc^iLZGjDg-)i1;8c)VfE$ytxPld#~aa;Vb; zOnE$RP~^eEh+m}R2sj-HRbgAfr_k>`Pga*6<+4!8tx z5nvnO9e^Ex-v`7T8lydLCEyc)s{w~2tt$XW0zxV=esTLsz}bKaKrbMAy%-kmw;0X!en>LG#5O#z^E)o{^-v$;-gBe~ZPm3Qaw&t>O_xUtE6%y*(B~ zfKBWdqlTN5x&54DX*^=(SdxQOI3_(BH(ab(W8My4>#72p4ugkcd_$}jt+e8;M>ody4G=wNQ$|Xu-P_tx1HjoemR4CK{AsCcP3>z-x;^Km4Jw&nI zFKub7tyNnuRm5tQtALl{wZ+!9YSn^Ki%JzQHNWronK^s*oSe}2ZQu6)zWqC&oP1|z zo@eg!%*;9S%q((=E}`=L=QYOt%gc)Cc9+$?x~w2UM9Tb3m(>}dRb@q6w(%_fE4Syh zEgQFdR)nyVZ3phQZh~Wlnln_IM@N%W4_72-?yE@FJztSrwk29KCKKC|N=LpQDZGbc z$JoH8J977fXG~zz+FaHtZo{Vhjhef8G4@@sazste2o(gb=4qi7$yjJ&G&w)CEZW>_ zCmaxaEL2}{cDiFBI3 zVw^^~{}8+z-iVsFhc@6hhCdbedWkq{BESj^XBfji^R3Qrj<%X5vC`&BA201io`aR< z_Hu0CGhdP5+GUUU_m?MjWmWh;iWEt<1M8=?wzhH%ofyR!DFY{_3&<3QOpNREL%76v z4hPfQLvf@G_k1@2wm*b_Rd_P7MZn-q<*>2ke~9N1JnpfT-|Yf$9}i4xq1cP+99tQ< zw_yWi*`$xHY@jTtww-w+Ts=GUUGQkXGfQt~h?Zfx*+O&SuwFYpi5AJcYytKGZUyp_ z2F5tq;)j+Q=PTytfK2i8!0Ui70B;Ar2>d?qB_NZ7z8-%}yT1W^6~F%s{2h>S{{c7~ z_&RVX+>7w2ond}_tKGj%FTU|!X*26h5730iRD9nJ9q8| z{FR&8rRYVtfV*dfe`|Ts?!^P)OfU5WHf2N;Tk&l3!Lup+Ra3aN;oWdzE9Sx5vPz3g z2D$Rl=|>dI^N@5*J2*v3Z}xQ~mJD~cd-%6w*zVc--0hyF*0$XT;p*A$2f?HLc29v< zhsQEZH=7=-Y=(AhLGxo?-UH&Z1G`E*2s{KF2>dJXRNyDTV&JF165waR^MRyiIeZBm z3Y>yRHDlUTGgfYF#>x#A?x0N>x~gWZY;4Bg5I0|j&&U`C0flSVqma@fnxhoS#UtOZ zNX`ijt274`{)ClQZer#1>gq;{=z?Z4{Lf@Tpl`{-8D$GahbCISHrAx;@= zzEW;JyDJi6nHl@>7>S)|IYhe9M%v{)|g6vIs z>`l4sO<5^{`~>pgekb$}3l0Wjv8(?Kubw+=VU7LOT zY_P5bQgAQ9qxu(Z*_^*%%*XzVRPZ2#QPbsGOI5z zf|BN(>EzMDNq=H!k>Pluw#|p2!sf>+v@y*QUne*ucD6Q+X>Hs(ra5yg(iCp4FtT7@ zN1*|4M3!jHXv%IH1N8#td;PJg$viqwY0=MANBQb2)lmkqqhRcr&rxV4%QhCuXhyfUAKR6phP) z803ru5S`Xo2mBWBN+3Jr8a%2)(xy73a${)9jrGO6TZXQxLn<4a^p)Z^K$Ao?W&&** zW#fRyC5@k2719;}VwAs=rx`vN@NzmDIk65#)|`$;<`gyXS#jioLUHy=*;qp=4p<}} zB8^uZiqdy-7vtnZKI6oOd~Hp%jkZ&o*9~98T{&g;X^p#%?5x2;IgRs z85Mf=N0V0;XTYtQGhBF;TGpq~Ch;>X{-i9cVm&ZX+!Y>lEU8SW!|iSD5x;CE-U?uj z7weXIGLDdat2=}r@wNC%N3?PVI7o>1#RH{@qe)ZbhO$ zU-zQ9yYZy3{5ZVs#m2r-b&p;&*(cnz{*?WQD%`a86s#nS7F0kd6g%{x1~CO@r`BBa zCT7&E!tA{|i^RyM6o}L|^2}% z!20V&e4;WaAZN;_1WL|g`^yJsA!tGT@W7e;X^6Npo=mDH$w-}Pu)CijZYLs%9G#(- z1sg}hOyfe>rig7VY-_}JJ!}*)s7cnmlY_)Fj^z$by2F&SHc=K!|>nbz&V^MN~n(}6pIwZNx<7zm7Az!-23 za1HQjpb2~icn$Db;I+W#fXJKiD;)pN#tXnFfG+|OrtuOGG{(!o=Yg*P-vs^+ zI0xnU2Ox#}&3Ke>r!AX`pW3ZS+p?v8S@xE>7ZxSll`RXuzbkG7GzsVTG^`n$M%i-U zb~hgN1%z$KGRoh{bB9n4=#DmtH$5Hl$!&k%;4j5R5wC0%@hW^+9A83|zcYMA>ASA0 zaUH%=T#c_Gm*Z>5#rSH`FBZUz5nn5Qpz`s*QEiTTI!=?WI_8I$-^aBt&F9;Bt09_z zrG_<`t}G3uT1Oj=t;%M*1mT(McGCpG!ErIN>Mwm1IPFH zrOkD&@L0;oZ580y-Wb=Trw1n6To-9Bu27tchO8(%u4_LYS!;8x(p*C0$QRqU-^bEo zTvLM=CT%WGNoa(|k*}_Bwc|SPk5k{Zxqc!%>Wdmun6_`4Yd&?CBjf6mICH1X#qotk zXdH3zO|>1@3%xtsW^=tFJeKlydR$U^KGq1$wijOitIc&lIm$b6XRG5R+P;16j*Rzi zZ`3YV3h`32K3KSmIao)#joSGmX$V;*zh|z99VA zqCOpQ-wK-xiyJXQ<7iQw^V)G8dN^{W&6UtxLgR?5uW(s%rFqBc&)Qr!X)d9WSnt&? zh7m-)U@Pb1+L(CYA6?RA9p$IrH&1)t)%|w7cp!Va^6_y(lMiRB2K%LIkfSn9KZNX* z3H{+}=XAqkckH#fFy4z18b?lp!ezD9&VT8GOBF4-`iABb8b>Y$2p8W;3Q1Y-gKcwh zywHpWft8B^sgOU_ArCOzxfm#1R@=CKdDR0p7hXb&5gJD>Lc(RW!}qQq-_PditGR^6 z(Ka{&*d_L@n?KlYbB)woLgR?*MB$SD3)_OC1&eL2ahgkL9C4lGh|5^r_YRwDmgW)~ zM_hx1%W8+;`MmEjHrEo(B{YuO87y3ASYqC-fBTEJwR5u2%t))9!KvC=uR|W(rgnx1 zmsLCO41KcH=Gv&agvODJp~A%yqp2D>C)4J7Omhj1BNwND*6*`k1N`)Zt036eY|?wm zsY1j4XSK0YQn}#qQ8cHt$pzOucD%*h6E3TbeQ{#Em(7($kpv?& zj(X?n$&Tx|lO`u^t`jtu&^Y26AzYS(Srs^Xip|BXzBEGPhzo;3T3kmx`k2>n;t8cKmKGa-7}7OUf&k7xw3Wh6&goeqlGJo|1>4* zr(bGw4bWUdBmRX}H;_{0kqIm*8rGNd$b_@t;&o&~3BvH&cIwz#sLv%R3^`qE>TvdD z$n7eX8!GUmb-OCsQJ%DJS4DfeC#~C6(K=JBk9BZ3w%xYn+?eFp1fol!AmnsarQmk8 za^^)l$`yj5byDioIvg*q;VGzUt1~xFE;gKB>vaNMjyfc#tMjX@W;{LQa#mSu$!_DJA|4fL#yIC*3v2B+yR zx?+!$vL8ecUvNQ~X1p|&*JCXEDHer=dNM>~Yh1g!gCA zeC(!kg~xK~&ZTUc@v7gQ@bBlMYp;Ia1l?6!vcepxejfzQ6Pm8Q@?(>F4KxScbRPNT z=_$vsz+u`8F9^Q^&`fpHd4#tFG?%;ST;<1g=|)Whs~E5HI}D$@K(|r9o@DyG%5OgU z#}lAAnG0c=I5HOz4UQD`~qm+aMO9zM=NN$K<3i47arToV9=c9rt=7II%qC()4A%G;jPm& zjF(2r&*LP7TikU2{*w@R!gEdRpFauVXbef#NeG$tVf#3!daQNQG|%Ga@zvPb!t<*q zh9^(1o)VpO9$u#@j|}BeGATS^e08LB@)SASpDcdmGdX;IX?1u)M0n){Z^se-U!R)5 z%^Y8!?f>sO+n<+09Kh5Gy83cZIyG5%lt&PK;s5LN{;8$kl9sl#%NxGF3gBOUo&t|6 zaGlhDgxdkysi%MGK@0!o0~P)!j!uBcKZGalQ!muMK0N`43uf@tgZ6F+*fjFp{UiDh zp7iLuwR3J-R*i4)U!R^J_Xhq$#{hhNdcr?cZ2w`WC+L~(zxnh8>cd2|TA|j5RO&J2 zEqM?DR04={2V}8Xf*rt*hngTKcdZpIMA(eTkp9pIh!pLM1j_bBo0Ufd+Yq7P2)!2^ zh@MA_sORGd0cak^!Bt^?cOn9hnCm5=s5v>W!a7P|a+Z}GZbyzre29QLFxW%K-N#c? zyN`!KS{Jw!UHMXp3%I-Rq^anu*^jz%y?Qv0cK8SOv{6yN4&kcZ#7;&1dbl@YR^`;h zPbumzqcx20H5<>EMe)&6CdqCU%8h3r<;-#{NcqT4TTqP60GZ-i%iE^J(&UQ=7j z$WicEhULWtFyGgW){Y4bge=1(kS|lN0bT<9Ht;$i9#P-F9>`CKo$;s*XtZS;5rn7Q zsCcj3;9)Q>%g|MAKvT9X{0@klZ*V7La15$}b2?*Zu2M_k$rfys*kP#~CALx~Rt%EX zIg_n(s_dVQHm?{Yn`gu30c`fK5M32)62+$8h&et8y{!1cS;YQ3+jAD@8j!%=Vo#CPnMqcJ97AH6!_BJ3L?(P3{WoA%5?>`z5T8an$*Lc2P#XxPZ7vboozrQ3&5 z9E);1)78@X`h~T008e`@9XHUX+B%z{x8eTHIK0v~+W+4>lp;NUEE~3Jw%+-8Xnu&+ z%C>d~us857;5op1fYX6!opH2uV-s*A@KNBCz+V8L20j6N9SAqsUb+SNF@A3YvKR2R zis}WlWgC=E%8i>!l-uj@VcIN1SJexYjlDo^r;)=baNq(Bmds-4tLT_7WuxB+Jbq&% z{=bgLGG1W^;fa0r2HGjMN|JY=CT}ln=FBft8#N`tE9?{Dj%eMhHaP~unjXk z4%!tb|0`P_Y$}d)N;rDPp(qFRgyI^?rW+2U=z#5=G~}jfFAh~k7KM=FpI1H_wO7KFa5T6eTYMxqs|8K<+_!4HyRg8F&M5Kkz1C z3-DIpd%y>P?*ktKegND8JP2eHAB9JW655m~QEn6^%8mR?n`P*#M2WJoL(6Uh)!m`z zNyA#E;V(s(ld`evl;csMFnr5+g=b*-76kN>C5!VE^fItXxO?J^*kW3b{*KLReEmXb6>2Vy4Q-4!`7NRa!ayg zP!eN)V#l!Q+oOpUxwuBxMU&DoDarb$$m7dr8?hq9k!LHrlw>ucYpS^i=N*_4q)$Cu z@tJEl3yGRh=-rHWCFVS2iDj87yZc#AnKH#?Y1`*&T!CL_cuW&Gx%&vue7vaECT+9H z98Qj9Iy}tsZG-ID#c*{`5u$M8Yoscl9GAum!ZEm5@u7dD%wgErkB$QF(5~YQb&*dc z5Fcvfsw?g;i{Ur-F*O1?DXj&vz0Czq0$v3CCXjUS6FN>%@x&W|^MPxC3xMl^q`Mx- z@Yw&VfE$7510MuV13m{N-77%S{SH_Sd{?`({OHd9IRTIApR{Egx2N1TYFjqYInG#!eDHKS+$HhPx}0qh*`A~jWOIj5sIOEK{_ZB zxUVY4bz1A>AcJb@A2G{TM$IxzoS#!EG53O~EXHf!5RVKwdb%oy!zkU*g6*dxQ_Nzf zoN0lofQ>!!Lp-d6vs@}jyMzLt)qp>=8>rgo(Ds5)UeQ(nQg7qcPI-z>SNmp588K~^K?B!~O4-<` z&}b=`HA$sLrrf4cHs+4q#xF;zu>38f{GB}PXb6{w5@;cBh0R#)5S5LCi3*!xT9mXa ze`nZ=($~L}(I4}=W9Hy6Gw5Vy&Su-;v538UzgaY`Wz3N5%Ij9YeCp;Y_5C}*ea@LP z+Bq~62mj7kc1He;2Hfm7YjG`(+$}Uj%)d~Cw^gbeMfT%jUz7h4Lh!@#*TQ%=HfJ&Mra&yb%m=P*V+%>OiSUb!qdLm z4yQ$IH${ghePqY=spje?zUgHcpo>qX0TZgGH&)nOz1i4cgvOCC_DjFdifi-#FUlf+D9Fp>f2OCtN}P$MgF7&>oxXL(L^Lj<}8%E-PQ3cN@3X z=ITmu1tT<$xa2)UN`dRr11J5+<~m7p35}z6jzw5XCNPDUy#ENg4ilCx*`#&(xb4T1 zY{#ag%@`f>u}07(6Z%QWRxVltR}ZzhCTlLCapXd&?NAEQBx<@nZgX9txrD}%i~gYX z`#6%4WcXXhVJ7I#MNnus3$Sw0Kb4EMI^_Pyg>xhQ0O7K7apumRi*2skHJ8vha&f$H zseXrL zPH@CE`ZqT}XmbVG6kvqL5!Z=uwa1-{@5^3ebDg8Pghu!+bqPaC6&vYCi8KDOzMLEB zPlAirM*4XO)#GKq-nr}Lqc_%icsZP`SE;Ezz}~*rMqqDW5k{d=A#Y!6OR%@E;yvSt zyzTia-jPS-ZO>QndZ)>&?5u)vaHzLOy6p0u>Ck>E_uhV<>38tCQtyb*DGfmH_W5?BS%E`bVRq~34dcKM{!&@R8uQ+xjQcJtFljZ&M( zgUbBf-R6ab!}EodyUhz^w|OPjO?T@)o<0qy6DQ#>TXJ2~7#_RLdF-(tb45SLU>Hty zi@DppL5}AYH~x#`IY-m*H%+lIu{eF&PPhB;Jn5qI+BJ%0p0N-kcmu~{7!DHc?MlBD zG(XaGlzOt;(qmWV4o$=GXuNi{eitHoALy2FB!=N6-79_fB7GPOjXI8*Fj6kLC>Lo$ z%8mayRNVoZ`!!vA>En>_E6{x8rt=6d7b9+8j=C`Ig~!3}Owf#T(|Lqf2b!3h&Q*R) z-?u@t$xY`G-pioj-H$ZwrH=#TSDHo$@z1M1HlaRxV0_xmQ5}ZM7O(m+KzID{c$iR_ zBh|-+pt)GnwU@pi!e|1`U2Zy${5}Pm7u|HO@?(7*Bn?M#m{hzT;T;E>lihT#@PY^< z3Yt1Mokw_Afacq7I#+n?8ux1&SjBkN$H{2-yFvF6=M^w0cF+2t7H&t(B4!T~vLp82 zt3Y$3rc0HJNBSND&9iPgkNmz1norzxuJBkNy$0irD;}CuydL3=0nG$Aohv++-+a)l zb<=r-_XE)U%uVMJ-m{uU5{Q3Z^^wy7-x@)8@Ki;`C9+rl2qA+F5c)TcP;^-mp0~Vu z2Q(jPx>UJ%q%U_QP8z~PlcMv;?^w`Ga?`oOV|~0@)hN7JYfz0>y&JYNFcqh~5AbW_jt?SuPv(A-v}=rRHAjlbJLvscr#mp<0- z`4BlssKBig!OP1|Ib-%IiyLahF7GoZ z>Gzoz&ykDF|2d@yc_Sae{Gq?mwR=uaE7Njo+QM0}#)et*s~0uQsclH9P4uwUCMHg* zDw|X~d2)Hx1n{f-B^!-#7fhN^J*KMcyvfz+1jlNEWr`pQm5b^z;Yf8!RiqTU6*=9z zred#M7ORCmW2_dRq>l0OSu}SpPx@$AlY(2`uSI2!8&gqLGCn+MQh1sXgxhAgN!Aw3 zYPh7f0oVI9ECwv7jnyrhgB)gcpKVdhspU)JhFaYJvpCk!SQCSmM^^XWppGPf+J&(O zY53hfx?(Q50{HJ&aI9uudl_aqFLP^VnLsK-oHzM;(v>>#DAJbM4S6$ z`=V|SqsB$9RlB=bH~0qGH`KMXSo39dAAsNIl~0&5{0wOr+>|Na<(1*GQlS_KihuWo zl)T*$FNlpf5DyLWmf%}sZ1#M-ea-6L1+Hk$4YjkdDz9x=0Ff{&R*UcMS=~FQc`aSk zaLK%d7inJx*9pFhaii1h`L$_0?HAU+R4ap0iX9ULKXQZ=JU)sW<09pir4wW@@J_Mo zR$vkpu_sqY%BMsv^}8b%#SzMo^7i94jfcukPTdfuBFN-cl}ss}B0_($CDq%$D)FvL zYRP0F>GiQXRwYC{<-2H)+>E&jrz>A;kNiFDk#Cf5+`d!P+6`tSMg9d}wr+drz5)xnN(+*SzlJ=a!iK{`E);Hk%l)0zQTR8s+rH|<@sQ$^zOmUy)yhZ&!0PDEV6@cwl+NQQv;fKLjJ6!hB9}?LJ z;wi=x$0LHcJpy>+9Q@Y5;rR^Dhj`w=vlY)8JU%`+)7keWp2K(!;&~m<7Cdnrm7jQT zP=&c>5Q67kEvON2lP&gWMRAYjFu0EV#4Ll-!K=3<-t6Sxw)L<->?;l?m%>Syu!Cyt zmd0M(JOvKfQp`{iI|gkp{P_mt%zSD!4z{ie>5GPv!xLL@?)28oq6B?c{w29IXeRgq zD_NFb`13DeY0NBcTAJ$$@qRENOcv3Hc)0QAbl2`czU`*}EqESb87c!!wi+&fum+0F zYEYX4xq$aJ+;lYzUg?_y({|Iw)3_L40n*F2Kr!w9HfoG%XaNoYz6a!sg1-RqT~;phu3*3-36v#N$u07h+ImybcN&Bj% z#WY%m{%Y5rvazXQItDl2F`bNKVx5iN*!7y5-^s`v!@ZllSng){Cmv<>pn23o`)OHF zw+mb_ci3EW7(P@qsW9J!=2Wa_;<9|BvFm=28*8@&)(%GlieJXFQpiIltw~R z&9b0*K^}JY^$jO|W?3kl3}>2Ug8*4(*-$`^SvCxi8@PH5m@ArpwgVu|kT+t56Nj_P zYZl;^n96P%D*{E8ri&8S`^+J>5()uj;fJPDaa+ zaC7vqx$ULHflXU*f1bHE!9rWNCDt{t>Gq>WGoOhJ*=}wN%eIXQb#i?8r8mOn?w1aS z69;^efxB_XZE4Z^%Mq`!s$1AxE4FZRUmVgOHedD4xOcQ!5gKMj?j1e%rPuYD@R@VN z$xb*EJ}XirWgb}nlAH)HCC{44ipmy#R6rCZ%`_GyFUT`}kz`rlB&sBwnJf!opK!8l zkQvTNmJKz-xyiC&iL(6G`*Ag`u5VM-e-wBZ%LPhB8-YA;ep!WihiDp5L2t8oJ`}p2 zxMl}ScKe7eEsvZ93tKU63`L>f6(DT0VH+Vfo>Z>f?uTu-xIGOUzc2ZD2Dyk?)fXsD zp2Fk4JBQz<*oVFad>IpKZPbgB>IF58)sd3wx$_$Ic4MZ@+u*=oi#;@d*6iB(!wm|V zji62!GSqWpQSg0Fm9MhoylVO8N9T!f=CZ2FH@iWvnixU>oVlK=@~PFA_g-b@gHj5g z_fmV6xm}Za!@0b&HyHzyZ2LR~SPpmW%$GZIMgiC0H~8a8;Ar6UK)SyUECnt{*kggK zfMvjqK&Z;ae+uN?I&T0c0N(~q1acD(>3RUC08a#-2dn~419E%JbRbo>A$Q`p0vQjb zULGDL^=QkM%hE=Q+XDQjEt~oZn(lRN%QhGW%fT|_R<*BeS@_M*W87+rayb;hYkpJ% zt9=SKQRVj%#!C6GLRWm;9HeYP*oNWpOM78_mhp-!B$NX*i4`u#4Ld!`#xI>vD+u zTE;8fli`UxoRE!sZUaUTdB{T^a*>Cu|5hFthm|VYz2Z`-@`a$>xT6Q|G&%~SM;{~G z*At!Dx{@?Ca!k$Qa8Y4?pEC+vOL`F3lD@7+kBIr`K{So1`CB!P9EkPi6&j9VTrk2p0N31N+NSq zqR^fa0rSN4QQ=gM3SoO#fcU+F3CFn54Y#g7KHM4@PDu?6#g({x+9k0V99Rvj;?f+kgZsyLiTf)vZ%$dFw~iEMnYXzq$c7%#mk z<3!?J-@xaiHM_z^*RP@Ts%#`vZ2sptG(>BjDz8xvb6>&$4_QAq*(==ADe*<15h=hm zA}Gwj)xX0K!BXbMOvTZp&$353M3mxstGrU=3ga|tCY*?bI22I2E77lO5<>wCh_{W@ za~!CnUaAZRaX4F-#adUgn$P?axinsS8^h)4so}C1!=+skG29qq6&wc3=2F~M^&&I= z`M~G>@3MK6VRk%X%Yk~pIE2Qs$u$0i|7!GzAPP02P|7JcHnHJCw+S{iqOciIhWL5! zg)9a9MglEeaj;*1i045(?oozc+$o7mfZn4_IDM390;#uYGs=vRQDy_E-J=Xk*<+L` zhO=vwu}2h+AeLd8`I}OVOB$NFkkHJ>rNA(-0mzYLF_81#ZvnZj`7+>IU;@a@tOc6D zbwH*Svn6=gJ^|hdJR14>3Gg@|Mz44Xcpvba!25xX&8oL;CZO{#>L#>%WzLhHs^acCUC;ihP5z zjX{UH8ljg1#?d=+jo$e^Flu$zim|x!h>PE4`UWc*udw(vlZVkrls3M|ov8VF_@%cK zkFjkU>e45SSXi{$v-QpJfi69!%(ATJeMx54$oILnsV}^TB7^IhptYXC5M_-&t0$`U z31sA`RsAU8gKC<;pIKYGCAJ)-!zkSI!-@SqECM*`zsncPoEzzUs@&_eE2~JNSh<-} z8<8*_n7Yd;7UN+LXDLA(PDy8qWJ#pRUuay(c>r97L)(hwLd{#uyuoseoe3|uM5}|FheQj)*+Zgz1n0Z( zScd7NJnI36+qL6k=(p@Yj{~_$43!>dPPYTO_SgYrf7l5;56JtE<^o>?QjYx^xCw|A zZG0ziA8?QM->3b55BxpcKLoxG^dSvz0tWygtKugD84l$K%S6c!+Omy@Qf`~IE!!YH z^I{oNDp{dykPpU%;x>Twf%}ULt#D3P8unX7o13yhk{I=Pa9<_DW*nCB3V)7J4$vf4 zxU79U4a&y2RJf#K*p~4M_hNWLMg%gA0PkJ;Z>5{zS}CF3D}0p_-=NOMASnCygtC7( z+_%&j_dD^vCApkaO>1`}q0wYr5N|^cM{6FCscUi>=CgILS0wBAL5m(!+vh9PyE7#= z!Xh!kPhgVK3ZW5x>7B$cMQ%WdR3sk{#gV26rbhV@h=u}QJI9wOkR{LQ{vKF+97-^3 zy+}b@fhf8ogfYnota}e10-~IIAp}Sms8!0;>UntLismT7MtUQBZ-S|=`D@yzmYP+; zO0#Tg>AF3o=0$m7v$}6Z&6AuUM<9}hRe+{mUIgm*3W0SGL55cpeO_*U8n~vEF*d8y z02th|4T&$ZR-H*X#WyAqb9>l)IhFL=Kn?LRCxTlyXOb|d0#c}cGa@ruhKs#hweJ#UeqFib2mWU7qB0}ueTsdMM3^bjJ$Rr}hSZaO{ z-ugFOcK1#oRufKq<%{Lv;=Et58q`&K%UCwJN^fFT;tSuZlT^5mGGVSf@Fs{ko}(GSi|tXzemVlksSwf(5( zr$?oONRKRbX5h(+ReTMUzwYVA{JHD)EDOx_KP@rNO~R+;gt>lsafT!)hhE{t`@UuU zTXKY`rGo&j{_}-#&1$shqrlZOP$Z@6K8fLQB2;I2P0oXuq(^-iFcMoZrX*vP(uOb& zJRV}hl3H_w@HyT;N4R7-a1#8(IMzYR5ig`l*S#-|Dt2MG==ZAzt5#w@=PKbwaHW+n z0+M155BYrrgHk?fJKP*@MR|X&%Vgm55uIxZy`_)PN!El@lc9wN)?SYqEwA~MS-oa0 z?CJF}kM%LK{rY%KS_7IcTa*OvRVf3dQo`$=Ydo4Y(q(Sg|C}oP&anPUtSm1iVfE!w zPT|B>v_kaD3Y2Lak?>U*%U1Pe^kKD}lDBN7Np#X=b>Grt71mGkCXMSM5d?TyMnS+} zZWhFHN)T_>Bsjc86MQJNMeyDbC%{-oQIu_u)>L5iyKc|wf$FABxgI`Rvv&P@rU~y6 z;Wu{|wl-nzz8|CimCIpMqyLw%O~RAO_eFXh@LkwOh}+?mTLGH1qN{<8qiCkFBIWiC zbXnzg4Qz^TQ_A*n$~PBMK>5NV>#08g-E$4@(8SvtZ0@-Uq+};9r0d;6WfG`~tWT_$9Cr_&4A>pg%*M9MBQ? z6a3Bw@_Rua;BMepU=VQ~1Kb2W7RaFt_aVi%0{a0mA2P6BithpT2Xd_y1oAE403g$N z0+4U{@WhLOX8QNRiy+DH5{U?H#>cqWi<(29WH1C9p%0C*PgXTY<8KL>_^PXeKa z7vBYBzFz{C;`i@>O#fTJGT;Fq;)9%RK&br1*8>*;uLWKTd*eK(uIR!?~DQ6i0 zUm@3@_@v4?7#E;*Tx%9om_K3XU$=$d#|DK1*YCoi86)=Kp5ZWMy1}cL(aT{uA$-;D zmY{hPe-&-JtV81S;+1~5MGCLn0H?sFJ>fvpNLd|0DOq z7ddSlk~rH~b)q$ML&8|b_?fI5%Ky<}I?{<*BlkpWzQ+U?eUC}KY+AHA|GR2fo4dj6 zxNb`zy0uV>AeIVG%>K*pjmBfGV|diNR^%ZXDBW6)>$F>rZr4k`az4Vq!sZ97=T|n@;wo%aG;?K4 zW-w;Q*m04DuxUJqiPu(ztYVrPNOw_EzbF>fSJ6xut!dB#q(AN4w-!aTMz z`OT@N$^4MK9gtg}GmGwHbSr@GTy>@d%u~| z#dr~ieI0+OgVF2dPDUVx>yZ_zty)Y(RZwx56)Swi-SMwjAOq3cAWcZ5QYgG=vyN~gAM#~TE4Z^Mo^3|?(J zo=kElrg1S&_PkC&_8ywcF{xo0C4oWUHNX-eUcSqTL}*pAq2?Cg8*slB$QHB_k7_}* zWwQrqH?}3^28+QsErV9BTadD`1^r0ee8+Y$j>Sfq9z4-!jFL-J zV$4;sp(w8XZ%=$QQd6bT-S6kK6&(G)pA6$}* z+O$H>Or1P&obb^ni1^Z#d6{sp5D*xY1xt5R=s=7nDtQF3z9ReX-5O zzD6T7j$CwstKS#me>}GadM>lMAkW1JjibbJ;BLninfI$FZLWJXm(V!kLNfsuYnXBI ztPY!Nx8@QWM_k>6ONEBz$;sO@ZLYU9m(V!k3J8~#uT`&f?O}6eu)tx2#u1mK&1c2M zvpQ@pj(jvK{plBacZaLp63+cY^GciROwA=U!hgPY;SV$enAs_ppmxEBOm0(=&%CM) z#2qy0Es8T|zmK2o*lrfi{msI*Es7r({5}S5wWuDc7R8a8riT%9^^0C`wQKqL`L`{y zx$x;yjLLJRwGC9C7hQgx#WQ zbN=v{&83S{wjw$Ed!8e%ySIPY+2+D)1~Ee8i0f$K3i3am&cFTB9X8jQnoDRL`8r0p ztb8TkNoLqwSlWvb8b@5m3K!ErlX#?amd(Wv!8Af6wyU)Ze<@M(#}`w z3m3nSA8tr_V*LFfZCgt}q2cV?lA?W6t%a{dX!;sKS8JhswOh+aFP9v)xwdOAp>gDt z=hN7i(;oWHpz$`>8=6aK9Hkm`#5Mkjs;6wOR?Q_ej<^O0mnDDlx_t4O&DD>U3L`X* zxQ>Ubov)=g73{aUiZqwdIN};8T&fk}BDIzeifpcFnoDRLaf!T2$)7`S+*@pOE!A8~ zrlrfD6H;-(V$}Y4;B=eoI?W|Cj+StuaPc(@W$rgl9t07LDtC-TCkagmVQ}1{IWg4| z?$;ro*rp{60-arAP5WlvY;*0@Ttee0vBAP+mDuDr9<8;x{-n8t#!+G?JK`ESJ(+8B z`E>IY8b@4c^hlxA624k|?+Tl%zvdDeM_fZ4as91i)i-Revox2`IO00Rk*~(d$9-yZ zP1jsPuG*d3E+iY{)pt*!b{2zo1UxTqFsBz&* z{K6&@?UF7xhJnWKWYJ5C)-lZW~6_xs+#e`MRZ|A$L% zX`8Rpg=QcATlvaQV?Fa&{(CuEp%ja#bNt#P&9Qhh0Tx^*%SFXOJtIf4Q za|w;X>$0t>G;`rR<*NWLUZ;E|5k|VExVA4+y5Vl^1%2jG8)xebD3`K>*LGzcL}AF& zQyse0j;9nRF5*4{XFHyXbJUSI+woMKo-yi7d-+vYmoJ!gQSBIAX6Lgyvoh?^e8vm)1%yMPsQmdH`~*r+-y(9=_ohb zvrW0#UTw=Q<>zr?f-0>MD6P{^PcImI*N!e3M?%tkJ(8K`tI~Oft7YhKbRostp0DCP z{fNBn`L-#av^2FXAluW~G^}*0&>Y{yM&P3G{Inm(*4}wb8v^MCr&py>vWY zey0@-8xc%1fA0@nfap*RFRjn^q~eff?d-FTb=m(vB)Qx{z^ zPk~DtBpHMcI({B#Ke=63SQLYSOIApeWx=cN2R%$xV@Z{7T*Xca;z7_v| z=BAVO1W#=^fp``)``mP{@HoNz1T@{a28Bt*>k-~i&=k1oT;XwIe7>fU0P)Z3^dJ`9 zg)Ta;@_QC^^`INg)h zG+nA(T=`}3{v0&B+;kq{y$zZV-E^+-f(S2w74T_X1;eD`^$4#LG}GL4uJBkNOErxI zh<{%7Q406VTy$RLSC4|-0lIvyoMDbseltK*r|DApaHWq^yDKz}1c-lL>AMf{-sqz9 zN?#mwrC3+*>X+HmCA=)NJ^pvX;}Yk$pvmAW4JH+@M|eTd40Y4F%8%`DoTiZg z@z1OLehPQ2Z;eiT2LRI%k5~ESqWnrgGg+_2j#PfQcFwp`)1~s^k-j@MjYN!pl0J{q z#2$9j{rgW7TTt6@QSJZ0X<}D&;QMHtV}){-bF3y#nIuP9-HHmkc*(p5oaQvEpjAt&XLk^In!c zj@PKJZD?486VEPcz)pj#?mH}Jxwe+t{`BD)TfBx+j#5&mr}6Bm4Rn$d)h1P4VDLC5 z3ZE?IJhF z$5083w~#d`fmfDJiB?4wvuIpD z-&ntR)`I%^NDR9y{}Y{dkgb@D#y2fpZT+YyP?or_w(<4wCto_Z(R9}+YRG$q3?Ub z&djc3U%z|o6?02&-F@h6Y~jV2?{)H2Slqo&o~q?Mq5bQMzCL;C>yxME)Xu=^RsT^Z zPpMhuzxP}zdncM~LX+)i;mur6S_d>0qhCWkwKZ37RVxcZ(=$ucn9pc;i>C~`+Df1V z*2W#%Ikh|YeHM>=5ghZT8{tQd`}(zpe-ZCe*&0oj6@(u%nun%#sd2X&?$is0&8MS@ zZJAp?%MGvDc3`g0NLFNg2@fc=?h(hWKY*5`b{rN-M#Q%uyk`H4o3OttIV0oC@S2um zrXnY6KK~NJW%W) z1w@`?b7u_rC4Mgfa&6ujkJ_?Eo7%Fb+}3N~Y-1yAOp9gcuQoj@TNZw+%`|dBGPbPI z(3OU$=(u)QHcXQA1_t_W#A6xd&yrR)`t!9J_RROrG2>d1{0MHvX*`UVZKDG)U%Ow1I;9o=;(Vo>0OIwou@1=eT>)gB z2l1#nr%i2iRc;&bTe)FdY8?f^Ok5Z%9iRK_<13=Fw;sFgaROVpdAP!S0av%`%bKZF zb~6Haf=$J&G@zb2^2G{X!(37kZ603?{mDVtj<0kmpDKwOEwyIJM2o9JhXTeYQ2a*G zQ-LuD;kFTW-12-dP|zCY>^-W(krVfo&wTO9 z25|sS+Lh0`mPagcR&*VxybUY59$x7cP4z4`G9JlW<(s##zEKWw#(Asip7};BXXswt zuxM%ZMGcD@>#J+-$)`FQd!r|p&=ne4IM3~$S@%-C4jE$`KiH=;4JGu{Mb z2fq!-Jr~~v&IE1*&H;WOI2U*)a31h3;H5x>6KBftqALCa;Lm_~WH51U#yf(3Z_(rnFmywq?scUgpg*q*Q`Y z+1QbpCn^%5O>4o()5$;FmVpHjjr~NKA6TY5Ztd6YGdEH&Co<4Y_SF-b2T}`EPg zmfYWkCdE?50{%qe7cG5&WD$HJ?rtyEXc$&t4rRZA&>lRR30z(ga4f6BJ*ce70oO>e2n8vD@ zPCVxsq7)x7du^z!$+<3SW`-jEUQHF|R(R%w#@A$C8Q%JNZq&aO$uDT~m)C5w>?OW& z&6%CWxg>*HR(aH&3Q}cC^sUfCSMrEU>dNtO6*ia;@t{MuQEcYNC(4lZzyL(NHgzMG z496QbyzzETXV^2m4ZGk>c)7bEJA_vkw7Wx_QI2ESGO)GjV75lpUGTOH^T3Y6iPG)b z@ojX3T-Y&*j~@m647dUK1@H#om%v+qUjcsrYz6)Zh#lkcp98ajryxumAQC@|Wdj@w z><+AAT)+!~J%KgAUceX-+Eej0z&^mcfq6i7$S5AwA!*At_NClj)3$7b@h~rzA*Je& z%9e%S6U0p&CkToD7V7q82#6h!I5AEH)zPcOJUohzBY?66VfzLizZ}rY_$;IR*;14( z3$`hEFy;*EhJ%g#MhI~Q5m#Tt6+m2F=0I0v3deOj&LHfHKa{c!f=$Hny{&>Fpr_Up|G(e&5`8{giO?o2FuM?OL4%5Ii$j@$ucjDz0eX( zt`9Xa4Q6yuS#z(>j3pO8(07Ups?4D;sc4g#p>XpUU!|G9UCE)*2xUy}IJ4L8z*@8g z@PCB<+DT+jFPsaPb2(*D7DPzL2xJd`K%VUKK_FeOd;MC8xT2CDa@H_wh6p|i+%1(gztt)4*;I+ZL_l|Ms`Sy? zRG9&CCDylCWZ|ZqkVVH-3MDNfDIp)BWh%<0S~FG7m)4r8Gi7nW2HBpt9kTT2z#U;h!4(&P+Vv6}10UQTB16T>< ziLB=W3xVGU76I=Bjt1TZJRA5ha0-y3>jEGbh0}m|J7atU_yTY`@NFPe4dOUY!uTfe zQy@fW{BOW&U;ycw38Z4iEZ_hj6lUT$FTsF_jgJD(0rDstybcnvigzMftkR~$s&b=P zRc=fV^K2QqDzU0;S@>NmZc3~|oW2Ed3dK!h2mJI@o~1=Yv8wneR+TLX+ogE?Ql^a0 zGG1|AB9sIA=NSDDLG2H59fi1hBCagNl{ts+fK=@eow2C!C|p&1q_9#(yH|XQ(sxt` z<0vc{dSc0tvkijFOBwY7TNyPf%B1o>pcy4XIqZL`B-b#jRtD~?iY3QaB%WM}oMtrQ z)FB~=m|OMhLcH|TJm%hLvLp|0?XsZv4r_4>j-OV+?J6l&!P?Y9y4R^s%EhcfS=++N(abi_bOv zY4``<_VIO26CTSjPIkX;K&G6A$5}ER%YXxc%Yi2YzXjyfe+94rxC%H1co}d!Fb|uo-v<@M<7uBX}jKyA5sXRiJWPuYFY`WLhn=3KrFEl#Shn z>4*OF{}Js~Zh&-}^sSFvANzgQ%g?&T^0?Y+m#(kLI`aDt;y-OPep#N;X1fI8nyz)q z_HOG3jCgWL51WhPghpr_`T-C@;OfQycn(c}&9u2rhYO9+IO5_Q(2lF&+VH(L7h4LA z&^Y2^UD~=?4Sn|QvbpeDS&Yy);$r`@<9hhmw_mck*p6s~#t|1=mfy$FXkIAX8L+v2 ztQ^rILF3TgVAc73oZ-`4^{b~pZCg7W!2G^v@!zToydfbu%ytE6^+8w2UE$;R@!bwO zrSZ_kAK-NnZRz#SzUmjPN-N~9sgVBwKbo#8Se|}gkpJ=AAMf@p zo2yiF35_EzE)(r~|Ge9{wKf+9ZZSgRh)Y^>s@~5%{@@2T7v!55tF_C4y2{CL>+$r4 zyWdx;ee3fdh_$V+K0?C{omPGIPSqE;0n+qF$j*Msfz-}d^4V3hY_7*Nm(V!!#U89Q z%oytJAI!Yb=6XeQ35}yYA1z$gYH#u_PcS+UYiSNI*1A4 zzf;-_po`C%G#;qA1dWabo-PxP7aF!EtBnmv)ed#EX$G{Zoq=$*+gQI>^6#;^p3z)F z&*tjHYK9RSM_ebuRq5N23vTA2U!RjS8SBd5l8b@4%gp1OQ<}VL5J#KSVYc8R2^qs+=_4_zC;rO?H z=^dy8ckOWYgkG6eJA+fTvr>mV7_|c(!8D0IM7XS6eDkB|aGT50uN4|cE~F)kjw#qh zlh5XQK*uFC)a0{CXt9IOH~vR9jNPDlS<_MGiY7tYw3>7r zXfSIqGB~q>Nzr+P7X-~vH=QdyPV2^jX11HoBfL0h*1PFk;V~a~YZ|7H#!F-4=WyQy zx_O+(!LVGs%I^@|uLaFI&fH**RDM4N&7+zwRW7ddvHX6cX(T}W^Ge?t2;k44>laj1 zzDO$4`{Z#={)M=4bZ&rrgP<&S?v-++s8xW z$0Pam2(J`0=ep@!;jw-fX&Qz{<5hl3(C$~b=)B606Q2(;gS&w zT`C{0^s%1)tZ5h?jaT|e@~Ml?D}6gacO2$#Z*mR?bENcTV?NY}b0V1b(nmRwuW5u3 z|Gd(7J={mT=)BVR9_XG2-Q%1s!W=1mZ-M5ZrfV;KEWd7?AEp_v^l|Ze9O!B^EyMFl z-^*}c1Df-OssN9azEz+}YP$B)$MXBJrcoj4^7GKRy3bAbk84~lLtJMWxC;da8@$KP zn_s(lM*ZRuGpIdr${DjyS=>+~_8H60$e%H(c782RSD10}9Hp7@GTJWgb3CmNI z^-#Q7-MPi#Vmb6-X_mZI<_rE|NL@;|5Z#w7Mu^{xgkkqRD3q*Ej1Nu<28bi(BFstMBY|1~;pTmr-~ zO~fBGvcC9L?Xi#6bt>$2@^}95@_jXR*sUe*)4ph)T>0X0eKNOAov<|VmtV_?)1ZHA z-nZ|(XUpord#`*l_)4J5C$i@j?q_elqUNX_H@!A(@8jinj~s^=S073^TMm8n@}fxj z(gj_8Z=dsNhZ@;P0Qx(M=I^Zh!B?N`zHa#Nu`6awl`oiZKlIDjdu!3Cd#=Eq z2P`3Sefz&vb3ya@eg62+{x0vI+PLsWTr(=}e|+gmb6dl$|78ugK4+a)_TW2b2G5zh zZPK3Gw%>sLViHbU4Y%Vk$MVu}8zb)C8g6qrFZ)`*J4JOu^T9QDXUMf8(sg@&bS3^u+Sw zjK=d4%UAjvtFRq82#UnAtc=DniDh-Z#?gt*yTRgX9GO^_lX2N8iDmPBjVC2GKP!&M znb%U97ETN`_AK16mSJ}(-0&9Bf4>jc7^XJcUJ5t2X4!JM(QrZZ2xb!6G(w|Yzah3% zz-6zAo3}<8_Zh8O9(o!C)E>aLyMC}C ze(IN{f%{(A5H`05?%U?y62^5a{Y;ZvtZ)%$;6Chczi*F!OVQTLI{9Bre4e%P*Wu*E zJnSq*$TN#p6s-Iaqcb04{HrUXiCrN?hCj3FEfvGoH~oS80)hL+4^#Q8+Mg`TG_PX> zaLiZU;>8Qa61!$5%kC;#T(I&9b9}Mhl7(C)KJ&!}A2yCpvBa9NLCB{&cr zx9;V^!Xd6DV3rglOIEgYf&+p#;wxrjck*UhTl{9p%J_C(gs zbkj={E6`0ZNqm;kI5)8Zy>w<&6>DKMt8t2S(g{{4EiH`ZTvjZ7^h~Rd4p${y7!5U^ zSlF}{;Wr*v*z^{$kC|YCk_ozUgFLSo8MJ+u{ATiOw=(=1fG5+qAZ1&VvR#|9J(RNT zNZGDOP>Poy_?0aaz8~UYe+;{}q49k<{dwea`ZhGKZ)#@Euc_8*Tyy3vs9m^t-lBzz zMLrAyi?^YCK<92xK1@ZbEW^0jW*8XNooLQSl`uWu1oj4A2!zZqYJg`0=K{wA>wwdN z^MDJ07Xv9DV3+Gg76CDb;(eU5{R}cOeh+@ffSZAkDRLv&Qs6824PMb){TA@I_`MSN zK5#9NpK{j$j{;r=oD4L9*kLNylCT9~o)~B6x&?SM@H@b5z@GyD1bhtmF7R>Sd%#D4 z9|Mt=_+Nof0KWh}3FNNS`+%7!pKU-McDobEBekQ-=q3awAnPU$9z9yD#iUM<}*sFMVgKd%k@cHec?48A5=VWi)R=H1E;Hm6E$zLf<{ro1Kb{aPK)7uDxOR>S8Z!b+0ZnM)5Mq6 z!H$haj4QJP-2o}X4>k1Ph$pRMP8t3vfW}-&H6_CAHhFKSKC* zcr3$sgUD|-aE5mL9F3D{F|Y@em6i#N06PLF0&)M3XklgnFTw9FKz8PC!1X|M!1&!j zYQV6ObHbn+Ic-X{Sh=yeD>qmSro}RJRgGNPkSE#Oi^kHggV7I-v8%oTMH-A~8zy-X z6bIC(`GA4C)J^8q{S1@`49KQqR3n=c&mgc{(p|_a=ql@dBp`QW;U)WE|4*$c3#zu0Up@BV?2tYK?LO?NP3m9_4cMD3^J^ucaIA z)Xc`y5l_a5Elp$lMw6?9cm@SFmCVLn-yM;zsf{_sO)Kj0T#Bb*Ep+Q3S`GM2i}i?_ zeiSFBX~U(Q{jIr7Xsq{BCG|dwBbt1SmEF=mS}2xS$EQjz^|j<8ggV+Ad@Y$mU$CM+ z))T==$yAuPO+-ajBrgntu%VGjxzx*h5L41Pw76h(-&nTA-2yco6^@00O_LieyM-uk zZhMUNN@WAT&_0ljmSf>Lh@N(sSr#9w0ck5PSQc!|M)Xq~Ge^AGlEDknRHTxmY~F=t zB|;r>K`qAH$O?~e>trNyd@k-djZKw6CZ&ZNE4AY9jCoS?l;R9biY6B%muH#gS|kf? zIyZ3N)5$0<)-B0RE@NpTe2+<&c4x|lflf=WeTeW}{K_<_jzKw)$%{ITDzPy?6U4?_x+=w%4_k%UM#IKwKqjx2 zG{%W723xthllJ zd?+LHkP^!&a7;H8?(`M^;? zPDBcUb-*)$^MOUcdf;ea40tw>6VP*jmjjD|oGgw3-U=)Meis-4{s4$QxbYtW#{xN( zECX^H9R*U&q#U>dI1acQI3D;k5EHpL@6D?Max!o(@HHUP9RD+L8jus8=|E0+W&k^) z3@!q)ERctI48ZgOQQ)ra&13pO!1_^)VlQ?_2Pjm6`aMK$BFj92)@@WceJ zPe-Ex*T9%iZ93FusoW0bOTe;custI zoe?`KzP!PRb?0$E(WHcl;C(H}$CuX|F`NK`1BsM#3sejFE@7BNgI5R;v}}=(!jgtu zWv4`rub5^uPLE&K*Jy-fO++m!*x7c4LsqH`gV_jdx`1O%E7Zlyke>wegWsR*JNCuI zoBptb&m75M5N^fzrbPbPW*IKaOoqW+l50L)P?a0FVJoH={;IrWv{%98sjzZCV z*3Vk}Pc9ns5Qk+LFJ)&C4msNW5%eLBJ&;ebX#556IQ;%4@OU8Pl`JBk1fGN6TYwyS zAiw19%ALTu_`M6*0E9e?uLAA?CV-G@@g(pW;Pt>~fj0u519D`09{2zd>V|PF;EWf6 zJAp3&p8-M+%Hk4x^5cKP?_UEC0DlAg4EQP#b6exLK<4d_z`?-RfkT0B0wIU_B_e(S z5OOqrDeztTgCC1#Ejwsa^I_%2hOOLSF<5q%q3i!+?@hp?tj_-7XP6K|5=i2LAgBXI zMM3r@h-ik)zzj}EgrKNs5|TioKw=g^1soirjAL9{txIj|+PYTjg1EJ80&3l{YPA-v zwNPAesbXF7{eJg3&pb<>(D(oPzrO4JzUw_#Cii*n^Ske}ug^K>QEi8^vF+e^9pmA? zJ&nGo+r9O8xOg^dUx0N5xAd^yaquD)qq96eQG($>VoTtx^y*_1l(_HO;E+2Lzrpy~ zI@kpbOB!10yOfgvP~N7ySqMAWVw(v4V?ttFE)5Kw(CNe(hOa=`(S8kj80bDwhU*(p zCT2B$sv)LLHN=X?hFI}nk!c1g4Y?{Ym5qtHP)@RXkX@mXkIuu&JC? zHs&mw2vn1UaVrU`Nxq|+SRYwUy@gM#jzq6uepofZy2B5vnv4jC{#%RDcd-JoLBMtx zRbMlV;jpnVWf(#HA15|5!&G~m?`V(1K(KgE#?PK%sA8@9qFLLv5y`dypx&mtdImHz zE@G3SzsxxLeWK>0f03$o6exRsewO}N(4nA=3C3@6hVyt(#*=e>l`*ub_Dk{DekmR- zjw@p>#2aRQ%MmGNmmj|e4;_4wCAD2k3C7`<;C*H$U$OFXTw!FU#vUzY z>cmKoSs;d~ic>n{ChBL(IKQjd2OPieVf<(ARQU@xcFjSKgZ#cPH3kHyLrvcg(|-M@ z^P-_wE|_acP1I6()a;09J~`>rM+XewS7%Ah)l!1N`IN;ib*&5y4Py#UO_N#7g<~(P zY}))j&UGlian6NLb&cr(g5gGPv#b`RV|td3vBondzTu`)Y(GmC{mzam4f> zk?PO?_AHR%wXPsh6VWcQV zFb=;CAzn%yrG^bGJHnFUe49ov4!9V?T)s6ElsT`y%jTvja)6pE2gLLCMj55qq znu;!*gVb$;c(?f8B_D4T{tgv;e61A^KS>oUd9GMz29e!iNh~mhK_^@Wj|>t zuPc0*v!~0Lb%qn~7{m-P0FRIbWK^PH6PX`7DtGbSyRf+d-w}W>Ow6g z7)LAuBE@!_=JvbZ`qGlRR!aro;_RCSljFM<|7kvY;~KOK?pO?gi{JMV{+qF|PHaA) zH4jECoaZW!6e%+nIZr%yuO+onO9{pii$alN+e35BLz_>rr2ed>1j814fAU>L8l%5Qa2*Lhx)qdBiHKb`^|UVBPp-caNHK3N}V8(X+vkUC@cA3$F zVJd9G25kHOcf~jNJDJ+lj&Saq=9fPBT@HnFZI3e9W4Nqk+d!_sqg`Axzue1Vt_<(u z?8G;$=RBEUn5w#&ffkwyyKx^`G=6-* zX8zMj)p27-O&l$Fo>aX`PO1)w8^)vTM_{~8sxIO<%5FSPs_wuz^XI@dvdx3xc%sI5{satl(zkaZ!a+4XV{kV-QaKXwva;>EkruIABh4<2>}u1E$`M z^U!xGFgLkz9{Sb;v&D^b>0^GpuQ7}Vjn_%R7$W#@7tX7^#8F{=1GCDFbA_)z^xdp6^q0mfe}94iJp$acDGI}S?v=kg zk-tlTnR&8>>n?wn0&|JRbr;_N)Z7Bh1~<+lzV8C_PdCmLU*>OCF{Y{b(WL$L&^MtN zFTC-iN#i{9RTbk!Gk!E_oQJ+Ei%~D}qeRUOeQtmm6zjznWS;)czA^GbYPabaUSu#4wzfrIF~+_mp=gWk{jot?_*%TapOGn z9Wot@-1yO?WFU z-?xGJha2aLFVnB*DTXlsKbo|^9{MH%gVWefoJ$|muUcai(mVZlvDgJJoLBncrMK}F z_DB7euf$;XmwtZ&=6#Jz$HNsq##eS@k!s_Wzn{YGpmGzTs8{${4*aKLNphCL>@R$? zfvMEE?!w3XT?tHw8|RT9_X6{n8|M+<*MZsX#(C)LH5=E6<44n7_&AOotuX?`Kd}iRfcgj zel%&ED?gaOzpcVa3H)f%I1hb0tFX9?A59wP($^nu+0_C`|MRN9^~m@kE}U2TjRNlS z`IvjxD0TZwzxRRpMB};(AL~bMZ8~UT@d_XFcc=^J6~3Lo`RfehZ}`#dFMK%*@Dd3> zn(o5K{2dQW*p2hZj~ZYa-8ff%P+tcyzi{I`^gRj8HaE_tkLBg>z z^A(QmLwDox*P5~U3_qIg;!FAOHAaB==M}yiz(1-5<1qYaPz^l8mk)<+z`W5au>F?5 zPGEA{6t27QWx@GajZsMN@QsGQqk)^hRH3>HAM5!dV0J81xc$|S?|{i#u5jIjkNJDF z#wetB_>PC;NiLjM{_X|tJmAi{Kxs>d&$a&dJe(82%)C(HdV+ZA+Xa3cnEHzpF0Id_ zJYNmW%^KHTe3>6lXpGY69p5c*+yvaED-??Qyu!B}`Eds@gH|bAI()A92H_mi7=`rK z$Mx8D;BLLxrO)GLs%JIE)W>yTEIE%1g{KAQ#42LZsV5AslEHpESYe9wt z7~IeBW6u8fZl-EJudeyW-%M57hll*s-BQ>mg`277%sgdg+37QlBaA);xd)n2RO|iK zt!>TKiz*wN`O)~pA;!z5aQ~EfpHxX%X?fYq@XU(JXb5}DlzX=29+@+3T4hCWDz3fa zT~L(nW4Xq{GpAQX#z>fAv?)(oHKLwobvLrSry?>TJ~hq zIck$NV^wTA&c^jy@N!x@HKr*SoywJ^!C9w-XW^qnDm7*rGb(14R0cz3Q^Rr(7{gws zndRl9(!laGZ}d3135>v5iis3Uvu117sTQk3vt~upsM8fIjHKZ;Wz;oSv6y31qZPB$ zfjL9*XH1JuGmg~QGc6vk6|0EMDV;hq7>&)2o*7O@{45(NJhwvMJ7X4-c{bOyeEMdx zvz2RUbasiEVrDL#qnyfvvr1#QZ^v{t%SxqkK6OrTX2og2*z9!f)+mQr;S%0kc1C5e zq=NV0@SZhBzg9crZZea#K(Uya<~?f*(=1%_qlD*wlW~Wu0n`YTmn8oNk z%MlR_md;LBnIaZX+Fg4m;%5lS719b~5B4cnV zTexh_?8;EEBAE8>0_DtHM+(m})6;-w6=0Iw zw8wBgrx>G0r8&=Q&geAf1n-50_L)KXBcFp-ioA^HS+gsw z6nRB4tQ2`wF{~7MO);z#*`XNY((!v;F{~u|lVVs&^oC+sN%STdYzNJ7zJ+I2e)IXy z;yye5{5GCLXhKZ)clbOrmVW*VpV6L}d9oAFK{i(=<2}W&;`zQ}Sn>RuVp#F~KryU% z{#`Mwcz&oDRy_Zq7!%Xp?ote#L(pYow_;dj;h&0OD+_xx$0`dSY0j8*&VQ^qR_XXe zbF9+wspeRv;|FliOr%rIhv$kgJ}QRmxC%1a`<8{Ll~>F{ZOtmU360RXOB0EOpTRcf$;!5UXy+d&cdCNsL)vj^C`>yDAsHEN`3hpZ@+t^Ks)1N zxn^D=P8fT1-Y@q%>Qnvn)EMf2RzWT}iyEpxzxNn6OV*ehQJAjlkmRuv4zK?Ie~;n+URP+$kbz5O1*&4# z%DKO*BE7FG?B;Glwj=BqIgYRfP~Ftd|9kfpdfZINB7Oj>espHV*fAJM{TJ^kWNZgJ zniAf_No8zD=0IB!CK~E#Mp;QkxI)^=7PBF&t#oe=V@hSAt~I4E@st}l17NQQTUuB1 z%FpWNmbzx#pVeC5SPSpu8k0Dtlla4(75{tV;ZLx%jhhxuoPYJf|ehtq-9xCbHkF>1tS`kEZWa~lNh1^^<({N#jTA$UdN(_`AUhTdDqLq z>zbPzn}4J?a?j3>PTN)_?ZW+r75A3Q>d^noHy+-D_U;k&52d_c&7t90tS<4E+t;buZlMBlo04Iua*9>~S=>hTOWe;Oec#dvW=d562~Y zMiLuv=6JWSZO_;ZTNBl6aJMGrlOz-KK$0aVu1%Z^%i2Vh{I8M!T*zIUXuyB%`+{wW zT0Hp-SQdz7YjJ+t(V@Gx%YtzP!q6c^UDR<<-Y{J6uFw?L<9=uZG4 zLwA)vmAVbdM!%l}Jsk9ppu<340OeM$S3t`_Uj?lIeGQbaW_N%xE`I{$>xFkgd0O_b zpqGR01ic#cZ=gQ|{Q&f4&<{Z$2gSN@oblZaIvlh&e(KOBZQ1fcPQ{CB*KAN6-je_7 zAKlfVO=aWSaGvnYLz_4!jVqVrq6dDr9+xkbM^fkGCWaM-xTk1$By|qT&Pi*p;jV&6 z``e+lt9ekq?SRhH`tuHK4ws2G^Z{0DtP|z3L_(4`AvB%eTa3uAD#=ZfM zH5Q-ICMx9L=>|R21w=%$y+3`mDPsycm2KQ9J|@HC+HjeK^0ak<6XOey6Avvw*a=80 z8D*opClak?B)!_}6`m$qJGHtfdnc6)$QrG`|*WVk5R{vF*Ijo|PUg}1>rDit0V zOnj7;430~Mi;_WH=op5A7f@{%NZi7P)Z2DdZwJWzMkeA!6Oo@-InG#`n^-x@Seltw zS!7&{J0(oikTeQDbmSI?Ccno^l1yhTNW(*TgAbEG%~Ef)4T;o*i(;u#bn2BmG41V-PVRO5{6TTJ+J;P9!Vk58PCKB z;)CmU6zYqWfO$-$)W*bnc^mg-1o6T4+{8}sC>1KqvWxw~F4jvmej1k_Ol9EYeyM?U z52hfeQ=ax*q&sQ8Bjs67B}vM&f{ABv-{zL8&}2mLilg}T^OWSp*5U!aNb;me@|>&( zef+#QJ~WP!&(r>>F;ah6lW^l?G0vG6;iA|*Z<#M4egggOwvGG5=^h2OeR)Z>Z40Dr zD}uAP;lc4@IN5K9JqWxAcme$I32}U~0D~OdmR?Z6W-86CZf_3uw9KHZO8oYn$c4;5z8ayMH9!-O-%Gbbif&grcc)vW2lbgL*PU*K^bP853~I$U z)$z^tz7_himicVfKSHfv%|@EtXjKG_UwwS}05l^F=tWx#n`G(+k3m}meJXAu*@`~(?`Xk3^|c*ff?J1}z`S*t zgoOON1TnxwNY`|!O(TYT?5NA3^k{T74H5{yG@GGh6|QFHO@P!vb?AVmcg!oy3{T$E zmK#ib=Ub79{~4O*kTUby{(7;kQjA*My8sqaF`+pk6?j%*7R4rR*bU75wl zj>HWlXv70%f8mJyiF9RxA@XLtB}TRc;!wbbnGj3e&bDgo1~b@`N{Utu(8Jj96LZ~DqV#z=-wKbUdFfWWa^+y+k-iJL8de59t zvO#*2gV2Yw2kDQVB(3vYrBixt#5|IKN@NQZ7fuCz<#Xk16qo1Cs=GaaeyYPYm~|$ zRRfiUJ!KVo%DL$qjj$P_OE1aOF>HgzfSXnXdkNNtezSxP#PbK5Hxj)C!!sUq9Owkl63`;h>p)KceGn7{ zI=&P1B+#!wPX=X82!j@bP6OqYUeiGnpff;k0p<064}q3};uyEi`8|s`sNU zoA*M?{XjWJwYI4{juq}&@Dz^u!gMkXxvEE0Hnzhh!W*n1=V;1Qv@puX9_uXpaA+Mm zsoOMOdZU7*Ug~^UL%Y*EN6Mqdt0&{ey|`aN%l(0 z)*m+Ihdnf4YIkS26jJqyoTI5YkTS)TMy7_c(La?gut-QqX_UKDw?g`c^)`mJ<{3k3 z`x*yV^uhf}xkkoq9LT>DS^d#+l&MIHO`#DPyCsrbQ^-;oO`eq>O`g|3nrsPhIv7n} zw9lFiVvL`j0OleM_4Fu~e5$Yt7nkOL+9Q^Hq!8sDcHGN%Wfeu?vuzT%&CV%R_ zXyDN*!54ag#u*cra7UeQD?2Bb&K652CM)PQAhX9eb#18dn7nlxD34Ayn)oh%)mBa| z^45h4k40b$(1g-{oZNzlW|R-ZLg)R;ybN%t6s-QGQNW?2l; z2ha|c`FI<^(&|N6EGsA&3hr-(JHMf|#Wt%PW%G<-3*h-kfD1MMPV_qzz8CZa(ECAu zNoAn-fIbNN29cU-$W1#F$*Mp7$eH?Tu=myZcK{tbP_P8DNFwkc~ zIg3P}D%aTl5tLOPSLnuhP0q`pt3h7@Z3o57G=4ScYoL6+!mA~30(}GYPS7_&H-i2d zbUWzVpgTbS0?Lv6yPyXl-tU190DT|yc+d|($ASJGbSWrizVRzT86Nh-)%dA?n6_-= z!8DJlp?JhIO-)0t>T{JX3(s89;A{@|FOP$_Sh?H*{acO~p;P6*no}v6{@^GZOHn(1 zekn`z%QRm8EEeQo4KekyKT>FhMcLS!DZMkHljYPjUV2;LsAi+onb6Sg^m4nXUr^L- z8ZW)vybHa@WE#gHO$H)OvXCZrKiJnQN%rl^#?(=M*pXmrcW1a1a&T4;Ba3MdW2TEU zHI#1pr_#laq}?n03OQg@wlS)81kN3dH3}=n7=dx4jcngY3h}~e>?*P9iw>muBu!APlhiu(w*6t&qfUR97=tk_tVC%(^EF_6zdp^qD^rL_R&c{LwL6Hk4#9(J%MV7qscYGil(j* z8tafM62aOdr>g83X1hX+F|?UNdFw_prZPk4h{uXn#185eNkJXM%!&Fo-=5>B@=yzX zsD&1&=vBj(XieCNCZ5SykQ^S2bo4ZUj7{E^cg1|nCmGws@)bQ+ERS?FWCWjP`Qj&m ztY6+^;qTb#>EX$6JpaH^%41=Jm7tY6 zK{?4yJcDldV_(}X$lf5+Cr{lNb8tJZ@oNp^62LLQj?X#_LEdYKmLS)$Ar zF;%qB63q!BI?0!?yk|TLJsHM0*w`3mu(8%QR>05jtHaOTHS$0;-R}c+ca7((u5m7$ zy$u&ytKeks4sD;|Vs4m*{si!R7#Lq_CMNT7-V}(1O?iog8{*=t=?=>7{VUL)g5oWL zOdD}idwdU`zX#n5`U7YV{lE>L13-PCShzHLfEI&dRV|JwrGeXTX7I-@_J;L;bhLar{ zHq1(f4V|*F+jb9tJ zk%o4s_kKYWMct>pHjc(rdLX8yeK9TVt*4~Cw3(e0UZ$J@i}f{_ zvHBYNi?TQi<>FcAY*{RQ3;sk>m;zlS?;iu`q>ff=rF{R0wNiQ0M{H}g#>pa^THnO` zN3LgfGvtRimh_QYx{C)g9i<2OddP-7(=AV=_rlzaFF7%bK~Gd6fyF#k7FyN&JuIMw zl6PV?2aBS9wQg1->t?m+Coo;YObsm}Tgf6Wl;PzeK4Qjl)Lkn#6sqWs*C<_Dxn}jM zd?=i~&40LuxXC6(f7r_9fLE*eN23+sBF3?xe2suFw#voO$AfafH3GB)bQI_dpkqL} zC^ioCdr&NF$zXmW=#kKkmk-jaJOMY=s?erd6~&9=S@9TOhRHPKs#ZnWSavrEZ!rGT zn5CMjWnq+!<@=BL`2|JYrt#9dRgmiS1GQPY>8qtt*;r$gZab28FWn01JEFI71TMcm zq&CYq0N;PGf2Sds*w>e}Mt?d9V=NS!w@Nz3p|bot?~)b-K7PWCyms!;h+pWNme*b- zwjR;E_S3}X2QMbJ41A`K)2FSgiSc2|+;i>fYFJ^*T)TR{vh`ZKx<+g>IH~TvVB>pP z3;f#`Bvahpk+*I}Hn=&O8-J4GJ~%D_Z5@N9@+UB2=|p{Ck;q$@qC2?B2$$jUOiz*# zv;kao#vmhao$NWm(z{eCS!j{%Co+DKEhRF9NzemXWJxe|7|19U@aYWrga=VJJvV!L zpH}*1jxXm)ILdOtG6PZ8#~Fg@ee%|oj*RH!y?JZ?sdOTY@Ze1KAS+G& z-P`blT*=J4E1Mc>M5zi+QloT?G;zC!3f`d(Of?6%1BTJg8voDM|Ai9sFTwKKG+oczo4@-`6M; zrcacp-9#Me+1er&HG4C3F9dMDpa3LoxE9T-&;WY)foXQ#^6JG6OX@1Co0>++V#NPh zTg0V?A}9-Fasi^Yy0sc(0JSF32DV}?s#}7?Rq7r10m5yrT0IVc8s zMmy*r&`UuvC^IerMKfw(?O)yxTnrk+^A(_oi*Y3=bQ)O8kS6sNgh@52v}H@vsCZlO ztaz}{|Fj`jHL1$R#*LeLa5w)Uy^KT9JRN}Msn0m;JAkMJxzcsVQm;l*-P83WBT| zA^!%@shOeVj8UQF)N#o(iy-0Oo}7XDt~Q6DfX{^Ac#Nc8Lcw19s|F;mY}eR&Sv{=! zYg;Vfs1GF_xoR^E)P$v11m#4ex_kqSsAiH*)Y;z!AmN`ZJ^Wed?zSdiC=?OgJRSgUj%v= zC`YLGfc_rz0np8$_k;dJKMx0e2R~K#Xj6qx@mTm2k8%u)X~Pl$E2%F>98$4w7f7n&i#I2)hsjB?|`+G(BUyZPYczc#-Z zOkGj<9l{YF_UY=~JCRU%YdY~i@lD@WS@=O+V=?1;MKHBSpy>7WIzngu?!UtkTkgIE z!PtM7jYm{|JW7|qN9yz~lDM(>mTVphJP$6Hr9G$l=R(Mq2 zx_O1eq?sUZDB27(7j!u$%{&h62|35=)?^&RVh$f>!W%Pe*f+Lyjl9!BtZy!4)3WCT zI-(sJX$r6%ArB3SCAa55zMBYyQ!j*5+mM%N z3kIxS$cKutcpv{Qo}U5T0J;^FZQ^sFeWCL;PnY)Mzf$ux9VZJ)Ab;rSck z4c3rSP1%lF7-eJISAY=vjp@+IJTr}#URFfarcx(|HZz6y480qNtt3wf~lcw z^iQP=ED{n@8ZX@nIbeKmWBisJ7&qNa&0vJ1u zeKnHI$AIffYDhNaVk=etT6|@xqdtH*Bfi-El=?iHl;{ML*BgNC8HAVbV_)5UKfDR1 z9wRH1Li(gWiTLaL!>g9FCI#1qRedu~d27DI`f@s6@;bV85MDl@ zzrm`sZ*3S|&Ng{>51q~L?deH!Pc(ID6MRIvw)K?-_Gt1-GWHx2Nfa5ay(1~SDJe4A zzE%tM$*k1*m=>PeKRE1P(QOh91RLR&7^}Xkbvpa4G0{|}*}k6*NHoUzLko7@GQ%2ui~*`>AB59B)=+XBFH0 z-6bi8L4tk zyKajoY69qr^mJnsPwgMJJ;8}w7q+d=n&{u=Z%P_~#~g02Jo z7wFTVUxEGs6q}ypJFee@et_p6KzD<7f_?^yDjNS1#0ScOgda2uVZaObcz@6=&_hA7 zX)4Zl4mqGlfMVblF9gj49R`Z8lEg=XVpEm$4|v%tEAst8S+WiVZ37($x*QanuHsi| z{xzV){|vMc^fu6=K=Jb1I2!apP<+26z7F(Q&_9442f7V(1n4WE_@=3R?-ehT<9qRp zt<7<)${Qzv4gsA6iuE?*1W>HE@q4E7;=2U26we`0Olpm3pxiiy&0x|`^@A?ePtlfb z#F0jdw?^Ak3(Gt-4c%2grEF|<2MNzNuD}?F73)!0Q67#}>w#GPJp`-22V(U%4=dO? zSOM;J8!Bek72wn`^+|BGuEiB#G>g^>@D=bQ0*q}1xDINb(MM3!67Y+%T-q}aee_aj z21BnZG_Nbs+-s6>C zPVBZ&n{%Po(x_}4ASm5-B<)_h71CU&J=9~NR=wJ=z1C3YtT2YhIji&;s({)3*>}3# z0Z*-cb7mJlg@d)$knF}%hf@;80Uvr!{d(1QhRJadN(}%+x^1hxB$nM=)~To>?H4AJ zIL@Wu!PVc1cdw%+v<=jUVc;LOSjl0S-BGOS;uT1x>9jmxv`*!#4|BbDsYF5!(QxZr zsyKkYQSb0l6;1DV`vpfq*jF5Y0N$3|$>9Z#2`Ycs-39E+k)E$cyt+27?l9M}$JSoU zmeeih7aMty^S@ii)S4nkPNtz>tYrs+!OWvM54D8Pi$OV9Yy#!}PwfARSAi}AW$SPO z=q;eDL0O`)^GiN!n*e=86V2AmAoRjdl;lGTlZo(+2_XAX7wtY5dCsD@3$bM*}UHd z%I5tJ(3zljf;NNx8kAZ68_>Hz?*@GY^gd8F@AreUpp+nkRY9Rm6%@szwBj+2_U4^j zRZx_T1tluH!LZTTn|BMNY;4}E1^qN^)NL9sy=7^=)LE^eOnEQ8X9=1p>Nbs+-Z@II zbQ_rxUQ;(?qa+woWn;IYblXEg{a(5iQq5U=5|mDl?sTj4up?>r(yfrHOUl8!!)&}e zv>jcN87gYvTuegM1k^oK#e2k92V-Gyni?Mam3>Q5Xwt)MnDg4X9Y-JW4iz=^&uhOy z7#E?kEW>bZWTgEo_GQm^o{ouY-WsmHk_$)F)WtGbizGggv%)6kR}PFC&=J$6ItSA4 zvQ%w0kMpSh1gCm%5Q(9TBu7S)%d+-hHuwB4C^xVpU`nLsr*!L>+BxNWu<|bBfI4ym zX0&TK1;RYOe`_XwwT5}0@C|6`hv73<7PQ~mi>e*LRaZZk2V;;7(CALI1FSr_l zKi=g3f7g9ndg2$R7hyar#U z`i-OUf0fucEN9=Bf%RjxV=Tj1l(r?)w!6}{f5J8xzYHT28C)&0oJsS|LWXe?Y)^;{ zE591o4}oVZnPIGe?R?0h!-Q>x*w(;yk=QVBGnR`DLo{Ql*mzy^g<`|7%(y^oH^8<` zY&XNUQf#-twnS{`y?I;Bi)YZcogu(gP7J#5WldkQvgTU9+W z$17ZSagSGc)ioQyQlQT&fJGVJ8mEUV>cm~dbm>C-7`c`l@1Au$=Go5U;j@>#z0f+K z7n?bT*9bZoym`>U;AMpl2Jbg?Fx*NskVi)qpG|Ur@>rMdU9nF6n#jF_5zX#>|_#Z&oTy6m6+SVq} zuRu40_JGXupd&$F06iIWBj_~H*FaAPot^=C&xIJa1Iln70Qx23H3;-yphG~v2F3cF@o&%|=y#x4Z!^9HZ3B%$ zj^k@?2vOr}+OiEU!LU8cky!<8*#`Hyuw~0JxP6K?H4bMhkz;TiPFuEd4QyV}HE+=cu28;^=XJNyMT+@^)AJlOPXZn+5WY@;? zx4+E1Osqvpu+&G^_P)Uii;|#;2<1EPwecK z3=T3cUgDBO5yE7>7dRgrG?(@k+~Al#6ThF}XPd)HpTHNs)wn>_HkAzk=54xNs8ow6 zYi&~WlWksK&=s10ChHvRXS1$>o&!1%v=a0%&=$}mL2E!KgVur8fGz-C47w1s5%fIJ zi$E8Ft^{oY<*=+7lyRgU*2#AGuj(Xi*#^U>cvonfDk}`DY3Q!Xin6h+q=aX?b_tn- zl?8K;bLw;1CzX=Yfox{b2uSTtF2}gumn_H9gilt|F!Gd@#MPY}09x7WN#v`sr@G^^ zQ5dEt_VrqJDmE1(i+i#JP2Sf!xno)n+vD(#X`QymejU?(us!yA65%xV9H^A$KFLzI zr>77ujXc2`p;k|rsANg_K<28olkzOA7q$-LznsLkzP$E12-P0kUZ75CqAcd5o@N!; zeIgvNUYNU0?ni<)uJK{W9P!%n{4Y2=3+d(HoM_}b3h8L*WeEF&KAjJXGIEI|3h4z) zYARbBD|K=GZ!Gq4vtbc*w&I7)hIK6s&2_bgwGgvidq~2tu<-VS{VC1A8-e) z^dZm~=)<71K_3BS2fiMZ1^!7;uDhclir)(Q6eyeSr$O%meH@f8Qjsn32S6VM<-*Md zP`>or2>Kc5c2Lf6p9A$HOs{~lQGOPbP4X5{zOs1+bU5g%q`+SdyDI#&WgEAod3R`= zD*TMAX|9J|6@F!7;s2TNe4*Y(Xk4bzA1i|eSQ*U4%3#J+mLj=7g>RFuVTvWMxfwFa zYgkIwmiJ#9u|PBl)*e7X9VyX^$q z^&bMvHj3eP56ZyexUAkLL_Zm5Cd53=e;dh1>pP$vN52b7-~I~9;;<8R5a@fLM}WQ$ zIt27@phtmz0LnQ0UDKPPUu6Srstr=SD}Yiw^Zvge-pU8pGjq|!;9i!o&&E=3Mv|(- zz_BryC{G%QE!J_cVwB*ey>PQaS z+*Q5cF|aXG8S-M7-ED^4U!*2wC2(c4njt5ozrd5b<8rnM&jY~@;~D&Hg~I%bHkbYF zg(3i$xA_kpSCvhQelo(Gcvfisr^rl(<15fZKz%*&f*8~f+5(yZx&|~8lvB-Kpg#lc z4a%@*gR)TE3cac@(54E5;;}F&9xMjKU>Xi^RGm~dmhImNFWn)ff>_|bhGT?S>a9>J zGB23e9SBd}h&_KB!|fYd$FBbOPDn*M`cP?GU!FQ>sS2)V-@Iq;>VJPi?r?7SZJ7~V zpG)pkhe&Id2KCZ9R{#44%H&3qGlqtfm$2AvRuU@)t^W6?c*JFPHJhTzD>iW*DV$t$ z33sGyj;8!kS&5kj2p*E<*hc4%bOwgunXOoc+>9|;Z0zctWrQu)L|4DD1w5LK_*Gav ziu4<{oeyf(D@f0OUd={-G$pM2s>{%g5O0CUhaCzE`oo1I`Z6DOtuJh?uauihrAJ{y zvjIQTFpMlytg)<D2SG=HvOyUNIuZ0((33%r11$v|2Fm_sIOrVE zk)Vq}M}e{|js@iiWE|+lpyNR=1)U7a710Tx*Mm+3y$!So^d9YgFX#z)W?B-@GK*9F zy3Ep+ZLCl8p3=5#LluWuD#&)zr1LG^!VYX;>G_|5-+J)WD49 zeb!~Z=EgScj;vFo24-@VO+CZuZaAhR5eb12ji_y|t7%QhiGp-3iTb{wE=7Hov=^HUt8`h6RFX>y#AHrXIl9pfv5}>@{jRsL zAV3t2S@;BF*ki$wg5S4*9>ILExKByfSWu_m$41=ry_YQ(3q-P)5pczV-H;WFiO2lo zLM27`ks_nID#YCu3yx^~J{DXCX;6N~9hTHMEhQL7isguunPQVq>wCQ=71mOMarh;8 zAKOX#_3XH8pCxsgmQp(Hxx=o=ir4GMK7GF>wNOh5#^D!xEPvXsn?HKwHcM)`mJ*C3 zUaWbRU%wl<^iP&lQcDTO;g`h7$6CsGT^IfR9!rV?dm0sMd%V~KS$;KT{%xQo#pabp zFb=;^MIdGRRWZ!pWJ$4^r4fuHUM!E6Uq`)r_IgX|1(8u@)>$^h7bzQroc~n(088o} zEu}(YFX8OE{Jt2I0_M#vQ;?-7%4ien=C>^@l={wY%modMuleti&#%(A5VGCDAV zarkv8xK^oq;-T7cmedhiN-&Px87NY!tr85-Ir)+m^pA{<|d= z)KbdT9xo0YtazO^cPu6cW~((zO9{r|*Wn^%mbw#9&bY~v;uxyce`Wdg<$L!P zTT)!@qY;e5uK>8JMWTDJ`n=(mR6tsNoMffpnb)3sp(Vwg(=>u{_%$3{tED~f=Jt>!HAPDa#^KlTB4w71 zxnEpyqb0>7nlyrO_%#AtRW_JldmesewIy}7mJ$rbjm4T{7y%hM;SE6-&b4WdIi~t` znnS6@b&G47E)aG2M~=M>=V;CE=hJh;k9Ms)qXe@80XFN-NUQGPsuh}%(Ci#* zjTR|0eZD;Fu=z@g=-=xQ3dWH>V?-*z|M(63%Nu7{QhY;8BN#_sj0M-q_aXhGaZBob zEhQL-U*kl|tUJZ`{pvTC)E8PxFb==QJN$a8*TpAUQW*?1j9?soO#s*GFFvoo?h#As zU@avWhhLoRS@9bGZrP!h)X`c>Fb=ox=~4?$2G@$|hhu&?SxFK7unv!495F2xDSOGZq_$`&!8lSiC{kvP`+USJ|FWcB z*HVIU_%&6e%p7c5wr`>(^`Vv$jKi-IhhNM=OA7Bt#R$gXS4gDH96bN#w?DC@GIg>F z#?eNFMQWw4kq=(;&qZBxXPRKvBh$>>38zOp{WL4wC3mKal$m1n*FATOC3U2h5{x4j z5s_kw(R};lxK}KxiCRi9j#xy2_4_^*8MJ^e|2)w(7Bd9Ha%jdPnvO+Gv!Y#Maf(Qp zu{eIpb1N+=yk8R|7)LB(B4w7by4-i4w4~10Qi5^hd#S^(GftoTf+e+9O9{r|*G!Qz z%UI*0>!X&`ue6k49DbEK{7Qb9>|sf*(^7(Q_*I^kg2i}v%jti!q@LGOf^p=|sUpQw znk>BMt-lo+h-`4Q0J8*BVauIU)47ASe=(8e{ zJN(*q=8(RY)DkTv7>8eTMat}(?)-DY7OyL`lwcfwo#F7Sa?Fi4T7KQ5r3B;f>r9a{ zOWnxfrygWUZP!wQarkwX!><$HxZxp7>O(Ch7>8f;L@I#)EHzi3_|R3BR1ZD%6^x_Q zoh?#pQR>*Zm3;kJUDr}~j$i@+=)!_aymc^)BedqTyOg?0kupodw5x)LSW?5ZlwcgO zs1hlT;b~6%OX5*W>Le{y1s9C;Z0mK^|T1qeuzZN?DV()25J*A}tsqaNoDp@T){YEu^0|k85=$E{Bd1lu|zOC@!yQa;&dzy)tVP~iAAGGnXzCQ zv!ssEQi5^BqDiFeWz3SAqNN1m$oKOdeiirM^r|H_TT2PX;a9W6uOnApJ<^hD&{BeN z_|@X@tKe@LKUh*1Ybn7v{Av{`vpoNP{*C8YQrBrI!8rVCbNKbr_1k`CN!_cZ1mo~) zsl%^m@9RFXq&8|P!8rU{=J1Pk$C7$OO9{r|*K(0E>&}Y8Py1O?Si}`07)PnQK%}^D zECAbqzxqd2*HU+(V7TwsY&S1RmpZwq0PYubDRmc#lv(O7-8pumCDkVjjxd68#9{@w zn5T%VVN~xp;ZjR#u$B^xQ5c)a$+fWy{RU%^DV&M0ap$7NnFJ2^IHoyc!H^5f(;U<^ zyui2XnLrMAUZyccnuEQxcyZ|9aNf>+pB9FyxkJ?AQ1ypC8)pplJmug}&o3Mt z>WMoz)Wh}4v}Wu=md|ro9Bfp^x`iDxky0ykYWSIA6UT$IAkXg1Z7739u zV{!W2{7)^ZJG7Kw9I;pxw3J|&Ut^@O0=F7J=PGeKIDQ{j}#L>fIZTFoJQU*yZ3l-&a~vg<485(k8GL&@dLx6ib2Q z_if>S{PG&UdaP@_t`N*}MAwX0Djlz4?N>_0%Qj-{5UC*k(~PUkMlI8{Uqz z=2=>EhtjOxH&syARU%bRtHUgUM4^<$Lh}`IVcU{r4NGdRXXRX^84HZUntI$bSZHG? z#6&m3#!!d}ZiJ1Y5aZnl8$%(+xe+#oLa2x!oQ{a#SvgPA3R=vF*cb|7#w?AnF%-g# zSsGzuD1;fRG{VME2o+4YJA#R4^V>~@<0p=vV1|11C{XAbCgCE5gWwDPzV(f z8^Xp=2o(_CAEv{noH{IYR*#|Q>qs&YOJZ` zXErKZ*kt?;}wQ+E)5FnMCwR7n2y7a zI+jkJmU1vFE2E367uHS1E;vIRTt{QqxJf~gwMq+?{PhZvu`paYb1UrW@|^2Wam2u++^R7gQa{IuGq+* zYG1r0?l25r{rzaOOd!9!%KrL~E*!oG4#8z&dN#r#Z*e~KNhu^k84lP-0du0parj)E zKdRWi9goO-{LTdCTsO``-&$anQ?`>2nLY7YVPq8sO-?;~LLxp5x)`VF9F%Sb$I zLwUM9i1Zud!g-}1&+)u}C=O0yxKFdc^c#Z6j9`Rd_LqJ!VCK1T9`U^pm`mL_S9}ZM z*B!uYcjG+teF)6wZk$WsLC}}aJytg3m44i2R_MZcrC$cq8N0709HA8MFa6E|=3I^2 zU;3>D<_0&;Bfjf^+2qD~#CIn!U%GJ~`VI(SF$h1J?!w39JuyIpWxUew1vt+QSQy&8 z(k~0?chq2P%Ne4u`%Aw$z*K8ocj06Gy%?CQ+&GW;-Ve;S6JD5P$OT=n-!IF`6@Ug;M?`uzah)T5NP{iWZzz%13c{e|yZVD50^JmR|v zm>1nRkM#S9n4?wr(*AnrI~LYTV|l(yV^j#e^Wz4j z^A_Od4OOTfAYS>wWzi;Jh99SJ`^%3CV5&4Ooi48Mu{^H==1MotBfj?mv)+w!>0|r% zCt&{R#(C(=8iwmU@T2K2d`!PF8Y4jb^J)+1-AotGEB$y@ayf8ohAVCROTYVoS+8;3 zg^%laf6^GG(K~!M!SP+-mh06>`s)?G6A`{!fO%(x(zd_wWnfU0&w&w4cj06Hj?fqZ z;-6Rg4S~Pd)n-(UQmF3AUlDMvz}zRV8us6x?*L|}#&s7y=I;+0;|QN^fsg!h{0`+? z0Gr{s4nxS1q42ceoLEIHI`xDh_*YU|F~rF%i-l$eOT)8=1elzk;kO*WDTc3r+Hfjn zTEn8cmU&GrW9D(td;Em?$G0@sh+R&_%+jY~&aLHFNNQR~G|oR4C(!y87*)7FTn@J% zv$Zc&9kaExp{BX9rEx)PVCbx417%IE4T~Et#8v8n5*(v}FU`vT12g$`xn2eLB7ZWB z8R1#8DyIfRl~dcwU3HJ=3E6ankXIEB4 zX3fDicjeH-5Qmak!I`I2hQhNea0N<9RQBoG3R$eg+I6D|QCr93M3}g=RJOD>x7D=blk8aqZy-LRpl(TPb7Rv5 zm4tCNlMlz=(Z>i9rm|vc46)2A$OQ-MYSoMC_{n!u(Ezw?GX2pZ(SGE@iAg32AhGAM z;B&Llj=66h1>XlZb| zLL3Q13vv+AXG6l=ZmnLZGTfuUbgi=cOJXWuYc_*TpV{tZNwYYk5-s*@gaYLS&EbB^ zJe}?~MM|#Wyyi${;CN3okL#uC1x1dT|r0v`28r;y#8Mp=fD%=Im(M zOex8ep%l3ht%#WIHLF5Er)H59$`;du+RCOz+!JbRJLrEFROrS51x!kud~Gz2E*5`A zzVF)?>jpkv-)quA$Nl2n9S_vhW6CJ}GrsMZUHa7P*cg#SUqPwu>T z!>VIny6g{u*Yk3|!uNZGf71F(YYy3R{X1v8^i=eou`@8d_)Pd4zWjVgV<@_8aUb8` zPyV`R4W^m!INx{2&Tdd}-J`~S7=(RueB{?>@H z->DNZ`M&ErC#}8m*Y!`9CkCJVMakf6)%*N>-@eSYHx6Cf_|EZ{7IaRYc<-h1JwfQ- zbz#lv9jEpC>m$2zJ|5AwM=Z!Z?ZVwX4%mC@ zYwEzcoa5~N$SiVmLBqlk^&CG)gI&EiAg5~sLzfp#ICkFR^hjW7LrYurqCiV)TWv#Q zpa_R+=V27FsI9hcUQ26jZQX(&sida46-ruuq?VTIML$x*QmjD!_+Tt+YQ|dqf)Nc% z7VZDQGEhGxQ-Hgi3Nad*;*$VP_3s%T@ibENX5ItecI2KM ztJ#R}2GD!>jn5U})84p)<)AnDm8W`WuZkusdhUzVY>RZ{ZX&ZOnvC__H+f0Xid*z$ zqjK@NcrVwEB8Fa1W?+WdjEpcTSOhb2dH;S@xPM#;c!5Y$_DO1YAC|fRg zT%7hxC(3j*jdFL&U}qGNgAd8X$1nOA*|;FCCoYboG5tWVuKhs&rEOeQQhvaaM$+!( zheG-$=NOZ5`P?yEvWx&Oq#K9}>GE+AUB)FS#i@5tV~Qd*t63}~DYF0Q1Bm@+LGG9@A%+ynB93-@^VOgm=0G1)$A)xw(JUZM0!M%XJtiFpT;`o z=azOX%g6WX`iGLag|@4Lf+)THqp7m`XlerLLk6y3A9O69n{Et#{WOCR!*ek8O04E( zIKSHd>Z(bx)Ye$)d0g{SI&5?4u;;Ds*i$V&nuZI9Hp-<#kz{Zms%r0jZM$ReCTn^} z?g7!%tKs%%S51$mHpEhYDjoJ(B=3Pu(T?2B(T?IDXpaqhH`bA{RRwXu)iY8V1=JVC zMMhD4clDHH$iFX|D&9xsZSO@8pySabyv`KIje3z`+nwRzwad2Pw0$Ze3E}H?@&%%2 zpmZyKTdIPSR~F@6@iA@|=1su?xnACNmprRB+K%*1^NB4*`@QmtZ&Fx-ZU(j0;KkMF z)m3^_;3CGs)35>;!=-BlmMgDV8%;w$S%XbO$I0z(~9} zMoh+=px1%E1-bzgwODQ{`wJ*HIlc>e6zE?;xz+MR&~ng!fL4Q2@4cY^1Z9m6;HPRl zZK}pA9&5bfF>M%T(~zrbyt1*zA1%DW_)mi|pBUEO0DgYim#b{7@neKX6m^>>0E=5M z!-yJxWVUf6u3tY0pOeh}Aj8Pol4)e%Ds~#vFV^w^etvl?r)>PM{DLKoq&-k7{|WN{w*t3b9Wpr zlg_|bKv3r&giq|{@XgS#x} zM*UP&RBkTztYFwkg(e(598f$4(wtVoEZX$~LPa7}Y3h6sO z$2fk6&p2XB4}7a66W=Q7iBGHJKDi+*^Z4>yBy}TmB|P@k(4S?q<_|N=NSY)XS%&Lfcin zz;%1lIei>VY{Jly^LL!4pcXW#hp3RO>vLg#ONmzwhw5l=I5bU_Jkc*xW$V>F|d=b4dbR@`P%S6 z(7E6b0<8vxynLi;Fz8Y|9}RjT=rN!_1sw|dYf$R@Bj_+t7WM|6M6+rQr z77U|l$W_H&*%-|V;SJW1ahkFSTNq_yv9H3b*N>jUHxT`kxSzA9`+nLXb&~bWxXL)~I5jbb-^eWuodTD>D9`g#TQooENk3;BU zMiCY3m|h#g_$l=wRiYbOgdPNX`64Lo#@RM9^Ic5n46Yv-KJzs!-%IHhpD*5^N%9aMM-N`~Y`rQNaS-`vv zOLrBV?4|n<@anZY%jMrC8AP`Zhte$#mAUIs_##;x!} zp}QwOMMz`n=aZ#X*$x6v>9-?k_tLMBzM(nB&=0bVBX{&R4#(#Y`{MJ5z47_OjN90E zumYkwuvc-^LXOW=4P<=`rgoR6cE(cwWCc7rQgb?Lf~th6iZ|+|7Ur!v7DXj-*%}1K z#|oJ$TfwfZs{Ps48cc5T)-X8|-{5BEZ(&h7q{@a;SH;PpDuiVetE<%2+QOl%u&kz` z)USvMp}OW>!m_Y!`U?Cvf|G_9<|XbChE(0urL6jiUB2XHad1?DGr`IYwd_(Cm5*vD`FiCsk*|4Cosh8H}3*gy| zW*E~EP>v(4yJolH>10=na|2Kr;PV>&?phqKhQd8!>g;6%P zAlKsOH;7`{FpZbqE8(cSf87$9y6LN>QQ6qiDc#g*B5C*1t&qOL9HS7e&=F{b4n!-| z7p+ilw0ycHil9wl7amIDi}5k6{h+6=z?bRAJ}ck4;`Q_Vh!JD@8Gg^;=bl9!2Oiyz z!mrzU&|JObJbASx9d86sZ^Mqa98T_zm-WW8Ecx9zy6x>b2c(5LD zaK$oD^CHR-)6DIT|_BEocbz zI#Bw<_UaD&RJo!p+qgN+yG7fwLDAmIfAx<@Rj!nc66hFZxD!87ZkrES0ebbr0=IuyoZzOq{Ony6h!VQj@tp`L>dE0`z zARZD)z0?WLRV-}r3-XQD5s5#VCaC^ZOWp*?rQ@uJdHGOFp)nH5kNMdu3J(7L-@r~r)S*= z&0mYZ5)-UHg;LvtowM?Ti7l8ZZ$)gUVIKVqX3PtVRy@UdML?Hs#GbPb_>S~ojoLg3 zA!I6M7;*gXEw&8&{|rBtl_{>Prnwi6?x?`V?JQ8rsG}8K_W^OzG1LTgpp!p6}QAn9-ID<0gDd;wY5sgKM*lKKRB2%Qj>8 zKk+hao-%P7`}q>~HGZF@7;NKTcpL2)lfr(sgfa8`Sb1opu`ZalI010&Crwyqt&63G zo%1q2I4t!Te70~jf^i%U#|#!y`TURHic`P9=ZZ}!j)-Xl~%?`kQ*IAXyy04sNHzc>F_ON#S58o@YHEDzlOhrMrskE%G^Kg$LP;j#%Jf}kw0 zY822wxFiN8OE$2Ji69q6MFRv7e&|0<1SG6Ld^%4XDFI6hu zsqOIGiT1c@7N`lJ+8Q)&Bb)n z2#q5yX#>6x{MZr_oj(4x%{5eWsdkdu>No`2ag7U)S!;7yYK4Wy5m#s7>WW{QH-FQ& z!RA_^;}RN2?Q{XH-)F5?|LD{DkDJ#H!}N1{m8_jE$=XTikh>T`SM3}nTvqLT|FgxP z*<813E}?PcqMLA8eaDyk%vzi4NzElRj@mie5!WL>&3wV;dRKD^jU%q^!X>$bEq={` zuWYUiJdSCE#t|3$y+Qo30lAJ z*TRF%Sy_k6n%54)genT;(&{@sleIHbhuqU}*UquRW!27stasYmTvX9VBQ%a&90yms z@63B>_ZFM$dd(#?juPuFTvl8ipMUdwo9maFOK2Q%1%=D1ok6GHaJS9%g60w$M_hdz zab0uaH9ni`faVe!M_he{i>;34PoF%v+~#V_t_veHj@s!5SHF*IIy5r}k0@?lJJR=k zn4uWMf?^RAVr+FX|URH1Ri#WxST439tj^EYg+Ox;z4#u3*5;j;Sam{rfFl%Y)7;V(3f zmM~DbxcR9AN#@Ho7tUc5BQ%b<_-1FT_P*i0O~1Ffp3_`H zQh;Ui8bIs(HDRE`%DVESUYGadrGT^6E`-`#Ti0Vkdlkjlew^zik^;K zKs8v3l-o$*vU0J0Vdz+!>n)ugp>gD*Sh%bfwc>XlonUh{X)d7=MNVwTG|UAQIi<)< zh2i4&ji;x>P<^Q9=0L3^pdjS!tJFcH^ObCehPTL@&R6kz$EvjxczSwmkVd> zr>B(#Pftr3hNq|E^z_o{_wq}(A4O+jSST%lN=yp`DnU>{l4i?GQmIZ_0u@49Z=J1l z{&aWmJJ8w6mqa!5R9Q;nsS-1|CC)USb~c*Dn34szU)rzB$<~#g!fImaDO8$3s`mj^b-K4CgHA^thZ3nwX~JtAof(r>t?2pYx21L36pAP8u93l;QLL zdeGeJrgMeIC;k(ldBaWT5#HyZY296gpDuljx1Xj_lsX?SJrKV|xtt2ROup>Ha2DiM zep5i#3pCYS0)T0${B8!#U79Xk`dEHDK=X>5&Lh8vNu#Gk>B3`Hj|0sxH=Rd#lRz`g zP3Ni)rf;RDfmMu`-2ChCxfXPDxHtiWV)87%!*E{$n%P{AfN81xt_97HG+ny zv&&8Ak>3wMbI48S%5Mnhims*f?E=k9nvUUljW1o{en``(5WUN<9G-1L7z1(9AQ_(NI|%m+K~sJ_ zsah_-8qloLbm`K^@>{QIBtZOll^<7l?*!e$nl@efHi2#%XfEf15KOZCT;tVw@LLa> zBPn!V^|2RpK`awx;#owK49}xI=YeK~rfVs`=W7}jqRwy1I~U!@SYlRSKm8CF3TaH7ObA@yfe&T&$vW%J@>Kp`exl#oAx_ ziKKePq;caaM#aY9F`+z%DbKUURcKuX;Zcxyr;dz!Ff^U6d?$_@T>*-T<0j%;$+tQ( z{;PCk{Ff`j_*Ur!bX)v~D!ric2aZB64HwjtF%+*d(CX4mP07E9iVJGf$WKXOW%Ybf zane%C|5wyve5)7ZAJU8Q@{Sv44S4MbJAb$Sl$GVDOe?}x9?Yw=ea-b^9Ec#L@ul66M7emdc|BuyTP^=_()v_UPHgT&a_cNNmy|Ue^ zWqEX1sdo_bqp|EI9w20B$Y9`5(&W(!zO=qm-S*zX~G2owZzC!#`}xwaxrw zSyY@)NmF>;8u(pPEC3ccB0Z18Nb8*v@ZI1iGlyHi+2FC3&C7^`K zfX#q7)$X9A@U(=^yoX^ZNf55;3 z_l`TT^&S6SkQnB;gNe504;WtH-ZO_-&WSM@W-57-c1#DGSR8kZ=?WRnMMDx}vUTd1 zt~H9vv_o`lOik3*Axac5#VRQ(ZF7a^K4)N5Q`@9V&DWI#e&WOP6c9dAr7%RV>)m( z5OKwC0nP^A3Y-Ik@QSez_&V@XAU4@j{xyzGvJ^~+`;osTz%D@E4?z6waH$Qmv}GCb zq+6Y~Wf|{-pJihiQmPHJ%9e@yfVlP1BngcfK$}L{xctjiQ@@-Q#IP-+{GB{pJBPqZ z*EU91Y{2b+4Y;kb8JEV21G7~f2YajvgG;U|4p@?uw0p&&D1F&}C^1o+dpWk5tJnq9 z(8hi1wMQTc@!OhZW#+0I;gSDh*evdqShWRq*n){wk1AUzY(_hT6UD`J4eu<*R(~8U z_%Up(UjsOTSpOny5!wQg-{gN9PK=N4grK$>tr8DxhmC@$#ddGAhA3>Q_hEcuD~+1% zOzEkq10xGi4O}v=V8pP-kJRp;sAbA!u*mHhp-tAVRL*q5k{WFy~5@ZWY-J_1NVN8Tqa^eN)zD% zzUj*MWPp1rvqtZvp-UxE{Czcsr28&z-HdK}Lno za4kyOy~0$ zm0zfy)szIUaG6IwP&19L(BTt+-k>ZOi@fy z#+UUl0(Cb?Ncy$vbam5|y)O=%S$i{n3u|x3@5&_!!TpyonCebe>)0_S*Vunf{K}wF zW51p8o1M%KEGi5C!M2plpt(a$x0p|+hV_(TJcD1=%3g$x?c8o<3vlO_IpsIm3{n9v z$bm%}?AocSSwKx7OXfilvox|?%d;7#Z)75Sw>yP_@v)U14Y%#uy$@OqTNieYiuR7< zfyd#VDs1??gIv4FnC1e*xIY;<5lETRsX$Cmzu;^EW6pzeBh5;!>GZuIhkm+G7zW|qN<+Q0*uH4wl zl^ZMu^K2Qqs#dOSY~|C%&38sy;|x4=JK?$BZb(~^*|SEURcbW(ZM2~y1BxaxcN7PW z9mRcc9qM3v7(kZV-6a!uwvpu6Ep)v6j-4&lTgS^$7EnO@Lb?Az$rjBj`M(hf#(BH z08RyRD7p|h0tlrCapqwfkd-wXm#QqgnUopniF3cD&P+ElYvZmV&x+^mKf&dh%iqi>{PR309FRw>BJ3mR$CA!=FK zY@>;&MamY8+wRheXmdl@cOA+)KctK8Uhl^ZNva!HyMu&Ji2Y-}aV#m#EE8Mym*ln3T+MW<;l56s1# z)*vb${_(G`5zWVWLH`-k13XfX2b>@pL z(vIunpH!FGT%32(2#q5y4u*=0{wMw7m6vR;S~|f9jo5CIU;YFQ=b`TH;pX@8Z5dT& z4FB`U6Pwo;E8OqHz@DrfTe|g5_|bfwgz(@*!FHQ#vtkm3dQO>Y&NJ-#`tYw$J!f-0 zuepTAQC|V!l61mW^Z5_HYjb^|xrD}1hJ0*6@|nN5dfc%IT8OO{^_Aul8b@3l%Ix~` zWq-fM=7RD*F+$^ri!D^;iv(SF6+C2fVZI|qXdDtdoD%qbe6u6TDZ`$|i=x=nPAm>W zIH7?whw*Fm9b3A!M2Gx!62i}P+rQc7I!AMY5*kN| zaV}|>*nyLZ&$GF%)m%d3C^4xQUy!`G*4A#t*LbUT?$%tY?ovmI9;EkKE#aDeKmM7` zwL^0WjUz5jTygza1DEjL&bqL2VwcI%K&RJlmmValhU-*=wo`r#|TKw&VB)F<`HLbF%X0F0B8A-|(T zJ_#W^r2+d3msLI=?wvc<=K5T735}zC1_)PbTeZ24WP-L#>6Z|Y{wirN*jmPm2BUNUp;Wl*b0P0jf9==u_n zOrzV~N~GJ}N~POf(dUQU?uy>+Y6KTCM5r|R?#3wimeIKBN;yhB^y^Y&AGUa{#k zdw4Zllhdhg?ykdV=HXs%(E&7b*8FbwG;ilRlyts2ur%Jy-$m2BK7-qgQyGq)7lWqCP3MyB;D~q~XdZLZd4%@{X#VJ? zbA`v^ZH+YpH$%h`gsHpym24)HFJIp5?a@ zo|9d4Ugh@%=zN$=e8~v~Oa`uW?eBO@9|my>0h6x$Sij>mjS%9;tNgygi(w_`rVmzB zob!97Zx;&Iho|w=Llqt0In$+Y;4rMr$x&|K%HbG2vAjqU}_ zt8O}v@IC>JZ#Yxea{78}8b#?{em_9FIu&$Jasde@UHjt<`W4Wee43(bseUJb<|0j( zuKZZP%R#f&P3Mu{Ux4NjH=V2eSRb!}X0MyhBfK_6Sc$jy#zFuX}Waf$NBL(O(Ox~N7CmZn{~6B?wiYIU503izJYAk9B6s`Cq=VlD@`>X z{k@HjIUTqnB1R7UTsXbDW(jufEn318bS-(PEG6+Y3Wp4;2X?Ah3T_zy^DeS1dnzsVWJ|CIa{&%5RO{fxPC7(+$% zvcM}{GWD2F;D$I&7E26)bIbG z^NZ7na`CL|*2vyW9G1Og?q$<RmgG9AVrZu4vUf5xfEm3=432`Sj{p7&J3;+NF41 zzG%rj9M!3P8QdB0t-={2GjP_4;%TuA|D^(Bl<8vk#JSP=gQZ{A;LdeIa`ObcPM2q{ znjfRwa!D{-X^PM(XvVmLOq4pho;|aL8d3F05JQ{SG^-0~UC=f^f| zJ7(7pPYA|eKk(9D&cPQaE_Y`83UbPWO@oizdi|Bz{+h*GQJ6h3zw?q&J44)?pWQq| z+`VPguI60vTN$-)Wz?#JEuX&qbq5*$N6Dzkn}r-mp6+yKq4+-*Vq1rhX0nh^rV^9G48l=?LHrQH7>2 zaea>KV_a|J+KOuxE*~$P=IZ+b*AZL?alM7B5m%h2yuKM-bznIb?x6WmP4+KvLr*uZu$~a zuu&W`dc}30R^#Z+O>e$NckK4e-QSV7N37du{iiiOadu`XW&|1V-)^M4RhhpcI znqP(+R`_D(hcWY0?1K+%KCb?arR_&GWE7pwa$echP7rHHrKJ9i>SLk}YX*!*6_uIW ziUXTp-3w16;{RLJzh92f-QlZk%3gV2ta4`r@q~CtZeC>d#tgCq9`OU>RFwuvwi*{7+GoRmr#2I_uDmt>i5{VA#}5a?KHe|Or)tPpd^2|aX&Zw zD<%+G3pZTRM&*WwUxXi_b7?`hC9};J!sel}hO+)Sdp=N!!LJ#)x!8OmV(!@UR{f{Z z%H1nZ9^0_yv>OpctYO^^j53lq21)dVaZuN4BxtK73QhCM58&K}hfA`Ya5SqgQnY*J zyJX$$56pGfrv2x&Agc%u_Q{RY& zeI(%B7;p@_udHbQ@|Vg?)$+>B+e2$5K-D6n=FK50WR03@q#s4|pOe-SUA3JZZ5zI7 z7=3VM@E{g^YNo9i{ae}Q;K|-s+)xOz4)Q0U`v?zy%HXmZl~W(&R8<*SAQ5ex&Y3y4 zgfeaqgCt}br{%E2kMsFtduSuWaHlN9U@!-ak?ztIiCvX*T7m#!0r-2)Q2s3^s@CD!|;BMe!~I z@F4KFz)yg`1GYll{~p*5_y=HT;9J11z_)?N0AB-g8}Wz081Nu)8t`La9Edr4{A%DQ zz}tYI0)Gbl40tc_2=GxL>3;(x|L=jwbG$XmHvmDliMk&rWQ+ zYTF}iS@LXBZU{kqvkZpEIpN}E^I1JSR`H|jaQtCvPZuRqu-FtC^fV%7z#uL^#)a*Wnt;H>l+37k z9)wZm;CZ$f0#}!Ik0zD|YajmtMG30Hvc$9_Wr;Zl%My$ChRwaD=Eo899iDPue=P{Y zwMTjc8o1Vsp{oY6@}nUz@jOmgtZS^kSlvN>d`f0ubK58mriR40@AM{6*AzCVAKn6e z_3rw{nq#(*HN5q`%-W|iBkkX+{j$gM)%zz5ZrndDaW&H$Df(n(2~Jj}2u^%ywowy` znr$B8g9M4f)BSR$(`*BQk23QoBns~+$@Xnw9rb_eF+yPTuJE4sVu=+7q{cE!6SK0z zi3MHn^XY@=@r=<@Vh2ESm2f6uNYo`Mfl@w9%qvr4EHg>eBjx@;lOi%;1_{&Jc#5Zup;0hxKmo=JHRk-6)+0C8i>hk zd>xR|7C#1-0oMa@x?vnct(*vk?rcoJJ-ai$bjitzvw#>vjoCm9nUaoYfrYrokZD{5 zd>Ob9_&Tr}_(vdjW3%BwXg%H@d0htN@cbR%vA`>VeSmS`@jwjC@sog80U=4k$3+}z zG3tRFzPNKp4PUfn8JFNUPuv!2Tb9ge6x{*1DLPmv?2t5rU{gbyvT;b`;|X$6Lj%Up z_cDw@kc%4#dAQz?TRR%^aa|z0#uLrj&Om9_9*A;6oENRsXQ}2!igw5`VmQaF+}F_q>H^ zQ@_{3MZGqy935*Iut`oN^S^#x$m*(p5?>XG6b?3wOv%wFl)jiC5m*AeAISXheiHB|;HAKy06FaPJ`P+Dyb6f< zO8i#ft-w2hw*emm-UDR0ZUlY+geZ3WPe9VM%+sx#4+WxSPidr#Xi zKY(FgEW@vps^cgd3Y^+4*l}jJH)caC!z6T)p4&5U>?aPop9xJ0NHT>Cp)o<^sFbWB z;e7NSf>VoYA)1AN%kWE8Ky9CD>1*Qiwk6x@eL zECRGz=mO-*E!ejaZuI{lu7|Smql~3u8=JnU1zQ?uuI1@Olvg?dE)X8V#ZG7$#>ZCF z0XSbfzKq&q8r}f*0lo<=1pWcYN5UZ>XVUKi*4r{1#L=FNx7}ozN%F)ZI+?GY8A@HRuL69-!W~CV<3FTL-Vq=03OeJ#f+&e zgz3|Eu3mt$_F+~K2EIALsQGg?2~3{$avYq71&cu44@k2j&j{2fU^7e6G7@Y~$p+&K z2X~hCf*;;t>q7M6LIc}P^_lrkhYK-kA%c}XqYb6Oog_2lRkSf9T%^2~?+b%bnn`J1 zxc1Qy8;a<>Sr^&`+m6y~V}D?9<31c@hEY;E##dw`%{Pa3gCL64i~9s04c!Ig!p4n) zn`Fc+OFSA{jr&0TJt)DLSr*ETn3KCl%oWHCRx}Rt0fJr;!D+ZWF0-MG=X6Ixd1h%a z!sBrhKC?8mGZGq)K%gZl!z|5Bgfq?30f}&j{Kjx$U8oUBCd-t-wV8-R_l9t76H0o- zlX%~KiaEiA?5U;feRFu`c63E4qsrysyXMZY`Qly%U)LC@d$b*p9w$4@+mjp-+!9AZy0wZY(BZ?NMLhg6lYg_)NdF`I zPD0g$A4AaOEiL+T#i=TK^VhEEPnYNsv!p@dkoZgce;GFaw1u&U%@_9I=GW>mxwoWf zz#V~WXTrz-A(HD0G~~gaoR2SO!9r`1gc7L#1p}yU!W{fl*f^)|n>q(a{xez8qftvJ z{HW6Hzr-|x^+T?eeVj?*Fs9xYBn|m*?C*7EW!W8=LOd1oU%M8* zfz4BWIrVP@R^y?8Hc90X_(6BSJ=6$qNgo#O7DtNyrrSuweAd-QdVrPTyW5EQY^49+ zkcmgwO3KtxvU}cPb2$Q8^?tiCkqH;Ai^J1c(Gg8mYz@6y?Qdni9!1Zb5`Xlh?&PiR z6059RvmI97)VjrHq;B!-L|b_BISQfn$#{hgKTbR9CNphMT7uW)f2JqZr}m_ite$k@ z-`kV^g4b8CQbJGC-RMuQo)pERZFE%8fDM6bG4)S&r$Ml%>rVHoLO^%=3^tGMv;e92 z+U`_}G0USr4br^-RDYWDZ`PmeLjK;5(WzYh>4X;hlk^vKsy?dYR6d2y^|NTq-{9z3 ze?{|@eq?UjdL*Ov-9VtO4wVz}A8e^p@nAWx=JJnpsw}Hh`FG1;5#t*~T^x}cvlCs% z?C*f(*+4zDdm=GmyrP6_zbX!_*^JK|`*?t$>QwRoTiasSqLj)1e%BiC_jautLFiRh ze^=LnEHj_c*24-f_i20A{U|s-8UhWU!{*Vu0!YZ$_O3DV`smTWeuJph6U_4|_xC-o zX8-&4ubcig{p&}l3rGK|F3^3ezf5Y}53K6>UTp=Bs{NVh4>dWCzR()q1o0@sG8rax z)>BbUT78_fa^mv)@t>`8XPitPfFZ0u;CM@oa6<3*SG8jDSG10_ik2iTy%pPTy z8A(j;Zu%mL6}=LrK{K3@C=Fo(nkdbMTDL^$fZEc$CNAUYX)L~)@NvY?Fn0;+X)nH- z?8ZGm*Q^%2J+wjmH-=s#;_C@u8{S6sT0n0!*^}S|6$F?YDq9t7v&8MYu;J;B_lk9} zVLk=hpOSPu_D^x#2qISO~K-#Qn=nY*5>)lFHLlB!<^$UTF9ps6t^v*m-UnO^+yq<#{1jLP&7t7F9tpg|4j zSWJV;k}#m4FKO!lTLmsZzrsl$1Bmeo_dNI@+`JA(-r*c0_r1QPzy+eTI|$%?EV%nbpt+HKgj(3pws3)mEJ17lx) zMMM_d{F7_4nS3SHHT?e=*8y&5NgUAq+JyjeQ7NtN*S!`bhPYtNf&59Ql*Y>hNRBR00= z;-pKe1UPB^K5k5*?ac?*J*0M4rs}?EEi`K}j94L~*T9YDI0f)=>%L&xZT&MJtb3rl z&BfZK5gLc?3(Ob6)r-Hlruz%V*jyOL#R!c21_+Hr=5jMN)ooeP1`=%=DJgJ35_GCU4)A*oaUU3JHE2Hp3q!E z!+Z_0dJ1#ltU*5g{JxD01m@jk^)EEf*HQ5C`@X=hm9MVJe7&aQ>WX|h^{{mlE-PQ# z4!!fG&9zr^35_FPM++BIMYH$zs^vCUljaf{M?2(`+wbG+4s$s7)>hk_=c0$u>_YXa z@m=;C!Hwo<)fun@$(;*6QS5g3eAS})*rg;q*h;FogvODJp28(<2DZze_{}jk*D%c` zG>(=aYKkkWVY%aXiiV+$|TpV%jeEoRx z)jzel@Tw|CXdLju$SgWqwh7TZPTFPIC#3Bd!x1aqYk3v=?ly z2Q`<_IN~}{xKxWpUyfWq&*pkXa|w+jE@{chUXXqFCm+~cpJ^`D+EaVMNfH<9nj}{o zoVd;A!jwUb&^Y2cne@rHru=2iO*U7d<`No5zWNK7)eAa>A3J1oP0?IJ;~1j`2-ijU zWvh#p?#1wo=H+O01BK=}{OVwg0m)XkR67kot8+d3-odI$tmRE(JzoxX79{8>v%=FF;`XH?)6lFFJTbE}tC zR4!UHZ|*FI3rQ?@&rP$Iz9~lM-cTD#O-nOR$0pj)(Bb(*4T&M;&CEy*-Qk`Za;k@W zN0knsnX~41yQeJ3C+j-Z&8ps1H>*Zd-4xyMP^z1vOLftSNOf`+%CNzh^g(Ibj9K&Z zLqiLO4pt@PRD|K&jT{;_X!u~wGZ;MigHWHb1=BB{HEMd*ETb85UV$ba1mZz?M!MCj zWO1Y=u*xPafmKjx39M2}OQ1p+7D`K?LTG_Ng^>SsA+$iCLP(neU8m{%Jr*CVHcmZ( z6)A0biIMC-&Am=79F`YMF<+;ttzh_|L5iH3+PaFSwzZh#jnX5hm!`HM`gx{FFg49~ zJP+tT1QWta7hSQ3rnW}V-oTfe6yv3-?MZ}nE*@Sz^dy_lOfOAT_>g0?!_@zDPPbwB zq)4ZUssS`NX*woVH0XF}0(uBEJKc0r-HbsQWY>5fG#|U^T;XwE5kTVmGXpTmcs;_4 zfo8Is&Lg}kO`}58`AB)+rTd+@z6ZKte4&8h)7-24-h}&D(44^60~kJ1)0N*@pgCXD zCG+7*ALkoOL9^OT=aJt#K=VsCohv+6|8CH{=ce-ruNB&HC%&-2q)Q*e8=z@~5I^ZO zDHXfvzPTo)rHBUNrF{3M(Ee!e<3jQ5oVs+_kf{@9&7Xxqdg>)JXI54(xOmAwr%UN$ z#JLo&DqW1WIfXJG92+T_R1uq4HtyV{qYuh0=r}q&aZ=K;m2wC5CuW$Lf^9z4d5 zDjQdFCO)$`)LHz;YB^%Ui!o{D8P}*i$to3huVF|LJ7?xR4?dX<&BP=QA_LGdTD@e^e9YR!`)S*|a?z~WsovD>fq~js zTs?=nSQgBvoV#%LA_!h)=DfhzIZ+eY{|dA)ynklqY`2^-8@gChMIY*_sYc?ZX;hR? zE}K*_>Adl!wmaKViaV7U^+!l!Cx*+%hbK%3pNHj+%$&7!lB%A7W=Ab2qf$yKC0i_o zK8WvfJj0h%R14{YRyNhiHxmCraDrt?a&j;ulrn1(Rm1pZGvH zJh1c8qt2W$XVQ$7Q%0THr|6N~ZC%~`vB6K2J`nCx6dQciiNkxo)$yl&+vkM`K9c*> zzQcPy(fQhTcjc_?-udWlUGK_ytK+rp{-76C503n3di4JBgFYSk%%bw^e(}e{Bk#_c z|Iv)yhw$-~=HSSpC+=*V8`?MWSHYcEeCO=9M_zc(lHX6h>o+5*QHb)*=BfgWTu>mC z8B5H|h7uv{-?~4D#boFb3g$PJC*~c@{}4)h3YTHa_-_N(Qtt^=3>_(lx}kEY8!Bty z2O;bdJN+s^w01|RtYO-evWCT(WepvR;iPwrnVq1ZCQx@jT*PvVSXu?@6104tQGGIw z;=>j>E)7J@_GX*pDc4Qe$v7my{maZVr`A7R9Yr|RLu)_xRYRalA2`XSWjQI*#WFhD z!1ZwB3FOt-UtrxKo5uc=^<93`{@%8=t8HzUw8j#r#8-BJKu~{#6D}MP3e@$1t;`%f zpu8TUbX{>%-xN-a2$?Sg>fS-{lGnksAe~1yPv^e3;TJW}8DgFHR{JD2={06R!_7m* zUqFuzcgF?ck{v60`cUBH#zTSg!bc7T&TsrnAZOHTr1~?QcfmOZ=kq$U{NTNn-fz(6zB6g=B98Rpf^&IlBB#8?}POItHZk> z#rtqzjUVC#`<{hcnR(WbSi|^?*k`Xr8}P{vO%laX?tiVkA!4*DYdDH^DXohdi~*qM7J%*$|G3rR*p|PL3JPv^S2t3QW9C7&| zy-$>7gJ;xVQ+>*dUPX9^mnZf^f5tgO@}FjXW#Cxkt*xT9pBE=0-$if_MWSE9_Qmpd zDP6~{m$BL%sLvhKB1Q8GoGmo4<_*ZiP#qN{sG&H3g7(GSp^07xAv|t-oW@Q5Qz+WV z9ahn8XCnJ;ab*}2lD1i}u?1up_a@yoC*9sjy6sE49fFM?=`f(6C5FV-2{z8kGmIXv z^%YwPwmxE`a*m+b_}Np%#!vUk_F2+~-Qn5|`>VBWUefm6r0qV~R6e#PZFLxBl$!~g z3YkOR$GA9hxOePxA(HgB15-AS+3UKpV?PQCZ^KPv-t~j}Xs%#w5RUEJ+DQWkLLs9x5l+gdBw#M<*9gSmV zb}+h4YHxHNl4Z2LicfePBu%+>D0s+|eWN(Q^h(iWg82bA#7C3+M|t9XEvFYa&$MtJ zMzUW8QO_&K$(hnnbTlQ}uoweciKREtfG>`AZps$@b#k){Dg^g3wL9D3xzL1h6ys+G zc&A|qUA|4k#W_M^A|qoZ5+&*#a&-nXMCZpDxU+YkF2db#*X~m^B2ZulGp>{Y#5#HB zG92VQs{$*9GLA5CZ!V2`8ksVi zM%mbaPsimqNX4?Vj90kB;fV&^x|PuyY9eT?uz6>PsBCP^D(qBB+P%V7l)ip#jebx= z(G#-f9fzQUj8e7w?|4=#zr{IC^WC(Knqb4EX zivz*cKe+p(<~v1N3k|=~saj!~(Tygm04_nqmAcoE&pCUi$o&s2+i!DC)LcU2*eSx{ z);>e@_Zx@Kv$-zTTtefBi|MlCTDbbTPBzySnoDRLakUe!Ui`&%$)+hE*j#w1iV+$| zTv>3p;~G4A#)~%BPc@g&IO1wAT#Som$Mg>$wz(cuj_8{zC8Cy4yK(;w%`5ueKshUy z_nNtIQlX4R(+VSq)1|Y+rDFE{>YA!qGc79T`Lb+)eji5z#@PDY7k|^dZOB8y_a^+= zl4$H*u%aA6T$rBJw$TZ$b{Q^v{OMoWTtjpUg~m~a0pVi5XMO$cgm_n*3!2Ns2#q5y zq4!B%Kyk~+OTKS&QO1Qvg_*j?D+jJ>_cP<#cH8(lHdnpo5*kNborTMa>*(iR{U4i) zQy3bdapX%T1U^2JX?CDamr~j4AX1B)EByo%20rsz_snr+5V zpTFb--Jqp|Qtk#X)q88iZ^+UiDSmUS<}bQD^?vqroa!PU(u8{U{6*7oFPk*xF0>!) zdSl0skcXE_zo(bVMt*uOPcOyg5tA;1<~~`c78VQ-rkJnWLo#USuwjaUdq{@L9+FE= z!M+aNoV@msOtl^WR+IDCLvj$qnCYS`<{lE)-UiHGj4P~0ufy}&+i(zm%dt0Pem6zL zaVFi~hIOFXpy}9ez4nGM%Ev+TqMJ_2T*bj(_Tqz}`NB=-+S|bA<}pV@C>a+`GG34H z#)D?6o6Z#;i|#v`Mgqi-*FVy239d%<@YjtHoNG& z%8#$8CLY{x9IL`=sr>xMVV@8#nsoVP`3(fk>25lY{9XW>i`{e{`K<@dEp9rG@O}lF zoo+f;c$}lWuW6VM8n5yj3U^;`)EzDw6qD!PBrYKogJx2YRBE1(uKz9%V$TsSnsnvI z{&7c;6t?k7UmV`Q2--BXdDSob$0>c#m-;H&mg@Iz&}`Op>C(sgeM!@(5WUOqeZ>2o zi_R;3Tq=1wWEe-C@b&3C9W*gb*HZc}2F>MeI*;~pJ!o!q)4AFUl4d*sns?oF9^v^; z#M>w?nsn*o_}pL92qAvF>X-Z@U36aMw-I!sK=)@&o2*~gcuJ|4Zn=gr?PL`z=kQ+P zL0N>c9WiO&vWh&n4MpFTySe@&H|G6a8|`?6+E}~-VmqR=Z`pImcav)DpZoXTYWMBtx{LJ=QS2eC zVtsjTIpYRf6AKFJJv8ODGu`Go_g*^EMRgOwK1{ZaM9e)0jZ7Xly zarJG*<2q(+y8R%&28w&@)yrS{uxf3qFR#35Ph`c}X!m~=_g=?8mCV5zOcA^pUO9jbG2_z<@@`0;(fc1?!RFloy?s7ueZsielIT8dWQHd zLB146&4;7t*P?Ss{Gy35P&;0dsg5s`Z@~_pG2Q9w;T}x7%V8Dr0eS8PM)+al-ea4> zkHp)THz8~se`Yicz@{NvlN!#($i^vaJVI^j=h@*^PwvCvCyBCFU+~b3u=%t&ZoTcP zq$8BHN5nTbylU@@oAD7dF}2kf;Z^&OnSz|G`s)`MTvq;EeUnZ-Xy8(eIfX8rWLzWV z`{if2QocIRsF^!|X2r6~%8Dfy�*8S-ao#yR+JgG6&&XhH(aQ@%?wIb{vCe6Vovc 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 z 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%0A)B%-q?>`HWKQwJa@+6w$uH2Pp+2IS%z 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

&xTZsk`g?cH#9X1%)&4gz4ZRZ43cie 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%0Dlh&j3%6ozKC)1>jj? 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 literal 0 HcmV?d00001 diff --git a/plugins/zerogs/opengl/Win32/ps2hw.dat b/plugins/zerogs/opengl/Win32/ps2hw.dat new file mode 100644 index 0000000000000000000000000000000000000000..ad70207b37a824b305c8fb7967c70dd84f037e8a GIT binary patch literal 106682 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 literal 0 HcmV?d00001 diff --git a/plugins/zerogs/opengl/Win32/resource.h b/plugins/zerogs/opengl/Win32/resource.h new file mode 100644 index 0000000000..053ec92e01 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/resource.h @@ -0,0 +1,45 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by GSsoftdx.rc +// +#define IDD_CONFIG 101 +#define IDD_ABOUT 102 +#define IDD_LOGGING 106 +#define IDB_ZEROGSLOGO 108 +#define IDR_REALPS2_FX 109 +#define IDR_SHADERS 110 +#define IDC_CHECK1 1000 +#define IDC_FULLSCREEN 1000 +#define IDC_NAME 1000 +#define IDC_LOG 1000 +#define IDC_CHECK2 1001 +#define IDC_FPSCOUNT 1001 +#define IDC_CHECK5 1002 +#define IDC_FRAMESKIP 1002 +#define IDC_STRETCH 1003 +#define IDC_LOGGING 1004 +#define IDC_COMBO1 1005 +#define IDC_CACHE 1005 +#define IDC_CACHESIZE 1006 +#define IDC_CHECK3 1007 +#define IDC_RECORD 1007 +#define IDC_COMBO2 1008 +#define IDC_DSPRES 1008 +#define IDC_WRES 1008 +#define IDC_COMBO3 1009 +#define IDC_DDDRV 1009 +#define IDC_FRES 1009 +#define IDC_COMBO4 1012 +#define IDC_CODEC 1012 +#define IDC_FILTERS 1014 + +// 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 1015 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/zerogs/opengl/Win32/resrc1.h b/plugins/zerogs/opengl/Win32/resrc1.h new file mode 100644 index 0000000000..6c2956f489 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/resrc1.h @@ -0,0 +1,79 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by zerogs.rc +// +#define IDC_CONF_DEFAULT 3 +#define IDR_DATA1 112 +#define IDC_ABOUTTEXT 1015 +#define IDC_CONFIG_AA 1016 +#define IDC_CONFIG_INTERLACE 1017 +#define IDC_CONFIG_AA3 1018 +#define IDC_CONFIG_CAPTUREAVI 1018 +#define IDC_CONFIG_CAPTUREAVI2 1019 +#define IDC_CONFIG_FULLSCREEN 1019 +#define IDC_CONFIG_FULLSCREEN2 1020 +#define IDC_CONFIG_FFX 1020 +#define IDC_CONFIG_INTERLACE2 1021 +#define IDC_CONFIG_DEPTHWRITE 1021 +#define IDC_CONFIG_FFX2 1021 +#define IDC_CONFIG_BMPSS 1021 +#define IDC_CONFIG_AANONE 1022 +#define IDC_CONFIG_AA2 1023 +#define IDC_RADIO3 1024 +#define IDC_CONFIG_AA4 1024 +#define IDC_CONFIG_INTERLACE3 1025 +#define IDC_CONFIG_BILINEAR 1025 +#define IDC_CONF_WIN640 1026 +#define IDC_CONF_WIN800 1027 +#define IDC_CONF_WIN1024 1028 +#define IDC_RADIO5 1029 +#define IDC_CONF_WIN1280 1029 +#define IDC_CONFIG_CAPTUREAVI3 1030 +#define IDC_CONFIG_WIREFRAME 1030 +#define IDC_CONFIG_CAPTUREAVI4 1031 +#define IDC_CONFIG_CACHEFBP 1031 +#define IDC_CONFIG_SHOWFPS 1031 +#define IDC_CONFOPT_00100000 1031 +#define IDC_CONFOPT_00080000 1032 +#define IDC_CONFOPT_00002000 1033 +#define IDC_CONFOPT_00001000 1035 +#define IDC_CONFOPT_00000200 1037 +#define IDC_CONFOPT_00000080 1038 +#define IDC_CONFOPT_201 1039 +#define IDC_CONFOPT_00000040 1039 +#define IDC_CONFOPT_00000020 1040 +#define IDC_CONFOPT_00000001 1042 +#define IDC_CONFOPT_00000004 1044 +#define IDC_CONFOPT_IDS 1045 +#define IDC_CONFOPT_00200000 1046 +#define IDC_CONFOPT_00004000 1047 +#define IDC_BUTTON1 1048 +#define IDC_CONFOPT_COMPUTEOR 1048 +#define IDC_CONFOPT_4001 1049 +#define IDC_CONFOPT_00000010 1049 +#define IDC_CONFOPT_00008000 1050 +#define IDC_CONFOPT_00010000 1052 +#define IDC_CONFOPT_00020000 1054 +#define IDC_CONFOPT_00000002 1055 +#define IDC_CONFOPT_01000000 1056 +#define IDC_CONFOPT_00800000 1057 +#define IDC_CONFOPT_00000008 1058 +#define IDC_CONFOPT_00000400 1060 +#define IDC_CONFOPT_00000800 1061 +#define IDC_CONFOPT_NOALPHABLEND30 1062 +#define IDC_CONFOPT_00040000 1063 +#define IDC_CONFOPT_02000000 1064 +#define IDC_CONFOPT_04000000 1065 +#define IDC_CONFIG_AA8 2003 +#define IDC_CONFIG_AA16 2004 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 113 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1049 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/zerogs/opengl/Win32/vsprops/pcsx2_plugin_common.vsprops b/plugins/zerogs/opengl/Win32/vsprops/pcsx2_plugin_common.vsprops new file mode 100644 index 0000000000..086133a60a --- /dev/null +++ b/plugins/zerogs/opengl/Win32/vsprops/pcsx2_plugin_common.vsprops @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/plugins/zerogs/opengl/Win32/vsprops/postBuild.tmpl b/plugins/zerogs/opengl/Win32/vsprops/postBuild.tmpl new file mode 100644 index 0000000000..b0f9fb472f --- /dev/null +++ b/plugins/zerogs/opengl/Win32/vsprops/postBuild.tmpl @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%\%3-r$WCREV$$WCMODS?m:$%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/zerogs/opengl/Win32/vsprops/postBuild.unknown b/plugins/zerogs/opengl/Win32/vsprops/postBuild.unknown new file mode 100644 index 0000000000..360b05cad5 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/vsprops/postBuild.unknown @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%%3%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/zerogs/opengl/Win32/vsprops/preBuild.cmd b/plugins/zerogs/opengl/Win32/vsprops/preBuild.cmd new file mode 100644 index 0000000000..fea16bd143 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/vsprops/preBuild.cmd @@ -0,0 +1,20 @@ +@echo off + +rem Usage: preBuild.cmd ProjectSrcDir VspropsDir +rem +rem ProjectSrcDir - $(ProjectDir)\.. - Directory of project source code. +rem VspropsDir - $(PrjectDir)\vsprops - Directory of this script and its counterparts. + +SubWCRev.exe %1 %2\svnrev_template.h %1\svnrev.h +if not ERRORLEVEL 0 ( + echo Automatic revision update unavailable, using generic template instead. + echo You can safely ignore this message - see svnrev.h for details. + copy /Y %2\svnrev_unknown.h %1\svnrev.h + copy /Y %2\postBuild.unknown %2\postBuild.cmd +) else ( + SubWCRev.exe %1 %2\postBuild.tmpl %2\postBuild.cmd +) + +rem Clear the error level -- this allows compilation to continue if SubWCRev failed. + +set ERRORLEVEL=0 diff --git a/plugins/zerogs/opengl/Win32/vsprops/svnrev_template.h b/plugins/zerogs/opengl/Win32/vsprops/svnrev_template.h new file mode 100644 index 0000000000..afab6c4fd1 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/vsprops/svnrev_template.h @@ -0,0 +1,18 @@ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ +#define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/zerogs/opengl/Win32/vsprops/svnrev_unknown.h b/plugins/zerogs/opengl/Win32/vsprops/svnrev_unknown.h new file mode 100644 index 0000000000..a2a3703186 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/vsprops/svnrev_unknown.h @@ -0,0 +1,23 @@ +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 +#define SVN_MODS "" \ No newline at end of file diff --git a/plugins/zerogs/opengl/Win32/zerogs.bmp b/plugins/zerogs/opengl/Win32/zerogs.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5cf24cf9e09d94de6bb9bc1c0099f1d3d6946632 GIT binary patch literal 921654 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 z z*T$v4S*pV9%fcS~pWypTgbfc)ddM$+=#`P}FAHm%nB4iM+lSn6``{aH9d^rIBd>2U zp-Qun%vTv0HzlF+gjQW<_v$yd_rPcWmCcgDKg8Gi$$-B0kIY1!P;+nVd%l@Dd-d$O zAI^Va?ZQQ$qI_RjVir~)?5w$+nPfxoCF~4*rF_5NVq(s~mj>V6&N!n32EIo2vYwGM z&WKr^%^+Vdd~KVr#`&Up{|@2n1w0dRP#1wwX6l8^i(-DPRIpfS435 zX^95lFu_i;R4EV?3Vi?yd@X-{c8RL`pwF(0Z|Z}#j6DsVl~PWUd`jYQ^5&$SUe;WT zHC`|cb8EOM|?;8xjqsY@rwi=muD7b(4^32E)K>5=P@HRf2JdJek-t@5exqM zbcFWhuM>hc>k@V`(_!&vR%B2V+L?|+5*YXz{xT`F(+XU^#eY~A*oL5;URVWlL2Dqe z=>-jcnGV|Yg3hHQH2jTha7z4*u6G>xYQZB?yWpT%b1=){Z_Qsd?PUJQqwOK-+vxlp zTzzX$wXbRa4RQ2uNY&3nQa%f+ye_cHD%LZKX!LW^9l0p?#5+9|TYD8Xg!WmnhT9+S2vw9+f35}v*yWX$DJ6IhEdr2JI> z*eCoF=8##s?BtR$11hBTy6)BoZoH%aovns9Z$0{^=8q<(kGw2#ihsgG!R5x@)NV%a z0W*3Io^ySxZ=xG)iLd`%Xv59n4ZjVozd51q5BCiHeBQj(FFwBp_%2@Z*=w(E1io5W zLCSaC>K~mpU(?%JGi(_6erLKm+um0Dov<_TJ?bnb=q#xq_!i79Y1(|Xm@mpVAHIa3 z|7sDeC^t1B^rWAa_>17Z|Ni?SZ_l1RyLa#2qeqWky?Q}opiDj#mK-K14TX`z(!!!J zU8Xq{MguV{hQb85p)j3Z5XFEP3X`HiR1H!GN}*7TQd?rGX{mA@!DN~Xaj1}~iro~p zAf|e!p2yH%7@JaO5CPSO8DZ=gKFGkpF?<0i#9$!~=y8;>xBHf)A~*(K5E*7cE_~32 zD8`^0u(K?dPl{Pk{&7br_c^THw2r<=Uk#2qJwaLL$(h^JCI_D!E=pI#rE!_Oe(3V8 zBT>x#5vg%>(?G3r|4brZ5e9s445o3MTW;<-u?QXq4k^!q2V|8p&xoHKIS^J_SUGyv zB9jNrb7vD@#_s{z@+p1^{2o9m6vpS*g3m5CF@8V%kgTZ~ha!hv9E2A?d_Dz;aZFUy z={jY(12X;~HSEWIj%>f;Z*ZK8D3I`f!#BFW!d|#N4ePjz{SLov`|PfrJ9lZH%{qlG z?)mq%qrcB23O&}lD3VdZu0CNa^&#vK^uAbd>IaNM>E6eEvGaflVtg z9ihD{IDcJWw*s=*WqupfiKFJ z)du$$z*loVJHw7b%(RnU_!|DEeG{0vDX{8BGx#X=3qsH=zTj7RZ9wLiy9V>GpGFRo=VL()&a7KouRYM7K_h-JzXwMGlmM++^CA|@yeh1Ec89~6{unjC1R6LHk)Z=u4Kl=H zK#WNp109G=3Y$>J;26gZVp!}*Ow$5uVTWVIsT+>+jWBlX61kjT-2BT&v|0GGHlMG? z=euwyCI_GM)EScE3(ELnF*xR0L}5~VK+Gj$x(Qr3`S^NEA*FzJiO51TcT$mmQtq=- zh>XJ>=7y8Wv#>1YiSUfb)T804VR~w$JWZu~tUOs9v6zPrb7lNC^s5lH$rPRSYhf=q zR_c)1pqcUlG>(XD==*2$*J8!z$Tt7~%K2|QpWkyII<)WJv2|+(Cw1u3rDMC>dp*`< z{I7K;s^$gr!ym#vo0YB){M~N?*$Ur z&0mybOY>*fC8P=1PRC&uCA_c|Sfh~OuMix6gPDku<&azmHvEk;{5|94FB3l3J?w@r zveziztUX~he=S&W(3$fYzTd52oi;)(-xnYX2BnZ(CC4FA2Sjr_sN9Lu9r0{VKlcSAKE% zj3;lnbA0o5fD5f9=bqZ+-L5JDcBs*ICu*!|f&KHc`0~fxRu_yja^TBKzTSzQPk8cd%vm#R{Pj}zB2pT-z()iu7)8|* zf0q6QxLv#QzS+4;mo88kW0Opbpfp{xC`s=unuht*`0?Wb@uW$UpfFMzniG`9U@<+l z1Y*7gEsP?D#a0vx#0pIVVo{jtQ8lDktSXf1RJAK0mWjejseYxEKrm)&bye(C^;Gy` z0geQkLaCqx2NN$KGSt9;i=;6;LK`Yzs}%i+ao?maA(zl5E(>|!4-IrOX+ zTYb{v%5!|nVq1nxe0u_%jBrej_^Y$!WGs33zhvhFaX=5FiebGP+4q>IVK@OgGTG9D!gmH@$a$0A%Z`+|`=T0VV-o8_t4%v6~o|-lKP^}AR zq||gAbi{J_o9m1Pb`b1zgieFMnvSv%e?hRJu%_bx!QDNn4uavY`a;_fv?MUSpewN` zQho^9hrb0YGTh;D&&A==zh*Azi}05yG`+CkZ@Bbt-DAMlhrhr#JfFXWooV)E-V6iZ z^licE-vQrXXWGe-luf{wKg2KajjFvh_4dOR5%L{8@wc9iXm}vD&H?6j4zGVOq{-3f z>rVt{?F!HMA*v>SJ0ffSK=7H=1fo;d{%_Lo!1##)u_J;K9xN5{pnv>`k_jV9mYZIp z>;nI?^Ge503#_^*Bx6NTwT~mKt|*cECQZhbYrJyDT~BrHF*>{Rgl^qubnE?0?K{4y z-0VQ&H77%^J<;^89g`k@YuMDK!$+;{K6+KxKAZ3C@?D$W-@owY>cy{o`r51CzVZ53 zZ!b0Q{b1R53^jthTQ?v1`Nwnn_j(TP_Z&XpIk?Yr;MbfzKcCsX^VFVSP7`x>+I-I+ zbJ~3A>I{5Y$=8na^_=!F)ClFv^j4l+BYgFD5la3=yHMHG%rFuD(!H5@GE_z35`TuX zFcePv}W5Jm1%OSNu#Ibm_(3GQ*P58C|j-adp zZrbA8OdJlY4=Ph%r!qPR^7V#*Lyq7}vHWv4y}>EKrD5zv0+Vu?z?Z8Qf~`^(h%KOj zFRv@yLv9_$Jyc);A0oqCcEMTlx#yVfGrP!VuZ#jbGkj3X1429V$Z&X|IHWvZ`($xM zWUG`#WUGq-F25N;na}c@A-cjQT=uEnEgg!?{~ehE&2Rmn51s@ypG=NP&Tl<(apmp7 z3p@5Bc9%QH`Z$+(KK3{&uTA%HW-kjA zRv+c5HOkX;Tu$9lIWddQbW$&htYMcD4 zeHC8ii@0hVY4$CZvOc)(mU4F-txR(^^NO&p)15h?_4Y>AJ7kVu|8QuX17Qsg8UEJ( zIU@7B=sH`&Yi^FHwKJ&3&e)V?rnNVIMCr1F%ft^2jC(LBZfI~q{}Ryy{mMNSSblD3 z+2=ya&A+n33oLjPS?Se?a?3+gR`?}<6q5XI^(HUel|8*nuW4QGed3;evl_P89M$Ax z!gU83X;u67-48vw?D6RzOrNpp*=N^0H-GJdMW4R-@`lAPfAPwzU%j<-%iC{$|G|6P zncI28`X6^}JA828*%Qa|PM$D*m;vjlL!M&?JV*BCf#7|+&Ozb*zn(k1H^+8$HZkYp zrp*`GtHlI0$k%Y!A@5(r)=N1o{AD6&sE1Z1hD_fo^sLpt02lZ|UJQrdyc{WF8i)x~ z17aG51!9_p>7#|In=}D!Ks?nk6fwQ5F+$Tc5JO>sn9f?#!UUypXeI{4lEaElqlnSP zG!vs))W-$~981?gVJcXea7@(-d@+im*!E3{?&# zF?X55zRDDt+JorGIt`f1CMl=KIg`o}g6*Y&V?;42#wFu(6EJQ9FC>`m436#?fYwc8 zlU*>En~9;0b(29e_niCe0C^+%JP3SJW%7h@;4jaGOr<AK}1X z3gGbc@k#lq=qJH1gnWEkw-@J#0>$n9i}LlQr0(Mv&h#nZF8o`4dvG7e=Qw}LH@d&V z=lJeTTg+yXBmM&4P93tTj@WF`t_uim+4Hf+qkc`D?8%&PqV5<^%~75jqjJ(%i^1uL zMHj5}VMhPf7-Gf(yZP&mLThP4rsH5Pj;g&3f4wt8`|>wW{B^eii@&xN_~QJvixM&l z$IapZ5UY@S0|wU-37*hUsvXA9LQsfTQ4Q8_T4A z8CmVisFcr3S6vra`T#*54DI zxtA``p_xC#X8sUU^~?-Yrw*wUCszB2qt$Nq;Bf=Gkp~K0WZhd4u{tcWv7*W3D~Q zLQB!tp00D(u16mIXvQ-uXFmJMb1!UoVbK>0U;J$Gk}qF>ee;`deY^CnZ$DVhghIQ2 z{NecF!?|b9dd{EoK}62PHS2_3^t_zO(waAozcgI|;AKZOvCB1Q-UXj+Gj81CJhR%20^reQ!V zElflj1Yz<0R=ngB*sx7y)WaVRvYn z+LiiNsYHe%;_M%ibkWKC?W z;mB?26Fg}X^D@Ss&l>HiH73`N1y(O;D}l8r68iT-{(7gwGW_kGcL9I9J#kU{OM6A}m^g3-s^pxekAg1a|Y6>7WbrZ~k1+Uj8;bAJy<|RQ;1?+6|+BO}8tj z<<~U(hSMOM$vT5YC|}4+YcGER)xHQz`7F5VhLCz&%HDaTTF1Q9PNoZ4g-*GqIlERJl>5;-^GZc_pagvcO6olu3OzDD};-YVR`2I5=f_ z+AZ_5`_3NGf8pQ}FJ0f|v!v?|CpJAA*Ysrl7JJ7(y5Z@$tDl{}cJ2bh-z7^nzw!E3 z$h+*_tpuEZ`uXUQBROZ!vxKe_C?;s^Sl;>Eb7ynUp3XgU!b{FR9Zd)5x} zRhzG7xH|8V_`MW~`j?hL|DHX27M7t&;qSO{cO@gI>q%e+nGs@D?f% zLt(H9Cpf-DTJdj)UYT#ZQ3-x6glij;n~0!hhEb%1*k!>D2zf! z7XxA;7z*Pciq%XEj*-U16(x%E1+llwmKDM{)V-F!s+LKqrDfFHn8C1Ps?t^4tNy2| z$H0Nmi~}-64fuk-lK~p5j$so#f<(eG%pwOmx&Bz?S(Pr(r*PiB54};XWVA_-q#bl>6)4d)*(jWmLdtQ{Mu73qsKC zTT2DAt7YeoZQHiJtLLMQN9-^&VmY&8)f;^#pTA}xl4gV!g3WXs&box@LU2D1@n@e9 zG!nR=BXs_BSn$`~3(MOI+&-_M6*xZxEd(={g}W8FxL#P^wHOqFc18iy1zLX^2yFT5 zOt|56do}}(41B{(G;4TU*4M(Z#Q&9I)YqtRJ$X`N@FhU(Mlc{2ixr?o?8u~xMP%XF$|5RiH;b(=B8$S(T(H1k__NQb`5i=f zyHaaYI0hxCV;}-5i31GouxF%5v=0r3cOuVxwR3<4oFj4t#uu2a9 zCL-I9_nwfqXWtaVvCNKr@WyjzMI6 z#TIa2E-CjD1Hs&I9B#5G%suCE@N~$5vksFDl*uIJ8R=p1;8aX#=2^pH`+K&vy&UDc zGYjXq_ZH{dVgJM=aYB+OCV_9t-SVm(U{E zJ0o;2rz4ir5!%iO?e2wTlp`Q>#sb4%A=nNCc1vLOf|d#{+zXlzwD@Z!ux5dVzcFS- zLQiy~+^7cUqU)cDs(T#%hSxa|k+qLM%U>gYYcN0L_hISZFvCVj+LwZFNa_Yw7z|2T zOQ)%@s%s-^ZmQV&WW_Ef>}<}wlcRq-daATCy`AAN${O(-Q}1v{!`(Ci(-0g}_j~_} z^UIWAy|6l&4nj0EzY%{zD6gYrFjG#Bh1-Jf@4 zUoPqKgC1Y_Iukp4805==w4UI94SYpssATyIE@{s#%wPLI#r}Vh1Qvyr5|Ks-V`yQH zKtC=b(omR)G+0Lq(=?10rd=30Oi&sjj2wo-1f>ze#K1WXOrdG%VkoTWG$1BAZCQ*i z2E-b;gcimS#ZF|}v<}OxBDNIfO05x{#w>-cG*;zI{S0~0#iW?@6e+$~tg4<=H9U?4 znlu{t(56sA3Ry@IdNL?%xeTYEk{ik}PW**vRvL?RY`Wp-rm%&n8_K`W*I{jH55igL zeAvbL=w!&$xrx8{8xF-r7*KhOW_Q_d zSB@>iruF}3$DW&yb1A3c{z&2ScCX##&Y_Y4vKS5p2t@0z2RWv5N{5bZ+qdd5?8bpB zvmQKOZGy+HOGrbo4}Uc&H2kfuu}Jw6SSr}PE|Tqq<(?55_=>;YD73@hN^QM!ai}A- zmB8Lb37sgkj|5I~H31jN-)M)w(G7B<>z_5Fkm?>5f5VyW%F(}w->{7B;WfTD^E0P^ z6$*UQzCiX0z9A`Vf~&3$N&SRHeuL6Jy}HFQV$Q53feJP&N`T;2c}cgQjl1SpY~!P` zjSPju>+X+jxHq)!&(SpxmCxE%CjOz)5&iul#?!(Z5Hmd_c3xoQf`G_{elZJ5B`yr8 z^d>#5!pl8!Ra}=+QT@Xco)1Wv>z6b=Jms~}^kwB5EUi%I&3ZR4ZgMM(SHZ_5{s4*xJEuJA}tEjOA*0ZBQ5L!uaz0AHX3ZZNnbJV9YH@lnTM zO9+#1w54OBo8=%5Rv47zSZH3NBYgW5_R+=cwcjO&0yuz}(;(I9kz(4E!&TsLQCtKL zn_L}N3X65gTst}V_WeXkS@6}{3-=20N+Xl68>?3xG9`++=QzSKjvfIHPlN{qf_a0| z(=k+ENJoJ%~2Jq@3a+s)#RV++_L6jxID z?qc?{+68>uVcDiHmT3!itZV01J=?YE*r{8q4xKx+YuUbgzZ(a<)nMf5%+a}40@rjS zSiP_Yu{zhc}>J2^{@%tUi6@{j6bl|&zRRxi~2EI&! zQT5}HsviYcT;W&gg^kmso_2zYl4<7XF*>h&^-qXj9BX*spUjAV*g#3837h6C$ z*K_7n&YoQ-fBoeIqm59$$X>c&(H)wYv*wmGgM1lh#H`LzzCH)>LE!(zrg@!k4C25z zx=1mMw=jQ+Fza`2|99B`6mpdB{mMu=-!D1<5M6q-+AXY@$fv^|E@OQ-u zGo=zK<^y6$V}vk@SSBL-gr-5T)y35C7(}L?$6*%^T8s)`VvSVNOd^gH7Q++_3S%G! zGy^7tA?AohlfWi1i&O{`jxG3bWERIhB>k2uc1dj8XS3qO0|wQqNB@#LKMjake-{)UI&>&17z(R{7CogE zlvdL)p=l^gXc{?;X(|slh0(%pMGT0M!;A8bW@3e=k;67dO&c+yI6pXDu=;~UF}fHW z%Pfn10@S>yaIfGmsT|2-B$W`1gMnSamrSu(DJo3-1q4u7fm0ZP;lmUt3_BnNP{#1Z z9f1Y}!zqg@5gA~?I8w|_WFM94-h_rlnl0nrOQw4h-xfP?;DE5J95#h!%HWg9DJh2& zQyHBqDLH%=;0njuWDix`M~XX+{UBda+-HmYcJ~MI zsT_(d_BUky^PXp#j`*H+39AqD)Oyg24o)BLsXEkCcUVsCfu5}Xh~M1Qfw`&1@njA- zXVyh>0@2>FNX}SbFM?Sb_`-Dwt8_9Qp^Iz~g2G8m>Uf7Ik-4yL z_jpGk-C}w{^A~@UX$7VWwCM%y%z{PZFHOLv3v?q75;(GcZbZE^;dPFM*E$@Tbs(bp z?&z9(;BR1!?fx0x1!ryzO54QRzC@l8zadrE8thj2Fert^0apZ6`H-$qWl}zhzJ6Q9 z&gaT^&a2!ux8iNbP1yOGlQB(CF%%aHM>jhf+w4ffHAivEUUM{|@u8>&ha#^(!Ey{S zcb!kX+mqBhr^1~%an~OYZ?G@2{{H9&`=T1|53jc;xW)%phW7}JyX&f`R(?_4Q?nkv zsrj4^-DdXaGt(@u(Es_tBVQW);KGsPUmG)N>4Zl^NIbQ(}z6{e9bbx=I?BtcbqSrGa5Rd>A&qu{=(AY zZ%$5*;?M9G9g6;ikGB06fa-rJDgT==_kSGaxKsAp|Is*vqa6r)DJ(gR3g#;?Ku^1{ zx=Azi2}29hE)0l8VFjf{VGUeD1w&!fI)=|{gD8wBR$Q7kVjMb7V~Aovj3I~BSgZzO zw6F~F;?PViQ7ijnIu@PLfB*;sOc=l-1y$lNo5Gg3W}%D&^#nn{he1iDhYlTrlJd#K z$HZAuOq+7tK9D6-$HZY1qkvL!+(t2bSo8Ic>9eHbvimBeg~`Fun}!^GD6GrJVG~&6 zKw<8cc{};>M?egAxsA|PuQA*@8JX-7h26j8!oK}g7vA;%P>%f%YyVeX;>p_&USj#e z#s1H4;9c$RVWoy^2do0YNZ{JTPSqNogOf7YQ*BUQjlrIb!Jf21p5*>#Q~RCGfV@mf zS(v}BbqRge1-ATkw*oT?_!9YR5PTtjwH8u7fAie@jUohH|7=8^lM%I#gx5aEQb!Rr zc9|7^Gj^J(o>RV!NM)+4&*|!H`dlT`;Op==c|~CIGXIM2M$i?x!m_xAThcpwDzx*& z{_}KVljDS)`HO9GBEH!v#BXe~qj61+Bs4n~)%09s6Q-j)7Tf3yGl5k6mnXToC-qK` znNjmjPu%sVBN`lvsedT8(Sf)|`=aXaip<<}c~rOHxIUK!_r5HkdBdBgwC?$I$8NJb z_k6bZfO!uLUr3*;k)vN9GyaY7liqr0>WU|y`skUNtENA@ir&r(U;Jv(iyPm4f9tnf zkNzgqIq=G3>gKbjJg1I2@Xa4;gm7_3qz7$@L1a^Yc z-eJWKiVG64SRe+$SbnV9+nX9Fqk?6kFe&O7_=00h;ZSgF4Hiovg9%^(i!mHzGCAlz z4A#IPkq93sJ2dvL2n>}lfmq}PaAF*rVxOC&_@Xexv^*6(*<~q-kC9IbWDg!Zs7;%r zP4U;g3*VX!t5iqU`REMYzFr={uG_dSUM-Yz)i_+Z-buI{a=1Sd%P?15<`&^#?9!d& zmKOdo`{dZ4v`_wDv3Zg2(tjxXf9kh>yN>MsxDI&n<6Pu?iu<7bB94zQE3WY0kbh5h zo9qs4TXwzoroIcah91ip;mKk-q~YfwZ?)l`D#K5u3^|!KD7Vf)Px=5)rTZQJx)x(LFAFRGUP9e(Qd*sfy5(eOlM^hiMA$jun$t`I33lTf9cBLKL_pm5cx2<8vQ5vG zYqTe{#`=UNKUTacx7@9s#JkQW-0CU!FHigpXCfONjHvr-RNXzXG!{2F5L4?%|MCyV zm4D7JaoS};ch|pWNOt!}JNKU6qwk_#gJ#Zub;BD=f0{V)gRx`YdU)#lk4}C6iD|25 z%wEr!qxlQWR2v_Bux;m0rx@OQ>1KGEOE}rYqR*YlJ9ol!?zs8OJ?Wa;*$F$t-F*A+ z)xT&!_zUb{pZY%+$=^%)FQfn3_CLGb6o@5!(R*uOo}cB z#Eu~LMyJJMo4NzkkXInKP$mZ=+pb#@$ZUdR5Nr(!8%gY#h%6`*qlU$#7}8i8Sri5$ zzy&pji84YDP(}cPBu5B(=cHMg^dEXHu^3)mb$sBPyF9=LFO9-cjrK%0{57WGe#R>?M@M{v{lQni zc~#g;r4wJfDse>3`UARkeY#t}*?s!WpZD_0U5C$p_4VmVBAnvd$drUV0UU{_M%FYE($l;|*}P?-)> zd~hs8cIK>JQ>sZ#%B68t!E!CGE{a&C+#7Y|R{7b$o%1SqExaNM@g1+mOoY6=2{`gr zkjncY?~mSBzY$-dimU6iQlFOr?n*z`Qf)A&TTXG#o&kU5medOw;0~QH_f?dzM?-N* zd1*Ecol#7uYci`ZEcvW?{uH>NeM+)c6a6&3*kY?UBIdQ%GtE*uh^^aL+~z+7Pgc zKL?pppiTY;I#WX6{L^iJRRM-X0$Fs$0w|_vlyL zqF?fed&xcS1;j6@Yr^v*5?^qMe~D+2f^)Y*1fgi>(|y)348MAut(%B^1m9mXQTvA}|GfWTk{G zCgfGb)LDry3{_xNjyj|u+ovP-Rhz1gDp3x1$lb~<;c!=S&oEbRm_kgT%ufylXcZIS zO~Cr=($Zb~JNng?b6wT=0QVq=^vdciar&&#UxWR%qcCb|e1NPp#fey-_b|Y@U&Wz{ z!t!E!<)YGgC8d{D@_n~(u`Zs<(8$w<7}NV&0X^mRt|b%wbwQt!Tm z7XJR%rbvs;eUW5e;NAz390+D11ezz!HL1 zk07ZjSRs?U*#gO&e}(=v`P=26*Xp0sJjs*Yt)PGvF0BV*gN(GulVP^l3s9)eTEX(sMkE>KMK#=ADrL7uy5#$M*pex zzT@lA!c4vj8h_9?^%d8|H$%o84bSfg&aLsx_}C-;9iQ|yK56gUQhBm?b69?LQ2t5B z{HsHO6ZeJW?{Uq1%{A!_*W^{UQEw)U`B%vmf38^ZI0L)D&@eh0n~Z<_YwcaXeEHso z-hSZW4}bme2Z-ONpWd{4cXNm1vD{7;bUqzef-U0DEO^!8fG^^g$g?@@YbsxJLnAZn z41B-!{N>%@D+?r{A5oW(4)6g%PzV{3sA~LofDZ^CH~px}@)=Y<733p{qsO9YALBw? zj-WKxMSAlC0F#}S7##+|GE(Z#W)NT17hSbW5lGq zb{QaMf)*f_X<8^^K#Vau423~3L&GW+5DS8p7AEVUv8j#)$`Dz|E2G8uN(+ml^H;^F zDHIk9d_@{VWaWrJ2E>?XVHr3E#~39*S!M#uG$fgTBtn=J1dB%A-D`jtgI3^4KrFgg zQYjG%iwIR9R*q7{f=Go<<@8rB6*$^wO$A(w1F5Bi>vCiG!eV@3u>e3r^=E;5HYJosfsUHi7M6c-SlnAfBOf>`Y_pd$h+jk#+*o-`z;`gO3$B(ze zNppn_NO_v9G!fitbha4nP3A5P=Ee#%1I9ZzV9vSv23758U79ashDsq9Pv8>rWvwb6 z5z_e!F4YIk`Ln~JK0m5*3WwyVq!daEj$)JAl+eCBEDVJ~uuzyA;5PUrKrmc_()=($ z4s(YxO&So(=rFgqr)g-%n_XK*=`9r42UHKzGz`gg3>}^5R8KmCMYeU7)8uX zEkKOP<4Zze2}^y^VnB@HiztS|$^bFZX@N2+zGz_uV&&+H81fRSma$`T zL=lssg)tlq3PWVFf?!f~F#&3DEMaOuEG9}>rX=yNFCkf_4IMN#1u}9NatV}$#gYOt zNGB;o7WSzW0_wO_gr%@g$Wo{uQgx(UZ%TYsU$R_RW{#0^GjdcY%uRAs-Lw37Aj>Zb zjF;xznWaR!ZhuFe%cZ_^>RhwG68&6NM=!)z<%4weQ}FqesS~ATmF?4!53C%r)R(Mt zsw%4nsiR+4m47`>seS&U((*;c<&NiuOIWp%w}9-Gi;5T6?bDauTX4;$T;^ikXpFqB zllb!h`vR*`U~^L>(Z7B2*MZ=H`AZbqqJL#C2H~$-g~OS@{`s9f`ZuT6FZ-l#`e7ac zW?FLMT*Ef?MA${mQ3c!3zr!P6MgqG;y##;VVqam{_q&PDxy3!}pYYr{u}=qHxGQCe z5isePYs7l*uq`8^Hn@!3?v;CtvE7J*I{)-d=Y%}t9rCnW*uPyO|9MX6pU(1s*dzQY zkEoZulis!^Z}lIw)qB*(w%pajl3(S4CR^G^K^Yr@Gj@9CZ}Q978a;}i1c%(S)@4tB zseH*(*WL2e-~ax}_AQ6o+l|^rmjYSueg~%9LuuEuKvNBk#)Ui0=Sc271 zSa6I+hQDgynCLX37)6XhUI|c>QVxRQlv0b}7^4J)0bfjXrH)|0r<)E|-Pa+DkDe8? zl=qpXCYK-;{^CPkI7?+p2ek4RBu-IrKWR<-on5~^_pLn?|elm>92j~`cl)moRU5pnOj<9FP~RY zHgCRt#f&9?8-Lxt+?%>Ht~au-?`Ap5l&j6ZjBC16ukMV$vOR8vF>0xiez}pnyenZ@ zSKLw~cCistWyCBoH$_S)H#Y^2FY66Kv!lIZMd&z*LjU(DFnck`j=(+JA?ZWFv$~mr zWj+Nw%Fu0x~FV$ zjals$^_ExcE8cO>F)hj~?nT$Q7u*y7?G^tNvFMn&M-r~>N?BoqPd)CIxZfpi&#>ri zF40@v6LxsSZygr#>Gy&^I49!G5wYvc=bJ|F_DtXGmA1n*al_E04_(u$L&w+nB)`Zm zNZ<3j!Iu7vPxdyy^aI}6+dZ?lvrS<@_HN(YEqb#eiuKf3nw?F@j-@JYZ z0z2Z&C#pL>diT&1|5^K==l3+UAYV;Vwi=Bb>^AXvnkEruCP5Q(X0^&r2h9Ixgl~^X z=Q|(z052vu5$RBJM-xZdx3puKHcvXLp4wt~xV@fhX zS{Ck*pfo}l3L}KMPlPbfD=}eA$zfD5<`@|^H+KNRqJ?F2m{c4h?TW<`qn0sZM6qaL z;?in>7*Py}p)jd9GE5AP;V%Y@QN%J+3sDSyAu^_j41Xc7C}MCdp=l^A2o@ZZiYONT z>O=;_!e2lPa21QiK@P)N_=|%Hh$W?5DPkP>3wedb$Yl7-z%hj~d<<>zF&GVqg~D)| zaZMGHz7U0idHoC-a_e?q9n{zlI?;scQ&pr?|W^Yh> zqb=>(A^wZM<5%Stb)PNuRkk?v%iZRex79m$2a~Y_GWYvt@A4bHbL8|*v&!E7!PT$a zbi>O(xa;MAzPPc)l(*(YtLC<@)>9n^ceOS&IaI1SQrp=RIzCPOnjve)T9mZGgTQ9k zna2Ki_{+;}Z*K=800>|qB;lG&enx>R{z``j!Kx=KNB=B{uMXijA04>F!Fdz(a9>fF zabW>5T38~|%#@bpvj|6{g}G-y434>fenQB&FmuUxMQCA1K)PosEmW`|*n#4nxzn&1 zA_HRHgoht~nCLWeScRq`vXaA47?a6bGC&M@l>uT55KCxU@mF`?uOJu-i-QCf6)YeY z3M(87h(!y7W|%7hYDHumAunjg#FrEbqlnSJqLB$lOLUqP9~MJf;ENFe!BmVI;9@eB zix~B8#~!|v0A)ciEEXK2mz9GqR@g;d;wzafPzH-25B4bz0%*w!C3SA`s%=aQa`Htwq7`Zuj*SIb&BN%EY--WnmGDVz1-P%K2hpO3wnLM zP0Lw&wJ+#fuA;K~T}h#HiSu2l(=CUb%biQ4{bejv&mO`>tX5f4RZ?g#ES_(_eD2a) z#$EnF{xt_OZsLD?$0=X-^EqyZd&=TTYvc4%A4P~ z@4ojouB$eemo&EuWCKAaNtuJUtws~7)x@x=eNR6CE&A6vJzb7}bM^U-LgE1?WFtZn zqCq#tUO^slV9~$o)2H`m@zo*SQPuQ9-KT<{72i@Qid#Sof`!7|m^?2`M4I0T7+M$; z{)!gnRX|}0O7o(iu%s3c3yT$qB{WT3T38H)VKE>kK#j=&G1IjE=9n_Ao+Bm}Epcg5 zKunlgqSH`VKn#m95yhm!V$s6*CX82oHi=pku|*eKSPX?#Xc|XFrxlkS9PVK;2o`lL zEC$E0ScpssT3Df(LqM4laEt_In3z=LunZPcf`c3uMT|5?`~qL-45L9aESAtTDdmKw zaRkIlCPQ1eObP)>;jdyb4u$ka1xI{As+60Qb#PYdkcz27HVKEC@lfcY^w#>o;!SGl1B4jNK^%PRrtnQvwC>`-<27iMlo9kZ% zIrd+GzcToX_+{p^clJT}i$3*EKkk`c#GUR58$FZO zd5_%SJ#v#*`bJXs*tKri>$9%yOuDfn`3fU!RjxBKL6^~v2ga_Yfp3)V0B{&P3p{>Be(U3K42-+JuNA00T-&U7na+r}Qg(3WU1 zdkA(IEuHP=HopH;y7kK>2g>^u`JwyHWv_!5Jn3Vl;){nv@kD$p%)erDnsiCYobo%SEMJv%)$#PJx-wT7=B9)zI+L$#8@a4= zk+Q6j<*-x;+VL!~V@HO;^VjhdlIUNVf~CfP6@P;#$dgAVfBkY>d`H*& zWS;cSI802~H|t>Jlm_2|TKAml5vj+0M%DSUDRAa7_vC%<@jJaoZuLps0(O0pH@l~8 z@J`y|7Qex}U~9(p?I|~OrY|>_pfnfM%5R6fEbGDk!hz$Ok-&lZ4c=qwZKGM8@?cm& zGpln1Osr>7tjNjr*#$e#pa0|8i*Ah1f0~hBWVK)Fha*zo^-JIBm%WFb5Q#k7#%%Y= zJ&-v0;KaG>F2C-Lt8aeg_Mfi0>)zMyy!X|AKDDm;c!OaybvPzUF?DLsfsUQ~jb@_} z72IwwbvWuBTmM{q?k7SjIDdScOQShR8BHEOJ;tEUAUXLSe;X;0ulw zh{e%IiWQ5M7Iwz5a9JpfFD!=3;s9S1F@_@umZ&v8x)>H?qK<{d_(~4r2$bP6q8R2% zuv&bfFhs`C#TbsnrB#?(#4;2X6C&d~6Iq9;@&(GD5%<46RZWT|>)c)Y?1#?PzF7AYhNl1aMbybYSZ~#$Br_E#ieXn$id2z;>Bzc zQD`^GTWGIXSY|IPUr<%PXkppPX^Wp5edV#tD~+@(3?y*;G9zw@k>Gd)7z(T9D4BxQ z`z+FD2##}XN{Ie7C2&s&+I$cg35@<_A!RiS8u<3dUwQb~Kfl{=Ob1W?`eifnTWv<3 zQ}+6eIWVfwNLbJjJgd>C;1uH5d(<(nlp}6&`&?tUdnIqNrEO$KVE^3>h)(|*!#wZwf8)B_{v-NUAE*<{_Lan z<&8&}{%j5aBZ|+&c+^PjOiunr&uMOMMz4VtU<9Y&FNzYPAux&eG6Dco_Cmupu1WDX0Qin=@*msamtP++uF*HYCVXtY*XTE+#?^;RJ`p&zE_h0F*!Tw9 zxLS|g%|1DsY?<3UGIw}nZKH9&q&1$I>wU-U@g03McyzUY-ci5Y<7wv|o?f)(rd!{> z?anuEzw5=jfAQ)azx=5DrZp26u8*I*jy1d3HOX&!{je$3$>-I*yTd`j)1UtQjl%Ow zxHw;fpaZ@Tp}p<4+Zg;sNHWa{jS1Rx{;E%bd_bJLw5sr>IF|NB4v-3e`Bi|Sg;h8j zMQlE*bj1}Q82&OYELvD7%u55oLSdPsg%*aw0%C&F$YBf+LteqI4q|+SFsU-MFayMr z5A*rc1rOy3=ZK`(8z_Gl1TKL>|K(6vd?wL!l zDs-W}w2%N>Ny*}p(xvF#QdWt!7gj7RE;Emm7nfA9N)Unn;vz_C`#p>`uC%&1K~7VTrrL#y5sfsAp>= z&(xisDZ4yUwuPqe^-ftIxA0_qMLT=`28?M7DCi6r*Uq20tzmw%|F~Aau}!}Djif;Z zb)mU6XT|?3aeQ;c^i#eQYS^PNa#BnD1ZFrN@J-tvlDRn`XC0wtkIapJ>8m|6xBBMq zXR>r)-VwG#3K)AV?c9Tt=YRD5y9hhK%(9c${%Gy2s)H$W8{_Aj>w`sK&>1_qCA^^3 zHoZ1te9LeCS!WLZp8oVJhLZdI`x4OjwKTz3DC3(D2USSGRt^3ler50%%!&S$&xQK@ zl2so!-B*P;sV<; z4~Pj$W4v&*u$YVv17hSb?+G|2#lS9HrjS&DSSezn2fT;CSL86iXP~f{_z+p*(jb_i zG(K`z;Ol^J4~P|o0Wsld6fp*Z@f|2O6MWIa!e7N=uq!NrXWe0?N7NZsllLB8Tj6+I?k*p44_zQd?GAZ$D!7=0o#E4>{u*}_pzhGB1vVt!q zB9P&)GC?rdg~(`U=uC-7V_~uQN+v^I(A)!H$NzK+Q=n%Rmo2?f^xgJ z*YL_|XJpnd^MK!|ecs7OLz38V@FSOz@B5DWIAPYokrgdaIJ(qu8+n-EbNKWQ|MNTi zXEd-*WBYF6WV+V4kr|~u_~smpeA5^v-fDjZ+wGaK{ILnuiO8vTO?)nTLbGQnRh6K(#lvYs=(wg0oc1n!e%pP4lT zJKzqnS@48%L_b0?bfxh3OZjfGbaL|>&0*?es6Mt*qOv%u4o-jV@FPKlunY~Og^5T5 zVhjq)svRJh7f66zBGOFI0>iv&5yCP-i&WRb5|oC&0%G8cg9(lSF-9QL< zu-Ke4{ReYDVnB>K2En}5LSYb$k1;e%@SjvfF&Kutj1G$;2EJr5;V)TetIJ`^RaOaM zox*}(Qe{G6vM?9mV&b5Mb)PImM*osxkQW~`3x6e*=rq1aW8flq{v=L!7efxI#WVTk;9|{Tydx%XhsE7 zj?a=EoT&FM-B%q?@2IL<>NWKWdigi&b64sHzMXfdZts7>DYBQ@OUrmzsiJgIxqU&Q zy<}e5vN>hf&n)}Xgo?K^%a8FaQe1@*#}i5R?xa!!jTvX}j4A4lF6@d~)X5*qahU5u zGYUM{h~_C^(Z82;MqOfV#1JyOHTZ(Ip!50b2%6ayIK%Lt%J{4iG0un_X9SHgg7S@k zOd}+%#V_%gTm0Uk(eJv1JbzZy3qvzLu;p#`8N1DG+=0;ZyJ9YG4Ifj>c7&mm>H?>? zN6au{ry1ch+CpcwM^0r~kEXbyc2=LZsGmasAH5o6lJ$F?yF>@%jx zXH3foHayDN=aTYl{N(1~DXn2Mo5LnGMNF>uop8c8_ke%KKHt&%eDV;yhtRyXoW1^e zN1(iK-eL1E=TLC|f%s|r(=Rx1LCN~Ne*WIWzgd0P10P*{!>KGLkn{Aky(_w;D{e+h z^!U~|Hb9(IJFc|)qy4NP*+X8YMR#>~nt%Ks^7hHu-pb!v;5y%!LU2ciDfJN`&;fQ3 zhJ{BfSFS`b!YueD!DmsvU)u*ned!JIihQxi9g-3%mvA&fSSTzLv=|rW7X>CyDv1yV z!H9icvKVu;pfEyMVj7K{R3X2Jd;jcJCUI&oPsI}mj6bj2^Em+KN8=0&nlckxg zg~4Ks&@?Jog3?eJ9}2@_F<1;2EL#f1HlrSmK6A+j!7}NjE^ox6a!gsEL6^rk_ELGXch;7OgR)56aG>n;pjp3G*!*Hi+)9P`-08tr;AUj zUd0!2^p-!joxxxFw3@YCcQ7yQi?nZEjyQF3SxF&FM^}}V*sJWNi%W}^loVE!6jzqA zD$!M!+V7uae>JOgUutP9{7oorV~iCEoUq88d=5QJ+ z5p`(?2#%R$M4xX&%`_s@32Qw|1ckH*M`%p}+Ku zdfp}GCC}uS0#a9nWUUG<*dI2&!zaHpU_wjS^tRy1?IBa!LZ`LjN1WRZ=$WA9V=mco zAa3e`v{?rVF4=R{9cv%`{U^Wq!v|OWCI$}nx|Kz5$ zi<|%ca+5aw8MrbR%UsRM{8Qprn5(DGko#7a@Djx2?(q3(!Phl_04@xPGD!)Y2&b4) zEWu}pCUhH2_qKc@zP7BoLmYERxOdeKZXODQU|tR;acP;CrQ|TbH)IhlSS(tYl(#}y zEYqY_L>d%>T_LY9SF(Bvg~@_o1TrbJreQH!m^T?i4kL}hF>+Wvy99`ttR-?-qSLS# z>_TC1j0u885d&h#D<=FUB}=M6EOBX-T6D1hnnD~QGFn&=EbvvjSP%?+F$H3@Fj+YS ziy<$EFnka!T3D%L2~b01Le>~rSPXw*F{UUCeDN{lFccP1j6*p@#?ZpB7~AbwZcCsn zL`5Zb2s-F|Ze5^rc;pH+r@a zHOq*cX+)fBgggGs^(SX^2T$t^nA%~g;4vLh(~P9~oo-`49TN19p}v3ruI=w`L4O_U z`NzO9Yt4m0uIL`QtSfwWM`(^=8)N=?jcxTBdm?&zW7yc*(1HfPDX08%k4NSm^-W%H zOZmVp;q}1eEzx7!{KmEVviQdMcHe?}{(QzZ`s6pmZUWJf<68U^-aE^Gcf-m zon4)s?8RWNVZ~xrtm}+{D)cW|S>8%C^8eyGSL$~G34)<8a+t7yM5LiGI0nJJQn+VLEz!b)U4b&G=weaCf?z0&Bg4c{7$Wn| zgJ4F7F&-ku6o^F;BZt-FO9Ef?FDB0}5tIhIDlY9zVdBz)U~vSy3cfH`xUAyRio)<$ zOmHlz!mb&Ne$PZODcE)7%tR0@>R4Fpki|XH82Ac>K{JXN5Q|J!A!|zDGUP=dW58D& zfiLAaj1hxi@QOng7OO0UsAdL^DOAB~Xe$U7hogX4SHysr3abCmo%BAY`>Lm@%F0oP z#2I`l?OWR6bmx-(3I~6!FRP}0&$|Cb+CSabE7u+T6;HSQ{#q_9VJdWCSy^F4*+NiD zAQ~0SAEiZQ_TqAL9yJ5RrR?os&YoUWRkVPoi3w1jYrl8A{jb?YZ)MEem2qiJ^t>)} z3iKRD2%1sgIbGqG7z_bN%oc1e87E$XrV^SX72*A+uNmksf`!6oS*L6c7Tk8j}*5C>0eXa9xZ0_J7a z^AvFCxN4S<9^!Y?5bvAM^8dk5uRHnsp6!magB}PScPQjMBk24tc8g%2#PIXYUk<2j zo?H%@*@YYqpVE|YZo{bAC$cU+GIrhvmsNi9=RdA~_CIU?_|Gl&d)j7PYZP4FQLx0A zct!K<<+VTf#i?grYTdG}bH|>#-FsV)A8DyQ(b3$aLMG=$AOf6Kf1f?x< z7z)c^vFKu@h?N`$!J>NFln zzOp;%N+V!)w{Mo=Kd!@Xd`IZm`tSJudB}*Hhk52ncoSaGYL3%5;hN?Y5oOHX$_v*5<0CVeDbOA@rUB4 z>`a}xb@akd&M*G-SHJ)8`4=}o^UCI*KYsX@`xRxW1;n@l1#6+R#KdQqx_a#-Lsws!F)KS&KnK`N*)%d_A&PScEtJjfcrNp`Bz$L03 zOEpz4ja!aNR+$Plo-*j`m!R*wEHD_Lk~xs;Ofg(YQ+N-Egjfn~K2$VKMHhh->YbJV!hZbBSD zJ1$Q-r(aO`g9{6PG<(q<7cTnA?1ewOVE+9V&i~bg^L{gP?yu7?eItEwbJDV|n2MH| z#YQ5le-zhwGe>?6-vT3eOub9kKZXX~?H2ujYwQCa zVZR*~@=MRqN4%qd`8~g@&URny;$t7;xjZ1@Ro|@Ulu0|rOnojj@ApFkfBv1o-wzM| zwP(mrh6dl`5%4ox$Q>j6@A{tY`z}5|9csJ%?7*M6M?W5z^JT^_}f`m(^1@6UanVyU2K z#pf*L=q>0qrCe3RkrF{LDJGM;NzwQq82*|M3}0~t4q6x$EbCZ;V2qj4yfesQw6L&P zM=(KqeQ4N1UcoMfgcnH3;^-!$!xEH64r8!bg3@SV#)tv2IaTWkbFvnr!)RgA#e!o% zOn@5f!e5At{*}-)jxwPzSrx3d@E1``iAZBoKrBL7904&UIGC_lIb|i%BUVi}=NWG9Xq#Y}7HD7a>egT39Sf zS){S(VzjX8C;jy?y}wBvRie6|Dmi0EH6@PTj(*6wTraWs>O@seiSh^UsCM+zRpDUT zQI-31^hTtPUZVS|1-)Kn&iJCSva(4P{~ooxoA`6avTi6G!FGq0#>g@wV$v?xQ6D4}HpVSFl~C9eIHS%# ztI;>T!IpK{Z{!AB)So=Vetu5aug?zum3zpeE|I?)9`WGN@ZSyz`q>cMl`giWL)}(< z*ZY>C!7B@Z`02)_RA%U(%Gwe(oM_YUCeow?6ymI``Se9lsia|`+*dH%EqC?0c3i>AOXihk=3eI#e9H*WYet-1zB`*>fHfZ+idCE!m`&# zXK#s_^8Uz~>zA*1?EByU$3wq;^|8lZ{owr_8#f+ayW!}k8>%<1Ke~Nu&5mugq`S5^ zAb$7lYCp2iIDVk}TYi7XliMd@!yX2?oPH%a_lqs?Nq$_2(MzU z+^Rft)Y8(zcP8+K1&nMW@z8pxKbd(Yk!PZ{efE<9`qh~ovV2A?eNxZ%*S>sR$Wgt1 ze?Bb6pfF)}!qJk-pfEo_h`_^N-VKc3B=A>2%uf{Luqa~QF#)l}rGYO$V|XXwFE|zo zlY(6_(ZBc<;*;{ulT|Fn5fH;-3{eb@fiebsVKH)8D2xP#!WjA&Q7kF^g~AvVMhiT!FudkqSFu==2{H+LS7^=4k^qP1QVCW1j@iy_=`YB9V32Wu0WZT5_*oMt5BkM zDoe*xl`UP)lBJq+i8@yuwKPuFa>$Z(uHRpYel6uo`zq_~sMh3=s;?YNd7mxlg{ncl z1y!imwD_uya-@P}^~%mA`qBP;)vU$ouf8g`)IZ&rExU3^-sgbbEh+opi?n`Vy95VT&$H>hd2^(BvHn~J@8XmRI zE&3y$(07Li{Mt3>@4m4cJQFs#M(uNn*zFa)$s=xyN8|?A@ISf*-gl1gO=o*wG2HEX z-|z}s$TeQUmwj*OoFT4rhMaTJ5V!e5d=`%gxN}7Ky>4Om4iEfgQ1*Lqb30=$Gh$}7 zcxP@I9=m#I_aeRo~GarkiK-aWMk4>TM()OzGl z+wp@PCy#cWI$_k;b~iP4x3+e-wskePwlVn%_9(tj2kre={aP+fOHN6m@SI0{e1nXLu z*Nzqj!OY9TctbEKY%1X!&7GAngs?d<{6lkpB~&mJ2EmXQlWEehSXactU*s@_I)8=2 zq&kH~5tGU^E&hQ3F>;ucA4`~w6a!-Z`G`v+jb)4&IShPJ#DEw@j0uG)6j2O|)eLF@ zu^^aKh3bg|B20DwtMY4TXlR~||bBTWROZU}X;haI^`sw!Ji{Jz4ZPho@JGYLABmoM zAab4&cu^O-CC1F{@*jVASo9i~(09FJKJbit&o%a~5%F(DkNxxXIXC4@|C`_Fwcgol zY#BS#X1%`r@_TRm{;z*>@8b_Y^6Xz9XIY_l)~(yKcmK(qd#m^DKhfCS&6<-94Q(~G z4NXlQpthmDgE3$8uePJ^RC{AXXIq=m!G^&dOovAK8lTO7?*8@;{VEBJ1B)e#1B-d) zk#Ar`7J`ciDkzbWU*HRU(1Re!!rwFNW`pdRdJp830j?!A`%9fKXQ`8Sqr-w=gfJ%IXado^X{7vafx?(RIt-L`93yp=IrCSQ0AkU?l7e7|4mSUd z5W@HlDQw25p)f>74ilZmF{9FsxHJfc$fN|NF?6x882)15SWE{o(imL~g3a*sOXkx| zn2Jd2j`)DMm&w+>5fzA)BOvY-#Q*hw6^_<%417f$_bOxa|4u{fjzrJ*s5 zmN2zInTgX786k{AiYV5Fu#65<2zmJ-iaB>V={c&y4AOCKhZ8NGP|x<)tfd`Gw!gE! zc)5Ndxlg@K{V3&@tX{J}Uq8jU{r=8!F4x;pNBb;PN55R>i`;yFcfyxaad8E~=hE_p z<|r@$n6d@)%k6W^uE|_+B=AZj^76LiW$irbo4UlD1s#8RYw{KCahJ8bCLJ6ezI#M8 zTm9}p-g-u?ACa^_dEDx_tbcmOt~w`X_gRsxd`r+my_z;20~T*E$szb;Yte<$eY zXZ!vzZq%~4tXn+e|Km0CwV>!%h6g?28TF2L^r!Ce>xYN^VTjB1-}PK+%Xl&7vZl}l zM(Esjwv7mx+ZAzPYw-A^=5E4KAGk)n4S!wY-t>xHoi+Nev*#|KeExm$S?iMWKb&25 z_qA8vanlce_S1VAPr`~$$`S(_Tz^0`~4cwuagSK=$2>fm3uLZuk{%vb(ILEmf_eEuVbQ{BTo@HhP#Ody zgrP9x<$aS0TBaCw$YI`085)*3TD-kzVGKu!Usx>6l~kcw$|)2R90Omn{7Zpj(ZW!e zSTqzSMGIpHVPeq;VH|WZK8hG3lR{z9!tfUdEiAfN2QfZB#xOuE2v%|!MJz^%6arsB zEQT+-SW+d5B@2b&uY{~|{)@iaLR+d_K&*>m-4`M&U98{>b_KqaKwgXzOjrzp304b; zNntUfn4q+b3v&nuMJ(gLmM-+=X8Y`r&V5o{)N;s@Rn@+9$8w?5%AUc^SlT~>7QU%d zzKT2NE685KgTr5)k+Clo@|qRC4v4`PW5fKYLExZkM>dZjn0xv}@cpHve@G z|7dv7U)@6f*MZ@3ogd{_wrcn>X%-zekUpI(ee0 zwWR}|n%M2=AO&7MD{piVZKl)|ypWf{Us4Bx9sG5ON<})Iao@PF?n(qN_hY^$#|`sq zpKoct($QI{HoyT*APXbE@E7zTej$;7N#Tk9_EmH_`S@5`wq(!XBWB*K!#?+1^#XB3 z3-j7#Tv%yg#)Wxjcz-a0(lRv6n+A*Jd13S~IOd&Xf;8e+jG#2J1%xmx79S8pVFJ;Z zU>COP{MCI9Vf-6OiUWedF)6WVSS$f*VKEd|a+rTy;A_s%dh$s|he0qYrTg+g9ftPm`6SXiuxEQL@Q{sLT`!opvj z!V;_&QLI?3G_oLAaI7c{ktq=n16;DAmjN+_!eS`=x&6daL3JBdZYddL_fw}^98RZ% zHl=4 zrMFzNXlYQ&Q{K^Uy2Za3l)F1%`th?zuCXPr;Vk!rb++WU0!FWizr+Y;d5}wuxH;W1 zvyJ$#v85_ zF$jjm09R)*s8w7RU-*kJa#&Ij418fRAVv<8MGiAx8VZABQkgZ45EexYkwGvxhRecY z;?kJR&H~L6k%r59XxgEP%>)eh>R{_0Og&1t_kVrjSoo`g(qu8kV&w>e6_<4ogIzrf zkrjx6FNes2V@V;e0yI8QR&p5r!eTKYG89G>L*&!#TB^S4KdR(Qair_gxU^=;p4la6 zMA{kPbX7rJTCc2*>UX7A7{EWXH_E)@Ga6tW;7-2uLw&wigSm>lIz25fUd-~9_NsY2 z4a{mBHdZ2YhmN+LG6gNZv3a`Xi5#tAnN-4!_6uYBCPfYle2Gh&&ksLg zK0yqTF$RdCFeVg6AR~cA6pN#SSVXbJrOmNnhe;MFD=jQeFNdwVSeUB^s}**I%Ty3Y zm4jnUVOJcLRni#jD%y%7CMzH&3wfmw*^5D55x)Xrd>lrHVX<>p9GDlXU+L9Up>u1e zTOv)V##Q!o+tKUOh-ycC=Ty~KmsTY>a=I$9WL0^ePM;0-SyL~RJJd_QZT^|PF3#%n zg_sW&msD2Si>oRYE-Jiw(#$6!GIyO5)9xDEeO6e9dt{eenh|_qM_Oeo@#nb9nFQ6~ znRMJM=D02QSk~1>+Dc>8l`KNlIAT=I@XTtr)cwIJhXO|K9+AA-CHYOyxL1eAzwMLw zN<)0iH-_DdCe#N^Iu$VaWMDp9HMJDX{c}n2 z;>*j5mn^=jYUxer-@ATt{~sU!`#+xk&#JfH{$$;z4V!mt+qrM|uEWQU*45NB@>f^i z%q%PxnS{TsElhRp0JSO*Eg)8kSfJ(ro4GZE1%KaoR)8xMmbAIKnXe|kmJv;S$rB?5 z5DfdG;F#`9d=n(Sa3{M zg4F_LQdQ0&vKWqVSw<5`(Zv`JI7SEq;zu5N1O!V^8X^mh85+hUK#c>4iHeXa{wf5+ zUrbc6V3$;hV!^IHMl1*xA*|yV_)4Lous~VqVjKluaRkAVI+Irr%u#47KB&c~CMmL4 zlrM#Jdwd*Hmr9|3P{u$qu*JhIz0s@pB9eOP$+uo%N)Q!VpS9!8%M&hf!BVQVx`1U!mt43zu z$2uV_0#a49I4JW8SHF8)J#HChyY4LC>sh8Fe8OhG8BOjZ4+rMeMV;3f%_hZ{c1E&c z;#>xQjS!|lU&4ll?d)?DJh_ft4kIQsMvrR_8`~Z}tu}t@_Dc$HUdB=-Ri%romR+%w zZ_1m0@{^zc?stED>Z#}6c;mg*t9eL&*Up{$ckNE(T%t}5t9DYRr&wJ*_8H?JIpU>vltK0AwFEc|rAcn^6e z;jjFjA*7(@XvrLD_$vrT4(kzVSPY0sMGgy&p{k&k)PdQagz`R(!xEQ95d&X-UlESR zK(GX;@u4t3y#&5Qr*TNp!Vno3>T1jAMBI_VlXoj<3SEba^MKK6grUWwlRqB|dV3!gJM_am{k z!FgkUSzJ-FpuA{KX{jy#2WR`NILG^H7UdY?d7~}w`NYc_*nrq)RIN+$5zp)s;pcY5 zfZ&U}_+$Qa#AWQ3*cmddF>pd%z~lzM$qoKf>jNAh4xZSUchNHoidL|ANI8pLS1w+@ z^qQ47-+Jd=_dM|6Lw|kZA1}T9+6Nzgymi~IeftjsU;YjsK5?q1v7xR71Os1F0yne) zU$$M)7Tj<=cBJSl!ROuq)^D7`+?UQ`?nfb*avrz|zd zd-;Wf$+$2P z>Rn&F6Y8zetR<^1^bI=l8lBVrZb{YbuY#pq>RSr?gPo;XpILPSeYV`^DT66I-CN@7 zgK2h=t}&9Abo=JD`sTC!Uz6A97T>(~;QaQ0tQ!AO2i;=VGdVdR z<(ZK5f2ECk?ED#b&s$J2apsDoG1qwoUUQcFHJ%~&jtKgdTiP=*i%zglB8YcOIpLO4 z?VftVJ)_!pTwTZ~ruY>Eqkp?PO{j^9*t8(;>!+~u4N$_sH7WPW{owHABj2uwAilKu zp68pNVM@ZJ@IonH-X-7*T%>zjI!1rpX)x8K!NIg}x|bfz)%&~d=a#FRu{estqJ=>) z#t#@M%$q4%n4mPq+sm7bsf9ZLF+u6uZ#UPG#`uR|Xc+zqf)#~TP#RGTi~SSU<%8U%x5te3{7I>taS zB{-%e?ll;VE|yeStU#<3u_YpH2~Dd2wZPXI%EDz*4D5=DulOsDP*|nHUx+L$Cad=) z^)LRpout1CdTZ3NWcxeo>nvBV(c<)X52{*!6)fdv{F3EDme$Cs8|bfs^C@4v#PTZC zJ$&(&r3L5qSs19WxY$%d_R=DI*_`F~q~6&!?ng$#BExgEVaqW5a$9WK9bOrRcSg5Q zMtA1q_w40G3+z`GEZ>)QgOPr1XIxQtNKUs;UbEkrHd{`se@=&gPBRZEc_r?3i{9d& zzAAmveUr|+eC&*p#LR2FVy_+%uyTa$s^MPOdj#GyBH&@Kq*d{AYokhy=tV}rlxEMY zlb)kadZbi)j6Cj@e!?%mKJ47K$cwr|nR#_?bI8O~5fd9C#y5o(G)GKqj-1%!JFPBb z=KIKM_Jt}ct1PJ~udJ$Aarv^9H+}z(+wZ#nm%n=K&wqX4`IkR#d`0|zS-op8?dUyF@812D_t&OgU)AZeP>%L_sLw*x znmUncio)`Yk^{n~7M9srgrkMOyvZ1HSi;f7r7dNa3C> zmY}VS1uGWgDEKNCgJ9rGxf~@cleHu+4UWZOnik<`2ZtZVK?q~8m;f~trng{lS>{WF zV}jBsVjNNjlY1s^5tkMaJ0NUQ7}{bGSVXa)*fC?vOq3!P{tAv2lwmRamDB=aMP3V$ z;WCFr3!4mfn83Q1#^(Q>S*(OGhd?kO*8l18#Vr5ygU@ohUfGh>4}DX9&ntBL-{;O$ z*0%Ipjg0FIk8v$t86Cbk%|2P}KADE^Xv1%Gd+eCw%$8nQRXXj;HCZ<`B(7|aC~6DM zZSou46fmaEFQ*O1Gp+hNA?sbDHuxlMagE*Y9`la7-yhELSaFWmva|fk-2Jce^uB(G z?+wGl?{kg+SLB5UqYJyD78v2P+k&SzFud!NbHXeAxGnvpExpD)t=e;RZQ#V#;8~4< zQ%{CWJ`pjwK4d}zQRtw_Cqt$kg~+q!J;<&Ti+OmtoMl8R$`_Yib@`I3ue#<(KfLY1 z2Y&VVV}E)6xfeco|HDliH}BrHhYe7OxShr{iW;l5GMD?J95LtY~^UcpNCDII~1}qS6 z0$%}&bAQvj$5-L&Jy5PLC4(tf_ai5&ta9{5RG~P19_q7DKT$5Er>I~N!n}>JnD>)d zw1lIfFu!mBF$g9W&D#!z`{XY_iZDRTKM+A_0@3_q35EH|1bH!W1hr&!{wm-Kk<}q_ zAhK{7_<~@}3{3ZKeJF|;A|sGNF#N@UF9B+R>p*eO05KGnpfnWbQDQN)u*}+$xU^uG zR7^lDP$q@H!eRyDK6SAL!LWFM=(O-xn5(D4Vx7XuS1MR>S@^5|_0_+x{!g#EjU078 zq?f3s)LHt`!Tah?EDa96h5l;lE$e=N^;NlEd60LdPU*7|RfwZ%s+LuWUhS*%Etiw5 zx}4>xDnDa~2K95zER(Ow%NJJ_vd2=Pz3kGerBiP`p7BE?^ZT7%lUi(Lu5Z-;9WU>Fk(Sheba;M*1!(FDopsvZH^OExz`e>u$g84*2`WKm6&Lr=NZA-S^?|UiRfaaPaWaV@Hoy z3xBJR*VLS>1HmoLtxSQIKlsaB=yr#h4<$KFDD2E%Vc*wDUUe<~(sgxp%<$y9l&~`~ zNxstgZYS&v1;7FDg%RjAnR6x29EteVyM*rR{lwWhT+O*euk1Lr=XB-w>FDj~ z6`afU65W@x1}@Q$imzWwe0l3g1;m12k;A;h{K63}EC@yj17af5{3`%rhKBhUk%yJk z(D3cO`z!HJh5=%wg(0$#7qE&c39LID0=O83q!NyH6qs_DtfYXLUuC2q7?VgfL21Z~ zp^Kp~iWq~!z*oZ5AQ)d%FsY(24lEW$tXK?%k;bBkVKMN`Y-wz%DF?!s3erR{cT$C$@9|{ZN0t>L>cS{Z$^IT(zU>=nXpi zs+z@duIb#e<&@LP_Se3poHq3m{Sx~9^jF7nx?auV>n-cPrJBlGT2`m13KmBy=!MQD z`q6=X=c}{$Mj`W-*y6C9A>hjSr6qH2dVa#4t$DW_!Ltm%EWnB|La`03mcw)ET*fyVWZ2<)xp_4lU@=tlB?;jq&$riVB zc+wt^xP7jXF9oJ;wx#a&PTA$1dL(ev?x<;Xar2EZp76cQ2%Fl>enufv>PYzuozxI8 z{*-U-Nsm#-pfHoNOumn)4VrM$Z$gdV_=ey~ZBY{%5+>EmyyOu=&uq(B$~LcMY?NGS zud2Lq=`#3>{=NT~4?OzFAO8K+)9<|f?uPXn_w3#){5^8)`0-=a)yGf3-(CbaG&MHE zU*K!W+yGbP-dNt5uOPlT`BLRen6Gi*>zE2;PI#8EGw{_T z&-8@T;%^^4XTYu|y|m9%ou`gcqWnG`b&92?bGcrk`_im)iMpJANcrlha%9Auw+;t` z!XOyKQ52SOVT7>AVS*3*D>z1mdzP{k5EGivDU1-t_=n@44+NVqc1+MR#c;3na=2&H zL$VxEN*SLLI)GGD_~!Q*2$q>zB8urJC}JTpKiCLO3y38sO>|l!(lTEQA8CvMVsI>S z7!{0xVCF~@lm@|=M5jdy3y6ituo#2Ff?y?wRaQY+&@8FKu`ZBdt_WlhEDk*%UrazO z6qb|{;H#&?V$~nizpN@5;9uWTnXFV+j>6{#a7dVS|Q{nhO6to~ZC)VE}v??kU4K6O+fJ|BOTJuOFXhZD(GRF)T3nB*-g zS#WhZLEPet7q1+*a$D|g1}k9rW*dH)jOTVSu*;-quZ-@G>`opd!brPEj& z+XFIogI^-%4$T`hxrsma^9`HS6gssb*zp%Iw$>-J+ILj7OUiNPWqG8T zL&JVqM-wJ*&piK?ahE<`RB|;N9<$Ri6b8YlU>483V%c)O`uLXPtBLOxeyj8GA$$YD$vlw<11b_ntUywoP!K4?7qq>l#d#G~hDk@90K5I((=cbl+ zR8#tia>f1*S&mABa=L2V;y54GFW2W$y#-a7cTA>GN(osBM}uHu(WF9Qd}0o~^ZXMi z{t}MHL<{q;!@m(D!pPytd9``UmeFVS8%L@7+;K!xdp*w0Wsy00$&^?F#ovf-?YzvXmwN^ zy^h6quF&VX6w1dMYePj-|4y)1RZC+h5Cio6hz1lK!r8 z2IZ<*b#=WFj_TPyeQ7}*vScY&ml)VlEvQqZL~jsZeQ8+w0Lsy1Ioltx{uK`(;a4oJ zT)bk!jax^Sb&SaF^2sm)vy6belW8+nT{Q1*Ib9l;l*>_=e%{ugnTGF7BlM!qsPl}7 zSzW;wbj21l_$BW@D{TXtGPp+n+mi*ak~h1ht@Tgd<(j@NVNQ4Kd?Vnz_TVYa;S(ER zZoo7%4V?;$8v`db2Tf^)!a)Ufe%W;%BTu-b*Z3wMch5fIH?A>m%C?IaUccD>*}J4( zJ_B=v0r}qJD-JaQmH4jU^Ul);+qP}nzwf}2!$*6?FZ%Zc{)y_7I44ikoT{yBY+!Zh z9u+J?SP(2Y7WOF$D@P9nf2BB9vX`qgHa7C30+Ax{<@=T|ZAKMk%(p+~Yv};eThzNJ zS@kcgvZ~r39o2%~Rq*xG)gcO%KS)Q~>94_o8&T&vSJQ8=KVLtKI!Xo8@i6$yuN`91 zVjx(?h511!Dwv2g4j`7HVS1?`__o{3wX^WevEd*8`1adx7yc>)OI%tgESeXL3Ro3< z1+VPECz@%MuagwEJ$O>ixB3ADRcRkx?X7U)hT*q~;o%OUssBvi!%nMW6bOt4W)*@q&vVSY*GlxZK<#Np&H;eF|q4{U&?%Zpa&b zo)I<62%lvH%r+ut7@>J5+>?*mf}i&ef5tWKWA~KREb{C&a;N2#sd$`@J)gz&7|TPHdO0#KcZg zl`l>OryR%5hd3|gIJQ67DW~iYjtc`WAU1EZ3`jx}pcjM&32D&H?>YauOH18*@AEw8 zoI5iDx=!u0diCnny?b}}zt`&C`}x@Ozx@-pKlrg1y!!Dkd*Jaeec^*;WB2Y&NQU;E*^Ui~5OG~Mz?-v69$_{5jI^tUj-;SK-lHE;Z%E?m5N?czDN zUo}C9ngdOJ@R$8-?lO&-84PWQF1!_M3;37c_kJ6|1;N2z5bO^Gf8@g-{n)Sn#&14u zGx$?>f!V^4m*wjkqc~P@$H4&Z%-IKs%a~2}Qi9*J;}6ka{Ka21N3l&9FC2;HVT%oO zIPf*M+kaeiJIDU*eP*W9o@vb9ytCv6r?QuZa5_IpQG$O^s9Yf`daRO?kK_=o?8RRs zx|q%{XxM~!q@geq*cJE+7KHjFi@0oIC>#jRHU0|V%MiAL@*EK$_{b;yq(uyW1HsH; z0R$J?!d7&ydP0yl#140lQX`P4Yk>F$2=Cq_2EKq8!48f^43R;w5hMU*5NwZFU$pGG{xmy(AA0CTvTSqa)Ra>oflJ2 z$*ejQ5rsqapi=g%aKvWKRdg5VI?WY5SK;sFD?23K;qSRik34eu?Qgku{_=nJofrPx z!x!Gcx%=qFYu7Gbe%pmddfrZ-d-S1i{ocRxRd0UcD_*xd$$Zxz{nYK>{=}Dj+x4&h z7B3FJ_xIoNxBkEj{_%hGqJR7QU-%=>`9nYTg)jQ?+wT7VzU-Snc-QMc>I2S>G~3LD zzdmer=j(s@d9VKD?GJq7wpV}1Ip;6A|C7FR<}FAjTIae=8Lu+ zymLq22ti@62!HWzc&2wBjxG%C5VK<#vI& zCMDCwO2a@b%D53t4T1&DE@=Ol!(|8`0rKwiS%F~t!VKZyueFnqP2u1#2o^kCJ(+VO z!KyMq?9u1x2Z%fDhAzylXrXhG${a=<*}=Q>T9$JO@lJD43xJp*EU<_{Ff2B#;+l4i zMI7r`&jh{}y};MCa2X0ShoP{+7^gJA4d%MCg^yyN{nq6G#1#d*J(M{-*upn3`N`AN zLE!@8{xs{kcjo?dvUmAXI1pWCrc1bzaEe|ejujYkmHY`tT&kChp$FwpW3=uobr_<( zVv9+giB9ObW_nv@NbS*~<@ukb@8dVWeB{j+{_0o1{gYq*&G7g7mw(Ik7kujzc7gAB{YRg5|GU26g+F%di{A6B zuYd1tcmLe;zW!aeeBHnOeJ}j+FTVTTx4rULc$mNBHNOdb9lL_Rx4h=Vcf98D=Rf%I z7dQ+3>c{Vd#jkn%me+jr1rL1mj#oc%`|F?hiU)t~kw?D&+9N#bSKqRG<><*z7N?0s zO?pfZ<_07(O$C3AZuYNFGQR6w?|RRB-t&PEeBgs0bO!5Je)T9gzcd6G_u&tJ*zXtc z@iKvfwqQ4OP#E$Ce1pFoC}$Ym=E!@j5@kL9_~U*+&Gcm&jM;12G#j&+m`?sK8lMG=%%n%kV5j`xyQ?pi#A#4Q&f@28(<)Z+OL9j=h(^;;tIQUyA3{{1I zETRnFaC-De@UuI}We$@pTR1?>5VpFDEgT?b1w-L}Qp*Yu9K&MB%OZx$z*hjr*(OHt zNDFaCyH*qsC+N?JSj5IDLwE>~H^y%uxT1x^QiH<92^NFk0hAfV0pkAD(0QN(bN}d^ zeeNN%%>Me1mDKBwl_8)G5!+Kf!j(%j8E@*nq|k$|y@oOl(XMJS39}jmozQd5^tO!D zISY$62rp^gF)v(t>$N}q zRX^~dJ74GE^k=^Gwb$=@?Qh-jswZ|QqF?^0=iK*O&-%Kb^TN?BcmMS5FS~xreNVjL z6~A%kD?Wbf{f|HAmA`rWD?j1nm2XQv@4=5jTkdE!@AJRuBe%ciL$^Hm8@Imt6Mk{{ zD_`~TFMaUS&wI^pf6asc;jyb1u3fzJ-RH0Q3|DR^caa-}zot9$n`w>V0HMqn2EL;g zKlzhC=?K;@{n9TD_**Cpb_H0B1D%7>P#Ew5-?*S-5Tk|QFZ4`^eYy>`LuxV(%tR#> z@zIZd6!MyR*cv87v!dw{@|unR^3hKU0^e--y73?{%PZhp_`BF8I&<;ic7a3bdM?R0 z>mLO6*FUS0cagbP^!{aa$yB(mJqexRlWPp&n82={g(nge_Kf0=&H=eNrE>+uf~N_H z8O5+ThOnm$f)mOd2E_V6xub)vv4{(f1Hs2$J8H)}4UY9O*EpqF#MvFz{oJXjfXU^Oplx*nPNTPf#b-R>GmHpDW%U3U)|Ne{T9}~H7;h`(%zW3@Q4_|%jQS5WT zJ)Fyznah9jYc9X<)>nM`wpV}Zxv#i>%l%J0`(@r2{>-f}`OIw(JpP=o{)t;Bbq?*G&myyE(uuXy5)SNbKv&)ojN_1hl!Z4PJOlYH(2zwYq!oezBcwg*4*oY#K% zc@KQ*55MYD_q^`s?*EQ|^c8RTe_rsqAHU`9cYpcaKXT#WOYHHtUbt-kcjynIndsPn z@CZCv!9Gca*~0NigW!a}@>h1|u&1vN@JO?Q69U9&5G-^EE)%#LyfY}vl3Wq9 zb`2KCB6ijH3@9O8kwwe|4iNKE1K(~P8+RshL^_3Yd939_sy z>@``FIVE3HY_!IZG(`6)I<3)fWLMtj&R1Q}MpDG0Dq^AMB1jSlKe_mGFEeE?oPYGu z?|$scc|VGD{;k(8pL_J$`D@-$>J=F1OH9(Y{^^%|_s`yS?-O74vM26%>1UqjMd15> z>#kRP=8IqY$y;9WtG9mDzr6K@|M;$#{g3y4=RbYn13T0Bt_QB)_2Bh8UgNWqpLyN` zpT6sxKEV-uU0$|40AxZ+P+F{DQCiSGT_CXK(wO z_uO^&&wj_7|H30z9=Uk_+_ftYsYca5_ma8Jv}P(ZQ<+c936|W(?~nY*kL-?M{lYIm zRoGho=OC|Zh@i04;O~3i`(9bz{qA>r(+3nYhka=(=dwWX&If%IPGI~NGzWGoiePao z&Ym@YooUTP$LL^>m=bT8LGN^Q)-3Hd)dKskh~Jz_5F_^9D8*agbqm=)YZ9oaIF1HnP$Sj4%;{tfaL-4PiLg;~LQ z+@~KD`}C{ob#o_4QVH}88%cxYcJ!z* zRvTn!s3E$jISMN&H`Q-#5GctI#}<(rkCLuD{LgB;;d3Tw5f6N?T)ODbdFjg+ePiS5 zTd%^o^WF>Qg}!#->Sr^4F7>c)PhB|ovWNcum%jQvU-Q5(f9Zoi`xW2v?_TtpcRl}s zPu=m&*Pr{!Pkg~w{@?%6ANr?X{*wRt;4*GM@N@3@4|jg!`)+;7FMQEU-uH@c z`683P-R{+Cm7vED;Mv&Sx+UeEF+`zkJs}{nJ0qf=1v2=#PEuV=Uqu2)sLp)iHEW8u&&M!O#5jKmYTN zSE;ZaG!q)wHQkx|Opm5nv#wwsHb1+;fNwT@&F5xyp(gzCS+_@)j?oyOLrVRe_(>z_ zc$HgpyWEmImKbU{MCa@g80s^N?aAqSw(qDU5m^y=I!s`XDTc7829C3KViDU8_Dlsv zF*=*Vv4xq#d0B}^T3`#qU)R{ePQMof!`z_o&I~>Z!PeNe1J2IT$^wFA5rWPkbj2WY zY+>LFc>%F2*cIS!9Mn!JAa-ZA{`TM2nJpu;K@5DsFgw><3Ypo@Wp@so|peGuYdht^FH#I zzxv0Y{gPk2{qFbPa`$@?FM7rQ`{t{c-*)-osu&`*Ma2Gvzh*Gg6r;d|V1OHUj$rw1 zpnvZ-fZy{T*a~5Vg5XZTR!J~A_zSWFzRYI`PDujVwk$)H7}U;Tt>9^)YN0SrcT3*n1k?|&OWY(EM56&=w3wW8ERYn{fScBZ!Na~e+7?52nvH>jtf0j zU<+sK#ML8qjXN45$K7G+g*Zaszm(nKKyaZjAhu4^XX1zknrK%zi*VJWgc)|pB=n@t zNya0Cc=we{Vy;kFFJ%jZ+F)_q(E(-MnCm9?Z`{!iYw<#d1A^Je;8?d8fUgiBW&)!@ zuqYb%##4=8>avl6GVlegqG1M+1GV87A{$u&Ws`s;^xC5w9(_gg?B;9ql-Oc)t*mDP zf4-w|>PAZ7X4kd~LY%&=u5E)}E2y%p2^`8Vg#)pshgc<57Mx5h;gmq}xvrh!a(w#X z^HvdBNQPUbQf=ck0r_P*X5-`k-JNWAeR^cy@72<8~ z;ETo&{&G08e`N{&0$dt?;wOH>o~&O{E(2BLBv1l)`Gl)&pC6u zYnlbopV4V(3g_&dnG#E;Ct(iJ65F2`^zWZ>Te5(%i=Do%Ow(L(|WG*=L^j((68V`33h~|HAwH;=^y>^M?QV-1)bC%Ul1eFL?2k{!! z2a977!(R)wtl0v=XhgP#U4z1aI8J6)1EkF1C$aYEUj#ZQbbvVPLs#I7Qv{0`T^?ym zU#m*j5NM-7pEm>o!A1eXND+d<28*#{QED6+vk-Y_6(7Ay42W^Krg^Fn0u*)y!LGnJ zrf~>HZZOvs;JSvuhr(-pY<^6=-}a{&T54ymsV)9N!j^ThN2Vn$D~P#PtDo^@m)6 zuV9guby_^qu595T?{G#-HwzXAUIWAd(-~@m&NDw8sX^Y3$iZKoT!?p?Q(DmZL9J21 z1Qulx8z4A{qXp>>jv+4;j$I6P(NLI;Y)nC3SBMOGC4u08uMrmrM&Oh=99!6sLK*rd=8Il({n;=5^z&cx z$y-41z1Q!&=Q_@v_x#$oJp30a^hwM=_U3nf&s+Wzhru3s`4p zl}9shs-fyR4n)ZpL7?b8i6KixtE{f4Qakfxbm?G)E9Hn}45uEVu8ZT! zts&$=d+3G2dV-G41ZEn;-}DfmoC8|A4OfX?6gUp@#v{$0BIt4nx?hktS9rP&wTlp( zECJtKiRtaoJPS*N{*Q*m)||{7xK`ji4Yef<+v27)OA@h8Q3Y z1T%^OG2{ixP#7Vwg@d^va)rNO*C2Hb9QS82(EXW8>Q8Er+(_+8&~wIcN^DKwZ247O zRjG42JydT``MI`TXQ$UBi(kUU2@(Fl+&@}s2R+3fR26?92C-wKL-u{5rL%;KgBY2+ zU;n#u^moZFu)j+eS*JeS@z}$cAAa52{^g5);QH6T?fMH|`q4Y?{m8TL{WT`=ZTEfn z_Lu+K9ryq0ox7h8zJ9CC-`)Q2^)J5vlegdf@h`mp#zHs$nzxaFf?ds3=ZBsOv|no7$)s{9HDc~bE%|-Cw27fy1-1=!%dUUO1i)z-LphV#Clnk zv6#h4mO)8RU876YK&;7ke$UeR`_R3r(KF}j`b$2{g5VVm+$l-cFO3ixpO+5f@ThWF{?5-MW2|6+Ma#p z^wg8lbLFFFjeoLI=3J$JAZE#`PbF2B;vm8-PIh~rlx+A5CoWyPc<-P5ci;G@Kl#-c zKK0!De&yDeedKxff9Maq^4Fhz|A%kA?_+*j;nsVfca#v@OL=8fFQuHuH?dzbVeVS2zn~xe6@_dSJYmJY93l#?)$iH`6SuClhb%punza z*$oD2`(2}F{M9!2PqtATBjFF(d$h8YWD$c{*I&6JQ_)_KKcNPp@G# zbPnZ%+Vhvs`Q4=5fv78&T&whRk6gQa`Okda4}SEXKXv`CH-GAjUh#o1y6@NTeCdau zckhSpc*(Cm_oW}c_2r*@*2{nUi|^g-{67EQ>o0iV`U}46x1M{?ul&bf|I1(fs(i#tR6C{%HXOk9u)qM4C`zx-XsEUaX- z+Qa2fX4L{;CNP{Wzzr=L4qUcPEMyDVk!IL!2O0QsJ_BE#=N$8Z?1s5{AQOnGhD~9j zW9Nch)u>5QtrFNTg6S0I3Wd4Z;WgO`=H7&|dG*iUMeD{j1GPMKtz7X z6`5V}&GatibC!X#sI9U``H*F1mXa>n>0~+RTG@N9V(v-ETau**r|2#)@Ou(E&Ff0c zRe#RYchx0y57(T*(|`0F$g4-8IZp(%<(xI1UI&OR|6GMYaIShLSBxt|I0p}czdCIP z(@qaS9FUDbB{6kzD2WvuK03QFR;0i;Sd1<>wqAw5u5cOJ#v-<0Ml*rIF%*Wp2@GMY zT!t`5Q>^0{%jJ<~6!TGo;3I2z_d>A%h+_^Lr*Ihl&JQb3s`vwu)cvo+7?F`ehy6lC zd1(_Z`m6{Q=yj+fQgosO677X{P6)cisB3$Dj2L*PXw*^}g$Oyz#eQ_)VYw@_T>7F|9xJ z@}K#(hyGLNul&ryTy6?VDLpmwRZxsC&OBoVfWHPNtc1Tgf@N1X_zPr%wnwP@OmKwKMQ(7f?lC}=qK41*3Ut3@K+y0Sm{Aw z_zQFOy(3Kivj{+}LmCm*gaSGcY=Meq4ujxab4Cl2;sj42DZ~t_x)x012ZCJ-h1Uog z0=}+sO}oNegT*zz=wNYZR~9i87K~qkcNz_pVKMv-3LDo3ovQ^lmCOPjptk%~`C^MwWM6z2H|8-gy28zU$&U z-|*1ic;HR{;OpP;lYj8R_ucl=-@NN(AOGrC{QQG&`JqQH{P8!x>A$(}P5;LqeDLwR zzT=5!zw$S~;ND-o{k~th_dEXa_g;R-)yr?Wc6n#)_EIWZ_gJYWt0U~%{qCE&$h2d+ zFp!N+D9LH;1tRuujzD)4coBaAF&V~kT+sZ_;M*3klUKF>Ymdq5+88(9*}ux-TQdup z*-UiI5cmsoO_c%{qM0*64TS*ilZNh%?Ol`Y(Y(8JHTO`rIS|zj13|1fLzbsKS`|ZV zS0<7rvmrkuCF91mbk0QOs-)t~M9B<9B#T)Yi-QlBKW9n0mlWMSCD9M1Phe= zoKD_o$oXeO-kRL{oDa?PVji>IrVgwUu$$R(FmJO|h^ZUQ?X&Jo_eR*C?oA}u5Zy0Q2%Y={Zkj~d6UZ8 zzg7oGUj1%om3J@dUcU0!mCKJ__TKJ8mmWQL?XmCngAP|5kbd-`^H+Q?>(NJc^U$N; zdEp0M^~S&Z(r@|aZ+PPm+fcrG@#rIy7vDa#!w{|d;CqOG%+v((Y>k;@ObCXpvB~cQ zF--h)rP=B_!`#?6KUmV6yG(8j5Y;d@ znkNIkg|n(%Gb&>4t94(9?bI&0O=}`yTV_r@L6%tw&Qak9SHQh@Z9}vt&2&nf`TKB& zyB?xvrJ-u*zCte+ln&rpeMUzTg2L%q)_6IW1%l(0hR6s#P_Pt?MeG^~4hp+kC_-VF zo2}uXumvQJz!4n?4tg3;A<80N#N3%#*$a6~2FH@M9Mpkhh-@73CJAU*95`kU7Z7tw z2bV!Gi#Von9MpD-1p}Y&E6D3Ai0Uo#so|lzZj!`O8i+Uq1JiOIP1? z;q8z5TJ-rV7cM{a$TdGTeA#ER`~dOQOON=u!}C|JzU9K7ICu4&mwX>R|8{`-)^pc} zTN|QvU*VgecCOxcyu;$(++rFre)91N6Mz0DrBkt+9i@N;IX!1m+1e4XRHj$qu!dOT($VsE%EnGbA)o&VelI z%;=b}CEV+__7n(9+6bj>Pa^dx;a-PgJ_Uq3I%O%_8jiiMw1aDP8-{SpXIq6JBzfv-*B`8lR- zXa31J^MgKH{U@u{+17!!RKv{{y;ds-vCJ&S)cYSMKoXwR~| zFXT&<%)HCju0U8vq~Ct=%J*Hk<`dAnUs<|v<>)ouOP9{Q?b@Y_Z`osXxuEp4n^&=_(qcjTm%G2@aF0i=@;QC11X3l@s$?Yg*dLV+-JqvnhfFcoavfBSn<`vY z?WJ_)({c+c(Cg6aHqh6uUS!q!bB5~L#Y=q7JGb-si{~z0Wf22n5POXm`huSmJh%IX z)|K-Ro4@+fJKlWpv9}zd_r;C<->OM<284OZT*TjNo-vu2F^pX6WJ8dx%5}_#TwkGt ztt{LDb}I^?yxV!=kf2s0K%bb7CD@cYm2bW=P;9H!Vg-l%LH?BW3VN76C zWuH0o1grkN0XLGm*s*lAQY80$c3tga^}4__gg*0n_D67ncI(Yj+1Dz$#_vi(r&hfe z#SnJYy9A3pL4OmVaH7FtOF_ZV&?jB9FI>m8^i@k%0T#Q){&f|yDa;U#FB*CdVFQ0F zsbDt*4IQat{NhLzg2k@!OGDuV!}-W2-kqIB3-DLSzHmV>6gCp`O%LNShOjGUf2?!! zo)sshl(u@lMO4yR5sR9`bgeKKm!#s07G1=^tf-Ei?8T`pAu6>C6tfF=fzCgcj<#dP z4i%^|+cS1%-NlJ(-ZdXfrxX?Fb*Nl(WgNRYfBDKeAI-RQ)sOc2dWN@yuUXw~sI{F@E{q%roW_ zo;0I1OJDY{eOnG>-?PdQXy6NE3vkO3jT63W?BBeF#CPotVn?t*Fje&muq|NkIPh+< zg6%^Y^=1R}2J|;^ndO)sWjtZ}_b0l}?Oc(ZuXC={E&N{3 zS+aB1?xJh!@`uug>T#!Y5uI7LMy&JaT%FT%6~D4e#hj}ee#y@S4GGDv7exjEbJM9@ zbuj&(6&xbq>uN*@WeWpeeKIdA!D3!$z0`PN2qS=R{L=AAvxN(Pd7;Z44T}?k#T`r+ zX{bu_2wk7NL@be_5gnQX#L(G*as|6Lpm^t@6g( z0A~vr1UrHSg>5|9Z?fbzIhd^24$N?Ko%+CEzCqPf|M|W;2i>D{vpf?xspNb;+q(6q zysf$V05Nnz&yuQk&LS=2%zw%rN3Ue3=PLDjMlx8OZ4Ltg0gGb@BXmFGf+1{asy7CU z^Nz49z|GMtgaC;3+xVps*0FlB^`tABV+R40gQwXV4rmsbib7{#T7Vmb4JR3kvky_W zFwE@%9E%!moYFAYU>9r+reKH`CycFuK8&l-PLwI;dE?{(Oq z2PG$~^PuE3(W>fcl$>qer?*X%-fyR()lhp9T}kL;hcK%P0=`>ey`IgffH?0ph~nU~8c;Vjr|!lZl(Uu$WP7J2*x$2u2HF*XYaD zN*MlzhR)W;)qn%B-P#e3OkD>Jq8myimHdWS$((?wigo?zCzVucaf&Wtky)vqU&MUN z&*b`7%U8AcB<7n+#+kp(sS0$lMP>;M1&IcKE%mMN;jg8;wQ)9p7^iGib}Rgaq+H7I z7rZXwZ{S!`@HZc#luKS)z>H{mSkv_(%0O^VLB|9(*cEL$GHaR5%xNr+azU$SuY9NL z?uyt>EwQsA_AD-9^YyH%@pS1Ka4pqvn+MhBQ2A1x_N+qp*OQF;mHML#i-W=(FWCXn z1LKqy4Gprvcca%+x_vkORmw- zxquiJ3&t802EhqvRxlKHUJGFb&iECK%4+I?=q*1aRWvf&l545>v!3Fd6|qsnp42OI zRz*L>diw3G6&;zi)RXaVhR$A-eqa00J#Xlf)ljZQRWq|VLqVdZ9czBGP2sO`YV=w6 z0!R1@G}*9_)GNSHHTb&-!M1~gzqW~kzpQ3^$38@96PXJ-Zy`B_<;^DkXZqQ{Ifdo8 zm$R3~zL~*{WWF+kncU2HWh zU#yrcYw|s*$|5|MGIQ2+7QZVmW{8cXL2{pHuUn_(9ioG_q~;p?HxL{S6xQqFh31h) zyT$|#90!GU(FAY|b_GDpJDmk2EY^+Lzpimg#}^HM1IG|q2n3f!42TPb;buXqfw^ep zmcT$P3KtL;9CJqlUm*l@I1tPV7GUwvZpTJ@!!8O(ppu4Y=XZKdtYi))W`#3{&M;j| z|Dsr>K4nBzY#`Pu(8an8{$jMtce)GjLnrSn*>&zi&l*QFG;$TJ)@;l1kf#ObK_Q>))=) zthwjyIy+qzJ3Z0WE>>nJqU6J`=t0Dw^Vn!rY$)Z}jK>NL3ipgsJ4-Gy2eGP8@Yhts z$!0z=W0(z$eQqe$C|HEQ>|ZbNdXvZ}H9+v5`0J!rzQVx-X8&?Q=Ph8`*uV8d4FB*S z{==BSc7eTY=&+@=x3O=oFio)<%w{Gx^PXu?Z5QvZZl|YqdhPam#$)BXlAdwqcTT5! zu1yhdPIvJh@MpSAyf1~4A~c>Jr(-u-y|~7ac>GU5o>QMZq!fO|aYz99wXfQ#yulU1uy_ z1J**=5Hcq3z)yDg3vFR8f`H=Kzvw!h#qtHj%;DZ>i*%Zt1dGzFg4k-?*T&3(WL37B{N6(7xjoEds@w?2)=&pGmS}7$~CE^r46N7xBv)HkmK~Ln1 zIS_N|%;{OSOONENq37z_YPY%sr1m2>84>Ab)!E7-j$b;quvKd|g^eA7Ic%*6bJ@S? zw}`;8mF z%2k{qbhhem#YB{nf#@=w9>j)dmkb?&P7hf`hg>C4{8^?am3)XwI*90bOW{Ep)`Yv} zS*FSw2$BOwbdedcS#vmm2AV7J5Sufy&-97IT|O7SC%< ztm~ZVH3$KrzEfaxOUN)m#wgFtjj zg|?DJBOrlD!voI!fj&2XU$<$yL!s z;vmf>-0RutLBOq}rkqVHpPV+dk;jn@{iEnW6+eT5@v%l<|5fCHY1 z!D}XP*}slpc?+pNgav~87BF+$7BCky2vz|T0*k;LW!5r-fnal;887ppyQo>T?g+8i zfS9w)KAdW|S#6aSJ+r{+IlYFRUaVEsXS>|eqxFuJECIRF+Eq&Fsmc_mh|0c3bV>bi zO>B*y>^-$OT{D417mJV-4V7i!BvsxW65l}K5CLEKn_vZt2nuIk7zD%LbYOkhN>VV& zz-|TjYmsT(F@e!WpKdSgF!(40g<}y1D+8(ExUARk1EZJ;0bg{mHP;)7pTjHxsmT=% zI6eXX_9xQmv~cGXU5&rNk+h*9sY7m2AP2{RK5T(g;FuCO>a_L-mYKRX}AT?{ng zZ(c##z~2tUX!x5CLHi1aw~%PC1soT&EnqHa_HW@YTRW$)yzkHYcJL!h@tlP=gYoQ{ z(^PW93U*()so{P*6WwpWOZK+ySq8P0rHEN!&%QyQI3t}yt%m4Yp($~na=XIHRcdEW zl8WE6SFV95Vf|bkFu&ZaXf?XNH`l>59)?*Rz z-nhmh=8@K)1rQ92fv-VloyiJ@!f{8tipD7ogpGn+VQ%0UK0@08TRV&v&UTqFOKh7U z97A}|#;*n}d974*QY$(TbKaRF%dtuZwWozcs+MU)kcCbNjYbqbpOTW=785v=p#*qw6qOL#XpGXO8Q(q zC@HalD6#M>iYUoq&N3TG8^Ur0e=~6OMxhMh>T$#gQmpSYj z6lVMyeSkQIuxPh}(dC+k!k{zOu4}>!ra{}n+=|YU(MBKyg^0>n4RuqAq0L1PEpE_o zX!cotPlbDm&HA4qoD($lnbdr7$Uj|`Ig>kzlC}OY-&*h}D|yRxQ-l>b$g}Qs`q6=8 z=c952i`~kM^%Y8x$^_oV-ykv(qDN~R?mW-D^T)tYT+*;!3s7g ze1yikw+UFpg}*^zwlE+TbYtKvFo9j+uMl%M_zQv=#R3Sn_+$&m94-hpBI1sYIqX`9 zX}nY@z#RwzPh$3sZQo=W@VE5LjdL?Nb2}eeO4pE??NAMaeEPt^oTI(mIra04Q^V&e zsP^JB`W?`iYqv1-(*l`2Ocy2xW8ZKFe9m75e>sYQFWhAR!ryEGFXC^E-+-?x{Dsu; zT1I=vjzBxd#gvA>*#gdszz#w?g_XCE;(}%Z=OgfW5h?g?@sh<&<> zd#|u2zb1e`XDMdoD$Xn%PD!o_9K;`r8=_s+q2+c}$xGWjFiY%E{d3(q=d9?eUMZ}5 z!5Qe1DWYy_))Sd@KRqym2%%fT-;5@^B-snrU9D^lE?28ZK{q~v-`xck?>y0e{M_Bt|36M0Dl?3@kqxCE?YQQ9E-RRbFhdDe`lNxa9746x`t|#Ly6vWbN{JkJXGyI z@_8uxNdE4T>0P?hLkp}usS-O@pd=3>Zj#!A>To8)z1x?<#k<2aZ)E9imCiF}>>JVc zUfI9=&kR!F$WZkIf(%&S)5t4GT+raP18(TfAwY}?{0qPE3o?RWPHZ@CH#u)175*}T z`-@0SV7tH$VsSyMiP^(!!zss1FlDJ{AXv3C`_(-T#6};BWCSW#$rnfa2#f7GFb7qo zp%b(Io;uSdKM;|`>{*8Bo=IKo#B^2f1R9d}1Q}0|WuuAq(N?!vCq{I?^uY8Jbig-O zFgRui3%V;TE;#1E(T8IW!{V}tb2N*e2LX}wb`Wemd<4b2W75W^D=Szq91IG9AzTm~ zL%3|)HEhiZs}k#&iw;;9{)+C?I46@yyB(W%Pq9JI$#M-!em6ulRKLw3+LJ<`ZNn~( z%3j2xz+9_m4rj5#i>->83B+>U5*@l3^%mO(9ov%;3JTe$j!Usyy@JG&W&eWIMf_#+ z4*1JVW&+zameCO`U%`t18JgEyNcABsCa_&#h|lf@{Q?`@L1>4;%rF-J>c(CO{+ibI z$KO*vn#J~9WGZN}o%g9gx?HaN$PX15qWfrgx@3l`4$%|TYX3$%f$|}X+E$P>Jheb@ znZO{}$kJC4!C&ATLm2XcU{|3a*a8^%x)%Pz+(58v=$$kAuYC5$9SjWzHWCVm3tJ0D z3uF;>!g)v)4gN;BqC*R8M>R;=XIrc{-I^plN$StHm~$>-omr2jGY_JBxd&xDTjA5+ z$aZ}e+ifGuS=DE5UJuveR?)qPjVB(-jjC=W4W)~22p^QRSm8zen1#Pq>G6hHV|(eq zC$Jcy!C#+i<}n7r-XsF1Yxo%FA zXA3wkX!y$u%>@mA9fXFzf~mk#-~7W1ZINK&Qd{_Iq7xQxO^dDZ4{A)pi|rYvB8F0i zXfJC>qM<@+yVG?P)(Y*~7@DF~ot6Gl zI1uy~2W^Ug!dB^K0LyRQE#r>;n=RnHf&_nkL(&l}-;;!={Rmd~Ja@VvIH#cDFALfh zF#NTl%>H$m~EgK!hkql=(wPFN3xFI z6pmjyK}KCD{dKcw69p8@B)}EM(`(RyJcp3Eg2AFs za4=W7j$tTIGW=x%*Ac9axt%Wjty5UcXD(fYSuWwL$ z5sCfF1+7Zf_Llu-Br{bY*lece>OZ$wzsI`Svn2{3qBbRldA0=|q%BRc*dRBlO$N0? z^q|TgBz#u)xLDyu=04R+tz35id=#?2O<#q@0b&lEK(MQj9bs^spnJzD%{12At%`-h z-*}|sjz+^@;{p&Hxk2IXjxLKhN2ZOVjS&2eK+*f$^@dC}NGG~{_?;7ajbD<-3Y6rT z5LN#((MHK){V~_{R|U3-IeW=hQaBaeCJqwbR&|X7URM#xDi1+hX{R8vscD}SW~hHwTsL(4JYGQ z^%k>NDq>OKSmvG?tDr&Qp4o?7qP3nmv4&aaKAhZ0mz+60bsst!a@9Fyu~3XT93bYs z0l{c}*w7P1U5&wP5EuS};OqzkVnk5b74iyDIEHXGg<-MKZQ;<2--PaG9_WJIPLSE> zevg&u4N`P+B|2+ZO;~d)G)aPUct>rrO1|wg&dbHDXag|z0rKC7(MCC=S$($ko zsVOBD-oFvf@CK>s_lPz>KrxGOt8N3_fDQh#J!AiR1u6D#@Hbz9b_9!s+YR2CjtLB` zLAEX6{1zcUHYj%lE2p4=yZvP@==>IvpJNFAD%vhE6Bq$%;H4tp1AmW;i6`ZR+Zr>->-euc$cmD-6#$vv5~*vzT2 z=A?Z%m3=0T&7LgBij_bw0<%XuUGha7T2N&iO6mMFr|TBZT=Sa3(=^MP&VBgGEits2 z!8~9FFxa`dj9EjH$q9cMp$t;~VSBaqZG*p#K*Q4DT;4euKESJ6GoPwqb1lv=l zwp`F&bYg46-}s-Iz#y0jY!{d(Tzzawn-6UPCV? zFz_`1;crkF1P6tg!v(}4tdJ9cuK;|Fg@AGaF)WT<94t1Xh1w%Ff`p*3kzTNCaG^UV zNp&N85_1bAWB6-ID%U{F^0S`K>9o9}vxd$&RKD^im5LTEi-*A$eQ_!;5JI)p`{LNQ5nAPx?eGTHhh{Oe*Q&>!3 zA^6J#t{0K=MJzLksm4-4ZP^PZE|ZwMs3uK=RCJ9vwB6R^qkk>+X7h);>&5k?;vZDo zuA%5s)d{IRxDMVr4Ga_JeN|O%3HaLGZSQr8Tmvj@18^{8Hi)E55}UIbB=vJ2SMTnR!Z1*NM(joHxvP=j<|a0UV^W@#+vV zYZNSU5!xh>x@H1{ z&K~Wlr78kLbkJF;oftGr>YRP((iY*0t`Ym_>@stebkPKz*1Ay$1Rp{1V}Q5c%$ZY3GcgEPbRd#(V2aKP*CdC$gP3Ru^rX(;C@xtB;V7)6n@UvW4<+`m z)vS5(e)qZSuBs}~nWbcAo|4n+oTAMGS$G@KTvbM>r7!%2eb5jrIwA!w;U@bR{^l!K z$J)QFU?woJxS$=u0^dGFSzEw4f|V^`Mbx*TfiJt;+s6!WyTDw~jBy8{eGV%wGL`_xuJiMtU}A}U!3ZwkQa@A z1j4(EVOYLsy*hM!(b*b~MGS?(uE6*;W@7@w;uyk)h7gN5=CC6Z@kK-AoiqAIu+oOY z@kJY11O6sD+}B2Qt;LdMF}2!cPQ~eEm1Jjjx&)3TdVLm!yFjNGg^y)!Xh_n0jn3lF zMO4xnae^#^s-X^22c3)ZgUqqfu4ES8C$;BVlkfb{Jy)l@WapoN9tsjIC6$!n4}WtY z6QUWXMx~`MdlUW&@Yg|Q$EDye==3p3F6iM1^oAE23I~6owj)@+W9bxhT+npphZy35 z4*upvB>v~x0_K7S!A@a$5h*TclZKhZY-0+7zu7n&Ah>S!ltgbgs)p#I@-**;WC@f^ zIMLQqXL^>IIX#!u9xXb#`ZYTrmx&lzu9Vmr;JGRZq%U!N~Uu{Z`ZcVN3wG|y_P!b z->2NQT)o6?JyJK6%t_%4Iv179d6TR1_UHz45L>K3XO=3=o_DU#8mI6Vp$}UR2ZeR% z0CBd50I?7V&eguK&L4L)EEd?p28F-`2Ej+B@Xi*FAq;Je8W1eRBF-LhT+>iEHZMX5 z9Iw^+(3`E6*-$v>tSr5S*Rl`78_{SWP^wC}k}5SxCAmMbsI%0To)Rl!PAX0jvz|&i zD{^wdM?HT{F0jk0D9L*5fat2o4V_C=ivRF&9l$uiK*LV+HolwdajgJ-d7{Q(TfdvpAi( zR=0s)C=7xV^kiK+A)CTw5eJBY@6q9`A7uF&1%TLa5CXxjF@(z~?yn33Vh|ksHRJ=q zF^U7eu9!n5hiKjJz@MZ0OD1n`z~r5Eo`%zP4t1N8PE*jHc@;WK_L}t6Md2>c=`|%? zW~LX5h^ob;S;IDGQOP26O;0MbmbyQG&@)8W^ek4jGY373NwwYvUPiQ0Y@KWja`WaB z9L!JlFJ$C`X09??8L<6_fSJJC_OI010_M1O3X2OG{{HBX{%BqVjtT4tR-JRiCxg{rL)-g{$--HI?kCp=S+ioXWcN^b(7? zmJ7ejFN#HALoB0mfZ*C14iLKiezAq;s9oVcdriw+7~ z(1r;90$)?X;w=<&<1R`j#C+FoQy9c5O1@~s5ba4Pqr1YYTT~@F(KP@oG57D(&A~q*==AdUWDgEC_hrdR#k!!#jp3n`_3CvF} zXh)#!)jBQ(H{mZga*jZ=e~)!R`$dMrUvB}&1?^QP)^r_#t|M3=I4)==FbFOaST&fy zUPN*#Os)JvL?GA#-ZWx*vG~tHED+3U=q)p}Lr>bD?yV=+5Zy;lsv;fZ4x3d;$32ApDK} z>+K=m&|t&n2z24^_W7&AU%B!jN?X7&fq9{0|AOGSpy6+hU|HLUTcb;5vxq zl!%GK)M0IJl2LiLz%DRNWoXxI(C@t(;i)02sY6ussVRLfrK-`BFne^7?u~hxyI3r% zGdry&Lv*ojH-q^!maFKLo^Bin?!IUq9w;0`80-%Ci(@Qs3JLHR_y&J-HCTjzZ@Hrp zaJlaY1K&gsYTN202j$vdIL)%Z{Dx$&YTCJkkDC9<5z*-qxEVx$;$8pZEiW>AuHOyx z;-d+3Zl5*&=^JXX8q^N_UZqOX@iMOC&N6HbOrU0il?&QiKdeq@m{*Wktj;ZiPJ6g4 z**XH9?`*7jq4Nq7q$ba5wgqel8HhWARbRo%5iF;mIl7ev?zy0I3d>u-!Cy5IRLQEq zK`dXSgum7aJZ6^emJMbbGY<&PMzC2+=%eiPO?{|_v~ya%=tN7^Q(wc>Bo(MyRef$Y zG2DJtqsm>Z(o^3`bBVp?MbBb&BPSzhcIZ0#quez;`KU+lF2P?A9H(?_VM90;u^|AF zjb({~?zo}q2o@X!!R%AEDx)<=u)GDFBhUfgZTmM{z&QdP z{Ivzl1r5#Vfo%cj6m)ih0kK_R2ch#tN-k&+Y?sP(VbUga}81Wn{y6vN*lZx z!jM<65Y1ZD6%glWmffY8!w7@LNRLw*A+Uerg+|9N&ULY#YFJh30*lNp&}qWQ$`1lV zv};?Vt1(Mp=2Q}5SEn0TNpj#+QnC!uuIFi?Q{kb`iKafgd%F?BNo!QbFzZUTXv7fh zN!#>|GCxP#c9tP^vFJtSkZ~hg_r7-f8+m(D-Q5Z5Ba0C&SUel8MyPQIfAa|}z{d{^ ze_5s+#Vl5Kt1V#o>j*SR&HnEO{@VWy{xX3{(L~9yx%L<6%J6P>%u=sc;C2_bdh4AEpSB}3{nFj^H>x1tdnRqZVkIs;bs7SJ(= z^?4yyaGAic*rHTm{04q0UV=ud&5V;YSw>O!)mQ!YBDD+GH0=;lC#*h zi_BiD;YKQ2M1+TE*YNbxL&bU&-J{#}93+S6cHW-4EAl9G=0UXFv-~1+7JCXfxw{k8 zM;4h zA_ae)f>uy{2#e{RBUqLJz&9@1X#-iFTRo+WJ+6n4${jUk+UVf`Nv8wkPQ zLSdr=5W9xR(X1H70peWamkt*1U&BFic%X^84r0%=Xxe$LwnP1g=riYD&Z=UAo*}yb z{mPiIf0jW~_JJe1$ehKtIj5}Hw(?_BYb|ZeS|`I_?p%Id-dz~S-n0XoSCBv?tYrU! zPDik80hbFJ@`B*S5KsowbqXscaD9l9PQQi3xQ6eF0KshS?t%^k1K)(WpdEyELd+t8 z37pSylo#46!py@KFeACU(=_jyJl|so*(PX`Mhgbt&zK!Tca8( zH&tSYKrky<2ny@`fY^u@fG=}6!O$oyW(C7y5F8XX@Do6Ac7YK%XVr%D9c^nK;OLjZj09Co2ADN3h^8uw#2V4P{#vI5Jml+Sgi~>XZ z2#R+bOxDw1)f0D{isGfjLC? z*L;GE`zSwinW3ITbpPUHOxQomASwI65xt>x;r}cg&Mdknc~kjAHH=v!G#f*~U$_R~ zID75A+KLVS!b&@~>|d`DF=IKCecNhJ{4EpMTS(yB5okxS;(uoU)+sFhXKw*>L6-^a z1!Ok3Wk7a;EeX^r5X?hf?*ivtBu+E)hPkD@(7|8#duV&6i4M(msQmCCD!Qhp-^f!_ z!?l|H9{)^Qpg+(UU$fdSBQ?*xUk3<|A#6|!AlT4`!U1Af9KSRI78~+{@gf|V!n>D+ zcQAbP;*#r7nJRSPS2O|@Ma-OHO6ro&Si0(2M5;PO_o=@u750(eQ)W#k{+=2Z#fI!d zbTP{!bFF%d!i&tsqD$>eEGoh5l4~+Io8RjYcrsv(Q{&MXj4CAH>f8FVzXvD9irB{ShqEYpVKPoW6#==(Q5h zmS6Snl`rN{)*62h`yCujD{Ztx2_QNO+Z4{A2Eo~jag7yhT<}60AdokPuu&hP>|)5v zE*5&*_Ogl}=2{eg5GctIU1z5Uv16k>??BIa2Z0`)g>eXkU&LZ`G4H@!E35N6J!D^u zc6oG{8KROR++{ZCA^Q;B$T%dW&=Y5;Z82}Dor$3WCyvgV2hIsJcMXB3ERw;N)vvQm zc?H;y9e_E8ryW?XU^}z6XnBmCoAN^pIRYK~Hy-9i{OwE-oKw(DU@mATFjW+Kv$(c^ za|$|dApw2m)`vLM1pabC=O8o_xORc#g;s5g2fJ79!c1a0VZt&0n2Q8=s;&CH4|H$I zO6tr`m%u=DnKim+*+*uOuW02h&P*Aj&4<>f?B!Bhgx;>t>--3#J6Mc>!VKZyF9=S^rtpy|yhG#|!U&<)vy}IG zhS|l?v*e=KAi0>UYbMa6o$h&O`cTQCpo$g|g+sKLvPR3&Ly2`}r%Pai=evTPEgfAu-AdTzib1`jaa>dV6%-`$oz8}{7qX`JD>7d^z5Z`Ai7MaiB&XND!NDv zYKLggG9;Zc8qHlvl@(?eKo^u$mM&1tPL#qTdg?%z%s>ocCyowkD>^7#;}feS#E@%9 z-4;k*y*)w0>i-EihB-R6aIVG(6b8ZNh_((l72xCaT7{nLHgkHeq;}4pbg3Q6owE;; zv%vnGQiT|D^`y{)z&_DAt!HS*B8pm}PJ(wG)x-oY0Y9)PtE(nN_i+FZIW5qS~{v6lYID#yurVtXH*|Re?pK#10~&YREEF zxQdHd&(i5ZNf#azE=m@&irXMccpx^iEG7-vD@wR%L`4^sRBEzxnXaVMU8d7rrs&c? zONLXDh~iYA2e{UsqPfNd&eiD1!4Fpu929m9C>uU=iM^~fdd}53d(x%6em zk~}d{IuTt-=Xbix>_aDSmz+6sYAjuz z)ZbNA-bJD$lN$Ytk{irH3CZFZp+=(N#%v7!dauU^E&{%J1(;3BOAIA#+U5u}3|+K; z3w#lUzacvQ`U(d`%QRX1DGu!N6uLCsUG)ubg{oD&dHa!|%9cY`=c;jzLB>M~Vsn2FAG&rfg8BPh5W`qte6zmpVzUa84Yg5?p7udXp3tYnI}0%usY6m{0&{;8~pVxXlJ(^!D0e4r74UFoDWgvEhHu| zr#BNgpM&NDSB<^}90;x-Me@O}ybBD1xzNi5wvsoKfZ({G>y|@QTMhh*66kc~aVq0L z%)*NT19Og+KXy=9(SaB=45^FJA&V%nFpC(X(NoM)8&1ELh7Fl6-|5P-L3H^}Z)90a z>UsB}7nNYHXe`fStNC9dUN%e5`vQ@1rF zHS#4Xy2kIC_o3-2v97<0SQO}`SN08J(7dR;XD|81(o0gR!RgxZ7jiKneS!m`^&`;U z3HoRM?4R*J^BBWT`0EIC@RtjE8-L3XF8r0z4zhDxc?%f+(i|5w{EZ2$L=ar3u(AtW zTfpUlwhPP)?G&_KU?wonx%wCWW+%%`Vus1&v)wp76}{Nh;a4+uqOx~p(Un>niXfBJ z2+xu;e@&)Tb%8}XI=kkghos`u)9I+~!j)RgD!Mq^M9FUuYZ^APEGDh#!7ure!6|wm z){;uep~S3zD55Lu!o|l#8{nPDcy~1xgdi^hA_L#RaV+1=38gJW6*TaNXo;ohA$9-g zoPFldR>keFc^}DATZPV?ee^8KMAc%_$(Y*;d(At2nzHsOG5SgNf+|`>iACpp?b!#q zgo_`wYy2)Y%T#KJ2o$sAi>RbUdCXa|bBsHKvGCXauUBZDA_igXU)Cl2SMUZ<>|Z8o zAeadZe;vU(cK^4`VHgd6Z5A_`W#qo*f{y*`wc^5GC?6A8i7|omAr2;RxuAh>@RtiZ zCNLMYU0|oMtQ^?y0xvWdbl#+}q&K$+ZZ@Gemj)S{v7$Yxw_6De#F|X_UAQ=N7MxkK z?(&1SL2?kTj6*K`HOa~nqB8C&KV(0XXfL|zLvzssG1oi-hgPQ4 zE@rG$L>E}(bD@yY+mnipQ{~18*o}Gt_!<|8xQPP3uHpAmiXKWYei4iHsnpXDi$zy) zr_ns;Ew#PSFlXVXowHrBelMLqakcj>?!@|&v8uYEXO_Vszs4_BB@p@IccLei{G#%n zYo^!q7>tCCzU=?PUzp_;Bwk$j%d~XN$(AeIlQrrUBq(XSmeCsgjs44?yk`I6!{3j7 z^rPj7_7<>HTiycBhbV0U=Pe|f^A(Q5UpvkU<${L4PCrwOehSi#OhyQ%oo;)TwVBTdwsbZ#`9wRT$+j(l_u0$oof6?4ck@GF{!RoOR) zD6EXLAC5afT=j#R;*dbCF+p7gLXA%3da%LF*vK%>bZKpys z5X|N41Qb6oG_(cmtTM!8x7xskp^VuL|MP&qP&g(q``25*aY0k%OqVZvz+b_KE@S@& zf0@8eU*{Kra|*hD2rJ*h@-DEibqT!CAeadZf0^)3VFiDAq1~NTea$)58pjfIbM?kN zHhTmXvlKH$kPN~mTGu^`I76|j*iiYZCw^6L5bo6|na(_xu3Q_Mk5%$JOdxI2Z>n?V z7E99&GO~vsJuo)`)Z)Z0&HxD_OO0gL-*qOnU+2`B)8$V@fr{7?vwOQND@406AnbRLZ)gfX-6tg%XW^HSn$j5y|X0CQJ z5-SZu5pz;F5i{s4dLfio|2S-ezxf0f(~`Z(_sa+ci0~IsLQG$w{JEd|IY+Pr# z#q2HnR}>;MfuS}Nm}~8 z>~#)Hj1d62@cVS|2h5FR(~6y23n zm1gG5Dd7{;f5i&l`J|QrQQh^cRsPs_34?pthoWW*@|452xQLPN^+{A>*;p zXgF5vSOH@pb#pZ|g2F>>XC+m7Bu{V`rD0IMrfN-I_R2C7gYquilPY5|H;OBn4PsC@ zL^m=Xlyu5U9#qydP57*ubWu-d9@@x}?;6&cE@RD(4|rlEX8#xXa^%7?MkRCueEiSs zUzRCDmAlyfuT#+MUuG=ug{M%pkhjow=73-U_%ea>7E(@O*;dZ`#q}X9+s%c)aY5Sx zjtja@K?i&bfAcx4n8210`CX*E3(N%0R|VXuTMqsnJHxCs+8Td;O!Xk;kKQc7YuyD-+lamI-WME;UU*X_B|Drh7dz8#SH=# z9VCl?CPb9Go>*IHSW^;#(mzCtzfDvri();s9$YaOiA6mdOiFs{5ba5!Q)uVUoSynr z(rKcNE~hd{-M`M&Al3eqB>SS0ed^HLgnShd{>({ zz#y0v3|I?fH;A19d<4PlUt7Q+7@F59X!u?~2Mq3W3JdfzfgJ;j3)=foF@bNu@9q}~ zRW-ke)OUfIz;35ZUsKU)p^cZuzBH|QCnXItk*ZK>W+ZkQ!Mq!$0I zh+doyFGTYhmK#;kT*Vy~wJ>#;z;J_SQlB;DLs_ScRvYfAr*5scNvc{&T~!zB{8>1X zu0vAipu3V|=|km@Rd|yGhFiW#rF`D0-FSS*witn9Wi}dQqv*9<@il=YhN1IUAlPd= zUg7a8gdDl?Kj#Rv7joI8@X=l^xXf3u9AgH)?Abl>H{i=zEmuxKb7B|%a&9w$;jfKm zSkDCwf0Y~jwFY2`JB7sr4*r(^8U6~abtbS~;QS~!@Ws$k4XMf4X>>Es)D{P1znp8Rm;!r(Li@Z9o zm7D&Pt}@G1Y6&c=T4Y9Bnrqg)!I1?710#WL=oKUm+Z@4yzxf0fyyJgnfjSCh3)m58 zAB`**Gzhktn^Vwb_BwVI`o;;YC!?4k7+Aw!2eUkc)x7l-=GM!Tn)zqTshUtb z_l>hH>uk04n$Mc+UL=uBn8omC<~HX9S+*4(lsc3?L>E;(H63ZO=$Wa)33Jj@#_1K% zINRmksPFE7Bxhn#Ly7g&fhn5MW%i_H?2<#YC!L0VvVQH~X|#Pl<~_ED9C}m3cwBsN zi_8?1N3nmQkQV?6kjN2e*u+Tm<}CY{|Cu9~Ey>5r-y8g8lL|~!hAR7)|C#m51-*g4 z9fb>>5ix;nAM-yu1?`UFQi}H)iuH*!CZsY_RPnM-_uxGy+_to{E6}?#bt~`x-n%fy3M^`xXkY4Ug zR~+Tj)|S^}l2I4Kt&XWpDDvC6ne5G($kSxSB%A~zDvDeGjVbPfBI`%IIm2YTX) z)#F~&khUF?7MYRRehNdXXi7)GUw8z61$H8|vU3{y7rL=Ad3~9mHe}hPOw=5~a&#H~ z!q9pPxDYmGFH^VUZ`s1^UxCRiqmOt{0?paKAh;a>Seb+FYrDAI^|s8( zQnxkFsWWGva+B+1dH2!(w9BN+RWl**^->PIRef01cmUI z@e6-htUwcV`izyGTwB0Q+QQ#$qPw7(&rD!n^T=Dk`4)6eLFYppN(}z;LNmji!UDle zVD@i)i?SeCZH2g?3x6FaW7NZ62cc^t*e-B3g57@n0Iq4AG|S>cl$6xoj3=WP^$)7Z z>?1bhIyO4o!Vo<+`{@OCjd){l(bl7#K7Bz?jfT{@u4h>2=VNP}^7h^Gnuf)sMdq4@ zr0=Iun6>2zdb`~sukZ(czv z7j#}hf_F?{N1>o0aI^(%$2MEQ>|aNqgTFam74R+NcM*%(zqWumuJa*i_!}2AWM^OV zKeK-Y5S*U_2EoHAEcS0dg~jq%`U&Lb3vx0-a9MLTOSiubcw1buj-X(f7 zfUh_H(@49)UiuL2NjHhE29N$kQ;ny-GN-@Cs(*+RD@^x$=6AfsXSB%NZi;HRZLvz7 zn|J1v@H3yN7OQp`i2ZM2Zih8h#ou4~Qzp4_7rhRrzlFJ=u798jAIl+7wVH_`dqwj} zLv|ng7YxB8_HX>p@R#Q{uOK<>#N=dn=KK|K4F0lzh2SqF1*rr6mcw}_vi}RUy@ka7 zwUz9JrnsOfw*_4IYyUSc=-_Xi!iozT1m|0nwFQh|{|XL|sXr^;jWB`Tk&WQ;Lc?E6 zj_d+!f&N6Q!K)>!#eQcHb%VK`A$t0IJXT>EwhBsgU{>lgpXl{RpSZ%$H2kf5>5ryv zw%=wK==?+Jw7^=fxs;i+miMXTtJPfGA~RySi}^Y$S>q&cPaU*XQt^xP%po@JqF3_R zTbT7MW+&G9r>Co81F@z#VmW^WiP*oK&(0}%XV$SLW+VHNIhjvT@;@^|oxg&=T+qIl z0Wle^3|J66<1e#!hTY=C1r4&<&Yal!3Wxn)p`U_|{TmZFTfkh}ce+<5{Kab*I}KgR zdrdG;qw{9uU98d~bGVVZ!4Uh`ZOAy6RRX1RmZ_wti%2DV>5J8#nLP`7O<+y`kp0Bb zDt91`RY)EN<^7}V|FRYV7W=ynKV*(3+ zJ6pg`LBn)Mpn2#CLR{Ou+0I~(lIm|?bzkUS?Xfj<-fWLq^&T6~B`4E;Z zVBTyH%>Qf)xITnc_{;hh@-0fva7zL~#hB;$IflLk426TgUPNNW^FmurS#IM%IA90jDE7s{?7K5?3bqs2 zue-)|>Hs7~{oFh4+0laxf(3x0?zjYyQfKJL{TJsMI=dui@8ywnx9`;a0GBYFF5eDa zpzoIjUwGHJ%T9WT#H8GjKa!?QNM86*&TAJSHIlnw!5Cn@HC-^K2pzfB6!XKTyd_K; zrfr_#OrIXZV->SL_yM!Bn51gvDStm`?ml z3Jm{}pOUEZ6)f^!c=H1P{`u#h@Gto<{7VTM3Z@DTo3jgA^=I?1c0ubySo#*0O3-|W zgDhAjXl;bnE@;k>FOLmc0#*u~?*da@=YWN|Qmz*k_D3o8K%(2dnC-=U_M4(fw#g7M zRNBNNNlnT_^M%q5g>f@|-jN-;J8_qV#Gs@(>?$y0-YMi57V@)0S_FDSm##&DEF<*L zLuDGue0^Ty>6Ljd6I;3V{9Ss7ms6B#F3vgfV(YGM?k))iSZ_@ij447#t~JH{uqkf| zlP3R%?1%}Q$p+hV(a@aPqR(D?D0-WB&xaap%{bJb;a_dOf}2Pc$r*WthvX4PgMX>_ zLcUahNl2*-!;(-ijLG^hpRvkUfL&ys2^62jzuE)~Ct1R5Vhha8g13Gxq?M4VNqOz3_hOq$H`C{XvST@rH3$wQrJ5-lU?I)l zDSH5G;qs8yZr|UV7t*6=ujG!AhF*82m6b(EOv;8ynN7)4fmxWb!bteUoV97GsKX(s1nlg;i-1M**WO@)RHC;|u>KzU#VMXpf*BVm{q{AAh z)_=(gAto4#f-U?Dg>jJll59f09IzqDsZwAn#^kMM`4?V>f3*Y*1@rnaBaW|zD9Oe0(M&itTH^E5$ktCZI!_Ga6KU~uuDCW%QoG5d0Q z=<>dwYsen4Yi6E>ob_(%yAw2P+djgzX6@~Dy|YnWi zSd^e4ah8(#rWS7@kpgQAmi`a}88<s|B}&jz``tW zvk^-rXi{J{LT43PDKOK*p{Zk{JclV;d0FUpDuZUML`u$H24JQ2(&X3@)8$0Y6|V(TWok`tD4`b?w^1yEN%%hmmJ_q^83B4U+YrI}rl*HPSSLuuT!V7*NcN{9qo zMp&4*EAcZq!6_%+`XVG|UoK8&&3%WbkQwfj;Selu!>*aKo1mG2rOz?nk=IeaPVaDv z4rggG{_b!H7L5Pl^Y#tvzq}92w;ACh_?IPMO0|@2SwCg}GYhO_ny?<}C#k5mK=ZB; zTd;V0ml8At%FDbYv#jbanAct8zoKC9@GmJaC1{qCSx^@LQi9Gc(4Bw%A~3aa#>Orz z#wq^wMriXdyRcM(7XOk0>vJ4r`W$RI)4NE_0P|2v(3_JvoZ&;|%(?WO<-yG&&|COg zfQ*|aslO(tH{|YQs1&T&x=F9(gjv~PXoO5m$~H;2Hn}Vmw};JHAPlpsG_y~g?CdzcTzM3|7`V~&yG-F&DNtk}9qujGWKY@cb;0q!k=koV8U z?XbBM1;d1uW_C#)23lANKl6h=9hMNbN=%70^KaWt;jEuB43FI5io?<@u%S0&o)R>M z*+|YtIpt>-8vWV0&*IAfO7ng!U3mKGnssl%51Uf<^V;*UmyAy(XgG-VUnmI*W}gy- z#kM7qO1}au{-q$yD?%*P>MI;jFe$J;!J!lw3Kql8_*Z&hP%tLgY6}({y5Mx`&sqW& z`HFu@fuUfwU{M375)S`zuqqAzQiArkD9yiG|5XYs3icPVv=NIMd;VPp?S4g-Sw~*jpEdjF&i(Swp*W|zK!V(4Z783iu#J@^`84UcZUC@-E{TG4t7O<0Fu`sK^ zP_X!yCkj68#nthEp%j=BbiRv33QRTN%@oYN(5;ccS%;O`MEOtu$A1gP8tI=pD`JV& zonMGz)m{&ducSn;W>x&)W}Pq43TmPr>1Rz<2XKL&cH0B)azrq`D z0h3wlMPLH4+zjI<|B?bT5)PN3c@aq|F#OvoSp2KU2{v_W6_|INwF*qWuf5Rh!eR#e zU1(DHRtD7jK?|v%j@{P8`qHz%v~VH1P12{7(ilLLwcf+{ z%0ga_ujtNzJxeLf9QNp`v4>)Ay@dieY&y#4Kc$65erXme8en&3{@sRuK}@q=?zf9Cch z<o+bq*PyeLfkH3YKDKPvi z3f77?6wE3xDX`u}@?L0dgnlOlGxHq2S==VybPK+Be0HEK-76z#bfcuYL1k@Bg#X;2rnDYe`qb=^83?Jn7-Ayg7kq-EQLbJL%x3<~gTs=Smar zQCZ1oAzv!4dIbp%;uR$FUp6UGrzK~Exga$N4*q4ml@(YLQa+BsD?;L5NK>yMv6BiW zg-L{d#Z!U*Q@byqveW%HPS`f-VBhekV`e-*UaB*#|ZRp!7Hq zAQvcDpWuLrRDXtoNfpT%Au{$jLB5oHRexsvmn~Rqlw$ptO;hkM*()5%!TK+hy2HOt zfytU#0>+jSG^sR8z|MdDAuOlB-UZEI^esy5!r}=*e-6p~`>_Z5KmYm6eZQT=zg!e` zbtqW7prK%;z*M23VDm2pdFF)qWPUVVoH=rayC!>)X8`Gk-nz2*r0IKCzy&#sQZQ$m z>xgH)eMh|KFvoD=>g30UrJ2r$vhLBaOG*KJF34hDnt;(1lb_A~8Q^ZtW`5tvS!BP7 zXFVi-_&Xme)5`MUOI2j(irC}25{Lef1%gm;dEHNB+F1XDKKB~fPbNKQefPY1w+0N zy>?-Ve-|$TGeYgcDqrD9{zc|-f_ITPD6MmiTqzG5?DuBXn+s9*388|tP74~ZyN?nJzRFK!8^qv&^Gt&G_ekW|)P3 z;dx>8v&%E!`L|{!liDv^u#^I`N=v%Rz9~w_yv7UvepH`7UjZJH zuar=*dy&bP^DQK&z$`IS<%Z~40w!YF1|gDE9wrND)PwF{c$7eN$E{tN%Iz|AVK zc41M1)}ID0tH7#4GfR)Zk(57I-!J`RcN4)d35upMUP`@a8@~q-zd0FXZe$v9ET?*T(a4=i>jXDPNoI zLn}hSDLPzyrT`27!bGqV^u+qFXp41K)_=7Hnk8Vq%nU8^l?<{}@h@AT_xac4``2H8 zA;Z_Cz;HKjA(8)b;FFJAl3&BWehWz{FxfW);1K`%MI?QQL%X17{Ht78FCu9pwBJP{ z3#JfF3d{`XU0^n1u?kEUOnm?r)*a!Y<#1v*0mI*U|2Hy(ZH5@ahCi*LQiFMX0K-wu zlqGs;&aB?A_XHk}(8wI*p;dx^%CDG#uX79dg$#crH?Nut+_^@us7WD*X475Ag02jpyiof~mD4|j$-ylVY(cxl`_WBzHo|3l4NDJyAq z=CDL5&7p_loF-P}za)3;HB#}J)lc?ck^jO+5EJPk6by^8w95J~IVL4v_!lZ<2^ex@ zqcU5ts6Ugm!oM7(u@sX#)ebeuzYw=R1g$^BK>kZ|trVD8Fg`)O1)5!0l)<6kQi9eh zuwF#^*nJiJ3laZAzaQV?fP%R+a(tG#IjFaD$!x@;_O69s@h^`h6bCpoQOp=ePOqC5 zvNz>2|Jju?uthVwcH}au(%kXz?09w}{_q&?!i5_#oR;FsZY{{FG>5K=GEI=PS&;8< zdOYRF`N&A*yqxV>|B5+#4DPxnIM6loeXGj@)+HYX@`WHAf?o&NjPCo0z+hyxd8NW< zpp<8q)}3Re0}3Y5qvA>m4F8e|@_8t@iA7TJFXRgav(p&XV-plqs1%qK_4nU@r(6ta zlDfjb>|`eY9kT6AN&T7p7elsSao~yrpD;UHtf_KSf~Mk4L=I7~s?ZE3`Ii)!7m=V~ zvURqs4NWw*VORRxgr&($)?hf#0A(?4KE1x=_q#6HSUs705m=Gi5w~c4D~qSNb@_gyq$F@E01tt?n`i> zA=tflu0^(TCE3w0xJ^Hpm*%EJ2B2ex$8C0%W_DTbBRRAx0D0(s9HI-wg8=rE_;g#W z+(dv@pcwd~x;NK_$8eF6*qC5?ql z`xY!xU1htSg#mMD3l=44c0vE~#~<)7yP(Oh#lLL9A|hYGf`2*4e>wOTrN6?#vjO}| zhOS2i2CP+JI2RV?>_W6l(CmU{BbJtc*$Yj{okJU;c?p_%;AsR3W@cCg<`IR1>E)cW zmlJ+U#)?*j2{b^aIT1`zAA_Mz!Nm$eEwB`fJ{b)q2;~UKz8tK{ihm(rQeZMxNRzjaNMK=7)_=sI)?H2ycESRSYZNwrArUcEQcafL@D43@a zD45DTPbMq@b1-{P@$dRq@rGXi2Hp^>hbTYD4!EW%ZnJsedM}tT>}yunuJ)LgdF)W-2S@5&jUijI+s1j?_(Bmxl;gE*PVwla@^(N+y z?7@3r*38@*IRg~^5Iv&Y z{LA}C>|XZzZ{LD7OMXd*#lM`%owWrE9#;t(&+so%*o6iEY6%$r(BnS6>%rT5aR(CVFa;;7jz<-1JbaXzECF zG}+vjhlWF?d=9%%>VSL^$m}SwlI1}+e1nlcNx=Fq`7c|b;U*SL$$x+Q?Kjn*AwKd@ z*boY)ILuclVM%=ji@cTm7aAo6CZ)|3c+J0}V65~O5~(!&i%+W1EHSgunp|5YXeb!| z)t@6&7M#1VU|}x-I|Ww$E7~;$!@t^v#X_(snCA_iIw(Oy!P*N=DS(4HAra0hG&8oC z+j1+vO?3NDf$cjih8|4OyQ#=-TA1k#xF)m<{ieX1yRLcOv3k)(IW+z)-w}!*H!aAy znw)hUMg%s)EV?jR_omN8B4;yUmJ6UX4Z9$G#GYU81&2cuMd@dOFAu;Dhe01vD#TN+ z9`SSNq|9e&9-1!z#Z_r83`^J0aHy2wunVR163FS`UnmBmfqzMXp&|H}sw~_DbHTsR znZ5$8Phi1=@Gs;@{h1|TZGjg5lKeuxtO6(h_GRDHfYd8Ul%UxKP5w(ljZgTO{F)S) z7lBEE^&t-NFXSu!r36h%&WlKpFNaFd>=sM@b=oTy))FxM%VGZIV&PvNJhTy-hY*&4 zIhYU$l)x#IvcLw zUvyDKdDb)Da^!AWP_LStbqq~Xc~-`42C}*JsTq!;BWYc|>k zLzJKyF=b%;L1mcu;;IC7Gfk{~k+3n``Y&v#6qx*%uTa96yt)eolf!Bk)+zoKWy8OepebdO0+au; z1WbMn%kv^qroiOCsy}n)TO3*ihJ3XPi#(lOSmIww(B!|F0;~A!{Fe))#?DH&OVA(N zuzvlO6qph;2PrTVti8}o5frQvw5E=;rg3(24Vwuw!?Sw(PeUsaQje^zqI_L*7_N`% z>;UA}euh!b`t0};B>@hd%4g+a^r3P;ZZTI=<|(5wGWAyOM=Z$nHjHb0N3QWUyeZ7$ zUUNJ1w$`h6=iEnS&o(y(jpY{!j{YM5>Gs)JYj4A;o0)WdG5=Wo{pA;OI`c2&EB<9M z6jmZVguEy|bHHm59GNBuNhpL!{h8zxmLyT-qZv>z{44V9OTd}%c3CB8_*W%p{E+|p zZxO=3+J&WWad-(B^3^UZZ-izQI7`qB+e^S^Ugy7B0#*tP5ktYsg0&D#9e}AI1%`sz zh{ZvPUSGu0ym8iimRZf;#;fHFjjV&97CeBWDNV!vMS?CNF9bQqpIt?t%|qF4<et!k@1!=2TkQ#w#m#@0tzNQ7ue+{KKTh@E*>HOrNqkmuRlSlSAg{i4hReW zrJ_p;48g&Aa35d8p#Dtp8GeL+Axe0Yw}&{`NmcS+y??acg~bvuhHy7az&IhB#wV3+ zLcqV2yUDoWU$%Y`x^KZED`#w40#*tP`RXks{)7{kFg##kNE!0wMI;WMH(2=Q!Gp`^ z;B_RPMpT8?>qsmFXA123_dT)(!OAXd!fcrM9odH8MbHQxdS}3!82LDnKa!p+8(`jlsbOw1kGqcZ=(EKm&FeaZWv z9%zVs5dMXm;4gMGaghH)bF8%M*Ug&FOLf3zdSbREhO)JE-Wnm zB?YGb%pnS9FEmTQY{b$=X!w_9ac#sR1%`jM5z7m~%;D^Q&GdQiW|-6`en(E*_sfhh zgYFFY6lULfBJarS;icz8qye_FrVGNP-c~~)ktq+sD8abPcafb6@tT?8=&jU@*c0_DGjv?Yo+dE%hnS zJSXOkjDMSJ{g=f}mN+T5QgnrP*a-~zQl5o>At_jl{Fg1z+X7Q?0lttvF+s}gjcU5I8Q7W~Uo2mH$tFb^TTi^S6i{Hu-7JfElp zZ3@=Y%LV?;`|BHlkouGpb4pGpZ^i&`%EFZ@e_3C+R3Fd#grU05W)5G7l%NLopOA<$v|YqsqIDKJXT@Gto< z3=Wm!ko*_^B?aa!U~+B3LBZ6Y^&+r7#GzeSECDM8hJP6(sXC*Df*CpQPjNuO=3iyO zurLDr%fVv?{L8^p2mH$c1v3dMK`Z}demIl@>x&#r9a*quGH=rMK zQc+T1@?X6LObQJDLcVOHO8ynMLa!vboq45E2^yLDGv*xdID5L-1+5fVZz1U|V92-g zFIhSK%i$6<1NMiov=Cfg1QrW_((lKKCk+m&(3t{Lh4x3Gc{tI#NbJI5x;S8A^DlQ{ zcGuSWynQodVs>QvDPZfrh){-i*wnBS)-~BXllL!w=E3@OW#vLJ-WW8Nhk{LvOiju| zbCiiGvQ4bFW?#V8;Nqt=fmzc9J9&}NBNmO~7UiN@#yLY4n42?v(SuKo&8<((9obRr z#G0XC7{U!UUl%UDkwF`Q|zhuE&AdeZOz~*0nj)N4~AEo5UghDh` zXlnIL7Y7u~)G>z~x*d7r&}4Ha=Y8D4Bz`6rKZX_ktDD4Khw#8Q1$j$w*Yw`?7fv)TBH#N12!++r)Zn_62MWPCpC1VJXx2?6n-^q{b8Tx_ z5oT7vvdc}Gm#*UTPE(%kAp;F%BN2vx7bz8Y-}!8usZV+4IWae7Lf}E^8)rC0`>$Y` zkG;R22Q)-I7H)!}DCELuB$!Yzgl&pO}<0bVf;8_?hQx z`rcBjd&1#_5JX9xxURSBA+EBmk50!{r{ zOTbVV#b*xXzfd0eFR3W2vE;u{Fkj)IP|T(&rN9sF=-{_{yA;mDKkQc+qt^^ uD@vq8Af$d@P7f)|Luw=+dM+k2JTQ0J#G094q|H;4@{WhZ+aZS5BmWO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/zerogs/opengl/Win32/zlib/adler32.c b/plugins/zerogs/opengl/Win32/zlib/adler32.c new file mode 100644 index 0000000000..bc0842f01b --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/adler32.c @@ -0,0 +1,74 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* 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 */ + +#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); + +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *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 ? (int)len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + MOD(s1); + MOD(s2); + } + return (s2 << 16) | s1; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/compress.c b/plugins/zerogs/opengl/Win32/zlib/compress.c new file mode 100644 index 0000000000..e7ea2c518b --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: compress.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + 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. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/crc32.c b/plugins/zerogs/opengl/Win32/zlib/crc32.c new file mode 100644 index 0000000000..aa8b984a34 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/crc32.c @@ -0,0 +1,311 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results about a factor + * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id: crc32.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ + +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, and + then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ diff --git a/plugins/zerogs/opengl/Win32/zlib/crc32.h b/plugins/zerogs/opengl/Win32/zlib/crc32.h new file mode 100644 index 0000000000..5de49bc978 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/plugins/zerogs/opengl/Win32/zlib/deflate.c b/plugins/zerogs/opengl/Win32/zlib/deflate.c new file mode 100644 index 0000000000..efe7b63aba --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/deflate.c @@ -0,0 +1,1502 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id: deflate.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.1 Copyright 1995-2003 Jean-loup Gailly "; +/* + 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. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, 255); + s->status = BUSY_STATE; + strm->adler = crc32(0L, Z_NULL, 0); + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy < Z_HUFFMAN_ONLY) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy < Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ diff --git a/plugins/zerogs/opengl/Win32/zlib/deflate.h b/plugins/zerogs/opengl/Win32/zlib/deflate.h new file mode 100644 index 0000000000..26775e9d12 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/deflate.h @@ -0,0 +1,326 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2002 Jean-loup Gailly + * 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. + */ + +/* @(#) $Id: deflate.h,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/plugins/zerogs/opengl/Win32/zlib/gzio.c b/plugins/zerogs/opengl/Win32/zlib/gzio.c new file mode 100644 index 0000000000..4cfd64fc45 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/gzio.c @@ -0,0 +1,1005 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id: gzio.c,v 1.1 2006/01/12 17:26:07 shadowpcsx2 Exp $ */ + +#include + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatiblity with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open 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). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* 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. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + 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. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + 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. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + 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). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + 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 ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + 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. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + 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. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured 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. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/plugins/zerogs/opengl/Win32/zlib/infback.c b/plugins/zerogs/opengl/Win32/zlib/infback.c new file mode 100644 index 0000000000..5cf5d22cf9 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/infback.c @@ -0,0 +1,619 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_stream FAR *strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/inffast.c b/plugins/zerogs/opengl/Win32/zlib/inffast.c new file mode 100644 index 0000000000..63aa4402fc --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/inffast.c @@ -0,0 +1,305 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - 68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/plugins/zerogs/opengl/Win32/zlib/inffast.h b/plugins/zerogs/opengl/Win32/zlib/inffast.h new file mode 100644 index 0000000000..614fa7877d --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 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. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/plugins/zerogs/opengl/Win32/zlib/inffixed.h b/plugins/zerogs/opengl/Win32/zlib/inffixed.h new file mode 100644 index 0000000000..423d5c5b50 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* 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 const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,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,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,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,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,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,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/plugins/zerogs/opengl/Win32/zlib/inflate.c b/plugins/zerogs/opengl/Win32/zlib/inflate.c new file mode 100644 index 0000000000..71fe3ccd0e --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/inflate.c @@ -0,0 +1,1270 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->wsize = 0; + state->whave = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + if (BITS(4) + 8 > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + } while (len && copy < have); + if (state->flags & 0x02000) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->mode != DICT) return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) return Z_DATA_ERROR; + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + 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 ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + *dest = *source; + *copy = *state; + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) + zmemcpy(window, state->window, 1U << state->wbits); + copy->window = window; + dest->state = (voidpf)copy; + return Z_OK; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/inflate.h b/plugins/zerogs/opengl/Win32/zlib/inflate.h new file mode 100644 index 0000000000..b6965127b9 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/inflate.h @@ -0,0 +1,117 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2003 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. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ +#ifdef GUNZIP + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ +#endif + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ +#ifdef GUNZIP + LENGTH, /* i: waiting for 32-bit length (gzip) */ +#endif + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/plugins/zerogs/opengl/Win32/zlib/inftrees.c b/plugins/zerogs/opengl/Win32/zlib/inftrees.c new file mode 100644 index 0000000000..55fd27b601 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/inftrees.c @@ -0,0 +1,321 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.1 Copyright 1995-2003 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. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 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}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 66}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 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, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || (codes - count[0] != 1))) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/inftrees.h b/plugins/zerogs/opengl/Win32/zlib/inftrees.h new file mode 100644 index 0000000000..1dbfe53a6a --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2003 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. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 code structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 1440 +#define MAXD 154 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/plugins/zerogs/opengl/Win32/zlib/trees.c b/plugins/zerogs/opengl/Win32/zlib/trees.c new file mode 100644 index 0000000000..d0bce9f2f1 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/trees.c @@ -0,0 +1,1215 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2003 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id: trees.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {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}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {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}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/plugins/zerogs/opengl/Win32/zlib/trees.h b/plugins/zerogs/opengl/Win32/zlib/trees.h new file mode 100644 index 0000000000..1ca868b848 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/plugins/zerogs/opengl/Win32/zlib/uncompr.c b/plugins/zerogs/opengl/Win32/zlib/uncompr.c new file mode 100644 index 0000000000..82ebef75f8 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: uncompr.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + 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. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/plugins/zerogs/opengl/Win32/zlib/zconf.h b/plugins/zerogs/opengl/Win32/zlib/zconf.h new file mode 100644 index 0000000000..b073c9e60d --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/zconf.h @@ -0,0 +1,323 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflatePrime z_deflatePrime +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* 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 */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#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 +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +#define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/zerogs/opengl/Win32/zlib/zlib.h b/plugins/zerogs/opengl/Win32/zlib/zlib.h new file mode 100644 index 0000000000..d54ac9433f --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/zlib.h @@ -0,0 +1,1200 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.1, November 17th, 2003 + + Copyright (C) 1995-2003 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 http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.1" +#define ZLIB_VERNUM 0x1210 + +/* + 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 compressed data format used by the in-memory functions is the zlib + format, which is a zlib wrapper documented in RFC 1950, wrapped around a + deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + This library does not provide any functions to write gzip files in memory. + However such functions could be easily written using zlib's deflate function, + the documentation in the gzip RFC, and the examples in gzio.c. + + 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. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + 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 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() 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_RLE 3 +#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 (though see inflate()) */ + +#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 */ + +ZEXTERN const char * ZEXPORT 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. + */ + +/* +ZEXTERN int ZEXPORT 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(). +*/ + + +ZEXTERN int ZEXPORT 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). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + 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 + the value returned by deflateBound (see below). 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 far (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). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT 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). +*/ + + +/* +ZEXTERN int ZEXPORT 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.) +*/ + + +ZEXTERN int ZEXPORT 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 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. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it get to the next deflate block boundary. When decoding the zlib + or gzip format, this will cause inflate() to return immediately after the + header and before the first block. When doing a raw inflate, inflate() will + go ahead and process the first block, and will return when it gets to the end + of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + 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 approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (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 far (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() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + 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 check + value), 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. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT 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. +*/ + +/* +ZEXTERN int ZEXPORT 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. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). + + 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), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). 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. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. 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(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *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.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + 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(). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT 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. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. 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. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). + + 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.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *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(). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT inflateCopy 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 randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy 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. +*/ + +ZEXTERN int ZEXPORT 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). +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* 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. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *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 the value returned + by compressBound(sourceLen). 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. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *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 the value returned by + compressBound(sourceLen). 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. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *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 or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT 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", or 'R' for run-length encoding + as in "wb1R". (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). */ + +ZEXTERN gzFile ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc 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). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + 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). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN char * ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t 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. +*/ + +ZEXTERN int ZEXPORT 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) +*/ + +ZEXTERN z_off_t ZEXPORT 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) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT 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). +*/ + +ZEXTERN const char * ZEXPORT 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. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *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(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) 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: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, + unsigned char FAR *window, + 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)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/zerogs/opengl/Win32/zlib/zutil.c b/plugins/zerogs/opengl/Win32/zlib/zutil.c new file mode 100644 index 0000000000..db137f8a48 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/zutil.c @@ -0,0 +1,319 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1 << 16; +#endif +#ifdef NO_GZIP + flags += 1 << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1 << 20; +#endif +#ifdef FASTEST + flags += 1 << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1 << 25; +# ifdef HAS_vsprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1 << 26; +# endif +# endif +#else + flags += 1 << 24; +# ifdef NO_snprintf + flags += 1 << 25; +# ifdef HAS_sprintf_void + flags += 1 << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1 << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* does not exist on WCE */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/plugins/zerogs/opengl/Win32/zlib/zutil.h b/plugins/zerogs/opengl/Win32/zlib/zutil.h new file mode 100644 index 0000000000..e300f7c767 --- /dev/null +++ b/plugins/zerogs/opengl/Win32/zlib/zutil.h @@ -0,0 +1,258 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * 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. + */ + +/* @(#) $Id: zutil.h,v 1.1 2006/01/12 17:26:08 shadowpcsx2 Exp $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const 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 */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* 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 */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/Makefile.am b/plugins/zerogs/opengl/ZeroGSShaders/Makefile.am new file mode 100644 index 0000000000..97da2236f6 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/Makefile.am @@ -0,0 +1,2 @@ +noinst_PROGRAMS = zgsbuild +zgsbuild_SOURCES = zpipe.cpp zerogsshaders.cpp diff --git a/plugins/zerogs/opengl/ZeroGSShaders/ZLib.lib b/plugins/zerogs/opengl/ZeroGSShaders/ZLib.lib new file mode 100644 index 0000000000000000000000000000000000000000..7f4cf9ba6ed5cffb6d54b7d1cac4876a65cda678 GIT binary patch literal 101154 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%0A2!I2ly#qCEz6BGQhV03jx0a+yMAFU=!doz!>CU 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

sSdPO@+xFslc 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.sln b/plugins/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.sln new file mode 100644 index 0000000000..45a5aa122b --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroGSShaders", "ZeroGSShaders_2005.vcproj", "{811D47CC-E5F0-456A-918E-5908005E8FC0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release (to Public)|Win32 = Release (to Public)|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Debug|Win32.ActiveCfg = Debug|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Debug|Win32.Build.0 = Debug|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release (to Public)|Win32.ActiveCfg = Release (to Public)|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release (to Public)|Win32.Build.0 = Release (to Public)|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release|Win32.ActiveCfg = Release|Win32 + {811D47CC-E5F0-456A-918E-5908005E8FC0}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.vcproj b/plugins/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.vcproj new file mode 100644 index 0000000000..0dfc9ad0c1 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/ZeroGSShaders_2005.vcproj @@ -0,0 +1,335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/zerogs/opengl/ZeroGSShaders/copytozerogs.bat b/plugins/zerogs/opengl/ZeroGSShaders/copytozerogs.bat new file mode 100644 index 0000000000..32c9820600 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/copytozerogs.bat @@ -0,0 +1 @@ +copy .\Release\ZeroGSShaders.exe ..\ \ No newline at end of file diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp b/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp new file mode 100644 index 0000000000..a2d7815173 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.cpp @@ -0,0 +1,337 @@ +#define _CRT_SECURE_NO_DEPRECATE + +// Builds all possible shader files from ps2hw.fx and stores them in +// a preprocessed database +#include +#include + +#include +#include "zpipe.h" + +#include +#include + +#define SAFE_RELEASE(x) { if( (x) != NULL ) { (x)->Release(); x = NULL; } } + +#include +#include + +using namespace std; + +#include "zerogsshaders.h" + +char* srcfilename = "ps2hw.fx"; +char* dstfilename = "ps2hw.dat"; + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +struct SHADERINFO +{ + int type; + vector buf; +}; + +map mapShaders; +CGcontext g_cgcontext; + +void LoadShader(int index, const char* pshader, CGprofile prof, vector& vargs, int context) +{ + vector realargs; + realargs.reserve(16); + realargs.resize(vargs.size()); + if( vargs.size() > 0 ) + memcpy(&realargs[0], &vargs[0], realargs.size() * sizeof(realargs[0])); + realargs.push_back(context ? "-Ictx1" : "-Ictx0"); + realargs.push_back(NULL); + + CGprogram prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, srcfilename, prof, pshader, &realargs[0]); + if( !cgIsProgram(prog) ) { + printf("Failed to load shader %s: \n%s\n", pshader, cgGetLastListing(g_cgcontext)); + return; + } + + if( mapShaders.find(index) != mapShaders.end() ) { + printf("error: two shaders share the same index %d\n", index); + exit(0); + } + + if( !cgIsProgramCompiled(prog) ) + cgCompileProgram(prog); + + const char* pstr = cgGetProgramString(prog, CG_COMPILED_PROGRAM); + + const char* pprog = strstr(pstr, "#program"); + if( pprog == NULL ) { + printf("program field not found!\n"); + return; + } + pprog += 9; + const char* progend = strchr(pprog, '\r'); + if( progend == NULL ) progend = strchr(pprog, '\n'); + + if( progend == NULL ) { + printf("prog end not found!\n"); + return; + } + + const char* defname = "main"; + + SHADERINFO info; + info.type = 0; + info.buf.resize(strlen(pstr)+1); + + // change the program name to main + memset(&info.buf[0], 0, info.buf.size()); + memcpy(&info.buf[0], pstr, pprog-pstr); + memcpy(&info.buf[pprog-pstr], defname, 4); + memcpy(&info.buf[pprog-pstr+4], progend, strlen(pstr)-(progend-pstr)); + + if( mapShaders.find(index) != mapShaders.end() ) + printf("same shader\n"); + assert( mapShaders.find(index) == mapShaders.end() ); + mapShaders[index] = info; + + cgDestroyProgram(prog); +} + +int main(int argc, char** argv) +{ + printf("usage: [src] [dst] [opts]\n"); + + if( argc >= 2 ) srcfilename = argv[1]; + if( argc >= 3 ) dstfilename = argv[2]; + + FILE* fsrc = fopen(srcfilename, "r"); + if( fsrc == NULL ) { + printf("cannot open %s\n", srcfilename); + return 0; + } + fclose(fsrc); + + g_cgcontext = cgCreateContext(); + if( !cgIsContext(g_cgcontext) ) { + printf("failed to create cg context\n"); + return -1; + } + + CGprofile cgvProf = CG_PROFILE_ARBVP1; + CGprofile cgfProf = CG_PROFILE_ARBFP1; + if( !cgGLIsProfileSupported(cgvProf) != CG_TRUE ) { + printf("arbvp1 not supported\n"); + return 0; + } + if( !cgGLIsProfileSupported(cgfProf) != CG_TRUE ) { + printf("arbfp1 not supported\n"); + return 0; + } + + cgGLEnableProfile(cgvProf); + cgGLEnableProfile(cgfProf); + cgGLSetOptimalOptions(cgvProf); + cgGLSetOptimalOptions(cgfProf); + + vector vmacros; + + LoadShader(SH_BITBLTVS, "BitBltVS", cgvProf, vmacros, 0); + LoadShader(SH_BITBLTPS, "BitBltPS", cgfProf, vmacros, 0); + LoadShader(SH_BITBLTDEPTHPS, "BitBltDepthPS", cgfProf, vmacros, 0); + LoadShader(SH_BITBLTDEPTHMRTPS, "BitBltDepthMRTPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCTARGPS, "CRTCTargPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCPS, "CRTCPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTC_NEARESTPS, "CRTCPS_Nearest", cgfProf, vmacros, 0); + LoadShader(SH_CRTC24PS, "CRTC24PS", cgfProf, vmacros, 0); + LoadShader(SH_ZEROPS, "ZeroPS", cgfProf, vmacros, 0); + LoadShader(SH_BASETEXTUREPS, "BaseTexturePS", cgfProf, vmacros, 0); + LoadShader(SH_BITBLTAAPS, "BitBltPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCTARGINTERPS, "CRTCTargInterPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCINTERPS, "CRTCInterPS", cgfProf, vmacros, 0); + LoadShader(SH_CRTCINTER_NEARESTPS, "CRTCInterPS_Nearest", cgfProf, vmacros, 0); + LoadShader(SH_CRTC24INTERPS, "CRTC24InterPS", cgfProf, vmacros, 0); + LoadShader(SH_CONVERT16TO32PS, "Convert16to32PS", cgfProf, vmacros, 0); + LoadShader(SH_CONVERT32TO16PS, "Convert32to16PS", cgfProf, vmacros, 0); + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + // load the texture shaders + char str[255], strdir[255]; + + strcpy(strdir, srcfilename); + int i = (int)strlen(strdir); + while(i > 0) { + if( strdir[i-1] == '/' || strdir[i-1] == '\\' ) + break; + --i; + } + + strdir[i] = 0; + + for(i = 0; i < ARRAYSIZE(vsshaders); ++i) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + + if( writedepth ) vmacros.push_back("-DWRITE_DEPTH"); + LoadShader(vsshaders[i]|(writedepth?SH_WRITEDEPTH:0), pvsshaders[i], cgvProf, vmacros, 0); + LoadShader(vsshaders[i]|(writedepth?SH_WRITEDEPTH:0)|SH_CONTEXT1, pvsshaders[i], cgvProf, vmacros, 1); + if( writedepth ) vmacros.pop_back(); + } + } + + const int psshaders[2] = { SH_REGULARPS, SH_REGULARFOGPS }; + const char* ppsshaders[2] = { "RegularPS", "RegularFogPS" }; + + for(i = 0; i < ARRAYSIZE(psshaders); ++i) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + if( writedepth ) vmacros.push_back("-DWRITE_DEPTH"); + LoadShader(psshaders[i]|(writedepth?SH_WRITEDEPTH:0), ppsshaders[i], cgfProf, vmacros, 0); + if( writedepth ) vmacros.pop_back(); + } + } + + printf("creating shaders, note that ctx0/ps2hw_ctx.fx, and ctx1/ps2hw_ctx.fx are required\n"); + vmacros.resize(0); + + for(int texwrap = 0; texwrap < NUM_TEXWRAPS; ++texwrap ) { + + if( g_pPsTexWrap[texwrap] != NULL ) + vmacros.push_back(g_pPsTexWrap[texwrap]); + + for(int context = 0; context < 2; ++context) { + + for(int texfilter = 0; texfilter < NUM_FILTERS; ++texfilter) { + for(int fog = 0; fog < 2; ++fog ) { + for(int writedepth = 0; writedepth < 2; ++writedepth ) { + + if( writedepth ) + vmacros.push_back("-DWRITE_DEPTH"); + + for(int testaem = 0; testaem < 2; ++testaem ) { + + if( testaem ) + vmacros.push_back("-DTEST_AEM"); + + for(int exactcolor = 0; exactcolor < 2; ++exactcolor ) { + + if( exactcolor ) + vmacros.push_back("-DEXACT_COLOR"); + + // 32 + sprintf(str, "Texture%s%d_32PS", fog?"Fog":"", texfilter); + + vmacros.push_back("-DACCURATE_DECOMPRESSION"); + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); + vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(0, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + if( texfilter == 0 ) { + // tex32 + sprintf(str, "Texture%s%d_tex32PS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(1, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + // clut32 + sprintf(str, "Texture%s%d_clut32PS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(2, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + // tex32to16 + sprintf(str, "Texture%s%d_tex32to16PS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(3, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + + // tex16to8h + sprintf(str, "Texture%s%d_tex16to8hPS", fog?"Fog":"", texfilter); + +// vmacros.push_back("-DACCURATE_DECOMPRESSION"); +// LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, SHADER_ACCURATE), str, cgfProf, vmacros, context); +// vmacros.pop_back(); + + LoadShader(GET_SHADER_INDEX(4, texfilter, texwrap, fog, writedepth, testaem, exactcolor, context, 0), str, cgfProf, vmacros, context); + } + + if( exactcolor ) + vmacros.pop_back(); + } + + if( testaem ) + vmacros.pop_back(); + } + + if( writedepth ) + vmacros.pop_back(); + } + } + } + } + + if( g_pPsTexWrap[texwrap] != NULL ) + vmacros.pop_back(); + } + + if( vmacros.size() != 0 ) + printf("error with macros!\n"); + + // create the database + + int num = (int)mapShaders.size(); + + // first compress + vector buffer; + buffer.reserve(10000000); // 10mb + buffer.resize(sizeof(SHADERHEADER)*num); + + i = 0; + for(map::iterator it = mapShaders.begin(); it != mapShaders.end(); ++it, ++i) { + SHADERHEADER h; + h.index = it->first | it->second.type; + h.offset = (int)buffer.size(); + h.size = (int)it->second.buf.size(); + + memcpy(&buffer[0] + i*sizeof(SHADERHEADER), &h, sizeof(SHADERHEADER)); + + size_t cur = buffer.size(); + buffer.resize(cur + it->second.buf.size()); + memcpy(&buffer[cur], &it->second.buf[0], it->second.buf.size()); + } + + int compressed_size; + int real_size = (int)buffer.size(); + vector dst; + dst.resize(buffer.size()); + def(&buffer[0], &dst[0], (int)buffer.size(), &compressed_size); + + // write to file + // fmt: num shaders, size of compressed, compressed data + FILE* fdst = fopen(dstfilename, "wb"); + if( fdst == NULL ) { + printf("failed to open %s\n", dstfilename); + return 0; + } + + fwrite(&num, 4, 1, fdst); + fwrite(&compressed_size, 4, 1, fdst); + fwrite(&real_size, 4, 1, fdst); + fwrite(&dst[0], compressed_size, 1, fdst); + + fclose(fdst); + + printf("wrote %s\n", dstfilename); + + cgDestroyContext(g_cgcontext); + + return 0; +} diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.h b/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.h new file mode 100644 index 0000000000..e2695618d5 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zerogsshaders.h @@ -0,0 +1,89 @@ +#include +#include + +#define NUM_FILTERS 2 // texture filtering +#define NUM_TYPES 5 // types of texture read modes +#define NUM_TEXWRAPS 4 // texture wrapping + +#define SHADER_REDUCED 1 // equivalent to ps2.0 +#define SHADER_ACCURATE 2 // for older cards with less accurate math (ps2.x+) + +#define NUM_SHADERS (NUM_FILTERS*NUM_TYPES*NUM_TEXWRAPS*32) // # shaders for a given ps + +const static char* g_pShaders[] = { "full", "reduced", "accurate", "accurate-reduced" }; +const static char* g_pPsTexWrap[] = { "-DREPEAT", "-DCLAMP", "-DREGION_REPEAT", NULL }; +const static char* g_pTexTypes[] = { "32", "tex32", "clut32", "tex32to16", "tex16to8h" }; + +#define TEXWRAP_REPEAT 0 +#define TEXWRAP_CLAMP 1 +#define TEXWRAP_REGION_REPEAT 2 +#define TEXWRAP_REPEAT_CLAMP 3 + +inline int GET_SHADER_INDEX(int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int context, int ps) +{ + return type + texfilter*NUM_TYPES + NUM_FILTERS*NUM_TYPES*texwrap + NUM_TEXWRAPS*NUM_FILTERS*NUM_TYPES*(fog+2*writedepth+4*testaem+8*exactcolor+16*context+32*ps); +} + +extern CGcontext g_cgcontext; + +static CGprogram LoadShaderFromType(const char* srcdir, const char* srcfile, int type, int texfilter, int texwrap, int fog, int writedepth, int testaem, int exactcolor, int ps, int context) +{ + assert( texwrap < NUM_TEXWRAPS); + assert( type < NUM_TYPES ); + + char str[255], strctx[255]; + sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); + sprintf(strctx, "-I%s%s", srcdir, context?"ctx1":"ctx0"); + + vector macros; + macros.push_back(strctx); +#ifdef _DEBUG + macros.push_back("-bestprecision"); +#endif + if( g_pPsTexWrap[texwrap] != NULL ) macros.push_back(g_pPsTexWrap[texwrap]); + if( writedepth ) macros.push_back("-DWRITE_DEPTH"); + if( testaem ) macros.push_back("-DTEST_AEM"); + if( exactcolor ) macros.push_back("-DEXACT_COLOR"); + if( ps & SHADER_ACCURATE ) macros.push_back("-DACCURATE_DECOMPRESSION"); + macros.push_back(NULL); + + CGprogram prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, srcfile, CG_PROFILE_ARBFP1, str, ¯os[0]); + if( !cgIsProgram(prog) ) { + printf("Failed to load shader %s: \n%s\n", str, cgGetLastListing(g_cgcontext)); + return NULL; + } + + return prog; +} + +struct SHADERHEADER +{ + unsigned int index, offset, size; // if highest bit of index is set, pixel shader +}; + +#define SH_WRITEDEPTH 0x2000 // depth is written +#define SH_CONTEXT1 0x1000 // context1 is used + +#define SH_REGULARVS 0x8000 +#define SH_TEXTUREVS 0x8001 +#define SH_REGULARFOGVS 0x8002 +#define SH_TEXTUREFOGVS 0x8003 +#define SH_REGULARPS 0x8004 +#define SH_REGULARFOGPS 0x8005 +#define SH_BITBLTVS 0x8006 +#define SH_BITBLTPS 0x8007 +#define SH_BITBLTDEPTHPS 0x8009 +#define SH_CRTCTARGPS 0x800a +#define SH_CRTCPS 0x800b +#define SH_CRTC24PS 0x800c +#define SH_ZEROPS 0x800e +#define SH_BASETEXTUREPS 0x800f +#define SH_BITBLTAAPS 0x8010 +#define SH_CRTCTARGINTERPS 0x8012 +#define SH_CRTCINTERPS 0x8013 +#define SH_CRTC24INTERPS 0x8014 +#define SH_BITBLTDEPTHMRTPS 0x8016 +#define SH_CONVERT16TO32PS 0x8020 +#define SH_CONVERT32TO16PS 0x8021 +#define SH_CRTC_NEARESTPS 0x8022 +#define SH_CRTCINTER_NEARESTPS 0x8023 diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/crc32.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/crc32.h new file mode 100644 index 0000000000..5de49bc978 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/deflate.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/deflate.h new file mode 100644 index 0000000000..0b5dd9bb49 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * 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. + */ + +/* @(#) $Id: deflate.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffast.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffast.h new file mode 100644 index 0000000000..614fa7877d --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 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. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h new file mode 100644 index 0000000000..423d5c5b50 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* 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 const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,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,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,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,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,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,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inflate.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inflate.h new file mode 100644 index 0000000000..fbbc871432 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 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. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h new file mode 100644 index 0000000000..dc0fd567ea --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 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. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/trees.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/trees.h new file mode 100644 index 0000000000..1ca868b848 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.h new file mode 100644 index 0000000000..a5248c8b65 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* 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 */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#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 +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h new file mode 100644 index 0000000000..48200f8d72 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zconf.in.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.in.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* 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 */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#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 +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zlib.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zlib.h new file mode 100644 index 0000000000..62d0e4675b --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 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 http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + 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 compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + 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. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + 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 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() 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_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#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 */ + +ZEXTERN const char * ZEXPORT 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. + */ + +/* +ZEXTERN int ZEXPORT 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(). +*/ + + +ZEXTERN int ZEXPORT 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. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + 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 + 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). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + 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 + the value returned by deflateBound (see below). 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 far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). 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). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT 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). +*/ + + +/* +ZEXTERN int ZEXPORT 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.) +*/ + + +ZEXTERN int ZEXPORT 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 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. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + 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 approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (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 far (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() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + 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 check + value), 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. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT 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. +*/ + +/* +ZEXTERN int ZEXPORT 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. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + 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), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). 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. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + 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(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *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. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + 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.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + 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(). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT 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. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. 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. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + 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 null strm). 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.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *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 that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + 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(). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT inflateCopy 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 randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy 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. +*/ + +ZEXTERN int ZEXPORT 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). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* 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. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *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 the value returned + by compressBound(sourceLen). 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. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *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 the value returned by + compressBound(sourceLen). 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. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *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 or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT 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", or 'R' for run-length encoding + as in "wb1R". (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). */ + +ZEXTERN gzFile ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc 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). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + 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). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN char * ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t 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. +*/ + +ZEXTERN int ZEXPORT 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) +*/ + +ZEXTERN z_off_t ZEXPORT 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) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT 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). +*/ + +ZEXTERN const char * ZEXPORT 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. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *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(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + 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)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zlib/zutil.h b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zutil.h new file mode 100644 index 0000000000..b691f27c26 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * 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. + */ + +/* @(#) $Id: zutil.h,v 1.2 2006/03/02 00:10:34 zerocool Exp $ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const 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 */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* 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 */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zpipe.cpp b/plugins/zerogs/opengl/ZeroGSShaders/zpipe.cpp new file mode 100644 index 0000000000..4a94499be8 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zpipe.cpp @@ -0,0 +1,115 @@ +// zpipe.cpp : Defines the entry point for the console application. +// + +#include + +#include +#include +#include + +//#define ZLIB_WINAPI +#include + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress) ; + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) +{ + z_stream strm; + + int ret;//, flush; + unsigned have; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION) ; + if (ret != Z_OK) + return ret; + + /* compress */ + strm.avail_in = bytes_to_compress ; + strm.avail_out = bytes_to_compress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + + ret = deflate(&strm, Z_FINISH) ; + have = bytes_to_compress - strm.avail_out ; + *bytes_after_compressed = have ; + + assert(ret == Z_STREAM_END); /* stream will be complete */ + + /* clean up and return */ + (void)deflateEnd(&strm); + return Z_OK; +} + +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes) +{ + z_stream strm; + + int ret; + //unsigned have; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + + /* decompress */ + strm.avail_in = bytes_to_decompress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + strm.avail_out = maximum_after_decompress ; + + ret = inflate(&strm, Z_NO_FLUSH) ; + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + + assert(strm.avail_in == 0); /* all input will be used */ + + if( outbytes != NULL ) + *outbytes = strm.total_out; + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +/* report a zlib or i/o error */ +void zerr(int ret) +{ + fputs("zpipe: ", stderr); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + fputs("error reading stdin\n", stderr); + if (ferror(stdout)) + fputs("error writing stdout\n", stderr); + break; + case Z_STREAM_ERROR: + fputs("invalid compression level\n", stderr); + break; + case Z_DATA_ERROR: + fputs("invalid or incomplete deflate data\n", stderr); + break; + case Z_MEM_ERROR: + fputs("out of memory\n", stderr); + break; + case Z_VERSION_ERROR: + fputs("zlib version mismatch!\n", stderr); + } +} diff --git a/plugins/zerogs/opengl/ZeroGSShaders/zpipe.h b/plugins/zerogs/opengl/ZeroGSShaders/zpipe.h new file mode 100644 index 0000000000..cb96229553 --- /dev/null +++ b/plugins/zerogs/opengl/ZeroGSShaders/zpipe.h @@ -0,0 +1,7 @@ +#ifndef zpipe_h +#define zpipe_h + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes); + +#endif diff --git a/plugins/zerogs/opengl/buildshaders.bat b/plugins/zerogs/opengl/buildshaders.bat new file mode 100644 index 0000000000..c7698558ae --- /dev/null +++ b/plugins/zerogs/opengl/buildshaders.bat @@ -0,0 +1,3 @@ +ZeroGSShaders.exe ps2hw.fx ps2hw.dat +del Win32\ps2hw.dat Win32\Release\*.res Win32\Debug\*.res +move /y ps2hw.dat Win32\ps2hw.dat \ No newline at end of file diff --git a/plugins/zerogs/opengl/common.h b/plugins/zerogs/opengl/common.h new file mode 100644 index 0000000000..280d62a70c --- /dev/null +++ b/plugins/zerogs/opengl/common.h @@ -0,0 +1,1142 @@ +/** + * @file common.h + * common internal api header. + */ + +#ifndef COMMON_H +#define COMMON_H + +#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# define CONFIG_WIN32 +#endif + +//#define ALT_BITSTREAM_WRITER +//#define ALIGNED_BITSTREAM_WRITER + +#define ALT_BITSTREAM_READER +//#define LIBMPEG2_BITSTREAM_READER +//#define A32_BITSTREAM_READER +#define LIBMPEG2_BITSTREAM_READER_HACK //add BERO + +#ifdef HAVE_AV_CONFIG_H +/* only include the following when compiling package */ +# include "config.h" + +# include +# include +# include +# include +# ifndef __BEOS__ +# include +# else +# include "berrno.h" +# endif +# include + +# ifndef ENODATA +# define ENODATA 61 +# endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include +#ifndef offsetof +# define offsetof(T,F) ((unsigned int)((char *)&((T *)0)->F)) +#endif + +#define AVOPTION_CODEC_BOOL(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_BOOL } +#define AVOPTION_CODEC_DOUBLE(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_DOUBLE, minv, maxv, defval } +#define AVOPTION_CODEC_FLAG(name, help, field, flag, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_FLAG, flag, 0, defval } +#define AVOPTION_CODEC_INT(name, help, field, minv, maxv, defval) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_INT, minv, maxv, defval } +#define AVOPTION_CODEC_STRING(name, help, field, str, val) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_STRING, .defval = val, .defstr = str } +#define AVOPTION_CODEC_RCOVERRIDE(name, help, field) \ + { name, help, offsetof(AVCodecContext, field), FF_OPT_TYPE_RCOVERRIDE, .defval = 0, .defstr = NULL } +#define AVOPTION_SUB(ptr) { .name = NULL, .help = (const char*)ptr } +#define AVOPTION_END() AVOPTION_SUB(NULL) + +struct AVOption; +#ifdef HAVE_MMX +extern const struct AVOption avoptions_common[3 + 5]; +#else +extern const struct AVOption avoptions_common[3]; +#endif +extern const struct AVOption avoptions_workaround_bug[11]; + +#endif /* HAVE_AV_CONFIG_H */ + +/* Suppress restrict if it was not defined in config.h. */ +#ifndef restrict +# define restrict +#endif + +#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define always_inline __attribute__((always_inline)) inline +#else +# define always_inline inline +#endif + +#ifdef CONFIG_WIN32 + +/* windows */ + +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +typedef signed char int8_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; + +# ifndef __MINGW32__ +# define int64_t_C(c) (c ## i64) +# define uint64_t_C(c) (c ## i64) + +# define inline __inline + +# else +# define int64_t_C(c) (c ## LL) +# define uint64_t_C(c) (c ## ULL) +# endif /* __MINGW32__ */ + +# ifdef _DEBUG +# define DEBUG +# endif + +# define snprintf _snprintf +# define vsnprintf _vsnprintf + +/* CONFIG_WIN32 end */ +#elif defined (CONFIG_OS2) +/* OS/2 EMX */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +#ifdef USE_FASTMEMCPY +#include "fastmemcpy.h" +#endif + +#include + +#endif /* HAVE_AV_CONFIG_H */ + +/* CONFIG_OS2 end */ +#else + +/* unix */ + +#include + +#ifndef int64_t_C +#define int64_t_C(c) (c ## LL) +#define uint64_t_C(c) (c ## ULL) +#endif + +#ifdef HAVE_AV_CONFIG_H + +# ifdef USE_FASTMEMCPY +# include "fastmemcpy.h" +# endif +# endif /* HAVE_AV_CONFIG_H */ + +#endif /* !CONFIG_WIN32 && !CONFIG_OS2 */ + +#ifdef HAVE_AV_CONFIG_H + +# include "bswap.h" + +# if defined(__MINGW32__) || defined(__CYGWIN__) || \ + defined(__OS2__) || (defined (__OpenBSD__) && !defined(__ELF__)) +# define MANGLE(a) "_" #a +# else +# define MANGLE(a) #a +# endif + +/* debug stuff */ + +# ifndef DEBUG +# define NDEBUG +# endif +# include + +/* dprintf macros */ +# if defined(CONFIG_WIN32) && !defined(__MINGW32__) + +inline void dprintf(const char* fmt,...) {} + +# else + +# ifdef DEBUG +# define dprintf(fmt,args...) printf(fmt, ## args) +# else +# define dprintf(fmt,args...) +# endif + +# endif /* !CONFIG_WIN32 */ + +# define av_abort() do { fprintf(stderr, "Abort at %s:%d\n", __FILE__, __LINE__); abort(); } while (0) + +//rounded divison & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + (1<<((b)-1)))>>(b) : ((a) + (1<<((b)-1))-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +#define ABS(a) ((a) >= 0 ? (a) : (-(a))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + +extern const uint32_t inverse[256]; + +#ifdef ARCH_X86 +# define FASTDIV(a,b) \ + ({\ + int ret,dmy;\ + asm volatile(\ + "mull %3"\ + :"=d"(ret),"=a"(dmy)\ + :"1"(a),"g"(inverse[b])\ + );\ + ret;\ + }) +#elif defined(CONFIG_FASTDIV) +# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a)*inverse[b])>>32)) +#else +# define FASTDIV(a,b) ((a)/(b)) +#endif + +#ifdef ARCH_X86 +// avoid +32 for shift optimization (gcc should do that ...) +static inline int32_t NEG_SSR32( int32_t a, int8_t s){ + asm ("sarl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +static inline uint32_t NEG_USR32(uint32_t a, int8_t s){ + asm ("shrl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} +#else +# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) +# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) +#endif + +/* bit output */ + +struct PutBitContext; + +typedef void (*WriteDataFunc)(void *, uint8_t *, int); + +typedef struct PutBitContext { +#ifdef ALT_BITSTREAM_WRITER + uint8_t *buf, *buf_end; + int index; +#else + uint32_t bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr, *buf_end; +#endif + int64_t data_out_size; /* in bytes */ +} PutBitContext; + +void init_put_bits(PutBitContext *s, + uint8_t *buffer, int buffer_size, + void *opaque, + void (*write_data)(void *, uint8_t *, int)); + +int64_t get_bit_count(PutBitContext *s); /* XXX: change function name */ +void align_put_bits(PutBitContext *s); +void flush_put_bits(PutBitContext *s); +void put_string(PutBitContext * pbc, char *s); + +/* bit input */ + +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; +#ifdef ALT_BITSTREAM_READER + int index; +#elif defined LIBMPEG2_BITSTREAM_READER + uint8_t *buffer_ptr; + uint32_t cache; + int bit_count; +#elif defined A32_BITSTREAM_READER + uint32_t *buffer_ptr; + uint32_t cache0; + uint32_t cache1; + int bit_count; +#endif + int size_in_bits; +} GetBitContext; + +static inline int get_bits_count(GetBitContext *s); + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table)[2]; ///< code, bits + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +#ifdef ARCH_SPARC64 +#define UNALIGNED_STORES_ARE_BAD +#endif + +/* used to avoid missaligned exceptions on some archs (alpha, ...) */ +#ifdef ARCH_X86 +# define unaligned32(a) (*(uint32_t*)(a)) +#else +# ifdef __GNUC__ +static inline uint32_t unaligned32(const void *v) { + struct Unaligned { + uint32_t i; + } __attribute__((packed)); + + return ((const struct Unaligned *) v)->i; +} +# elif defined(__DECC) +static inline uint32_t unaligned32(const void *v) { + return *(const __unaligned uint32_t *) v; +} +# else +static inline uint32_t unaligned32(const void *v) { + return *(const uint32_t *) v; +} +# endif +#endif //!ARCH_X86 + +#ifndef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ + unsigned int bit_buf; + int bit_left; + +#ifdef STATS + st_out_bit_counts[st_current_index] += n; +#endif + // DEBUG_LOG("put_bits=%d %x\n", n, value); + assert(n == 32 || value < (1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + // DEBUG_LOG("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); + /* XXX: optimize */ + if (n < bit_left) { + bit_buf = (bit_buf<> (n - bit_left); +#ifdef UNALIGNED_STORES_ARE_BAD + if (3 & (int) s->buf_ptr) { + s->buf_ptr[0] = bit_buf >> 24; + s->buf_ptr[1] = bit_buf >> 16; + s->buf_ptr[2] = bit_buf >> 8; + s->buf_ptr[3] = bit_buf ; + } else +#endif + *(uint32_t *)s->buf_ptr = be2me_32(bit_buf); + //DEBUG_LOG("bitbuf = %08x\n", bit_buf); + s->buf_ptr+=4; + bit_left+=32 - n; + bit_buf = value; + } + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} +#endif + + +#ifdef ALT_BITSTREAM_WRITER +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ +# ifdef ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl %0, %%ecx \n\t" + "xorl %%eax, %%eax \n\t" + "shrdl %%cl, %1, %%eax \n\t" + "shrl %%cl, %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "andl $0xFFFFFFFC, %%ecx \n\t" + "bswapl %1 \n\t" + "orl %1, (%2, %%ecx) \n\t" + "bswapl %%eax \n\t" + "addl %3, %0 \n\t" + "movl %%eax, 4(%2, %%ecx) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value<<(-n)) + : "%eax", "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= ((uint32_t *)s->buf)+(index>>5); + + value<<= 32-n; + + ptr[0] |= be2me_32(value>>(index&31)); + ptr[1] = be2me_32(value<<(32-(index&31))); +//if(n>24) DEBUG_LOG("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# else //ALIGNED_BITSTREAM_WRITER +# ifdef ARCH_X86 + asm volatile( + "movl $7, %%ecx \n\t" + "andl %0, %%ecx \n\t" + "addl %3, %%ecx \n\t" + "negl %%ecx \n\t" + "shll %%cl, %1 \n\t" + "bswapl %1 \n\t" + "movl %0, %%ecx \n\t" + "shrl $3, %%ecx \n\t" + "orl %1, (%%ecx, %2) \n\t" + "addl %3, %0 \n\t" + "movl $0, 4(%%ecx, %2) \n\t" + : "=&r" (s->index), "=&r" (value) + : "r" (s->buf), "r" (n), "0" (s->index), "1" (value) + : "%ecx" + ); +# else + int index= s->index; + uint32_t *ptr= (uint32_t*)(((uint8_t *)s->buf)+(index>>3)); + + ptr[0] |= be2me_32(value<<(32-n-(index&7) )); + ptr[1] = 0; +//if(n>24) DEBUG_LOG("%d %d\n", n, value); + index+= n; + s->index= index; +# endif +# endif //!ALIGNED_BITSTREAM_WRITER +} +#endif + + +static inline uint8_t* pbBufPtr(PutBitContext *s) +{ +#ifdef ALT_BITSTREAM_WRITER + return s->buf + (s->index>>3); +#else + return s->buf_ptr; +#endif +} + +/* Bitstream reader API docs: +name + abritary name which is used as prefix for the internal variables + +gb + getbitcontext + +OPEN_READER(name, gb) + loads gb into local variables + +CLOSE_READER(name, gb) + stores local vars in gb + +UPDATE_CACHE(name, gb) + refills the internal cache from the bitstream + after this call at least MIN_CACHE_BITS will be available, + +GET_CACHE(name, gb) + will output the contents of the internal cache, next bit is MSB of 32 or 64 bit (FIXME 64bit) + +SHOW_UBITS(name, gb, num) + will return the nest num bits + +SHOW_SBITS(name, gb, num) + will return the nest num bits and do sign extension + +SKIP_BITS(name, gb, num) + will skip over the next num bits + note, this is equinvalent to SKIP_CACHE; SKIP_COUNTER + +SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache (note SKIP_COUNTER MUST be called before UPDATE_CACHE / CLOSE_READER) + +SKIP_COUNTER(name, gb, num) + will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS) + +LAST_SKIP_CACHE(name, gb, num) + will remove the next num bits from the cache if it is needed for UPDATE_CACHE otherwise it will do nothing + +LAST_SKIP_BITS(name, gb, num) + is equinvalent to SKIP_LAST_CACHE; SKIP_COUNTER + +for examples see get_bits, show_bits, skip_bits, get_vlc +*/ + +static inline int unaligned32_be(const void *v) +{ +#ifdef CONFIG_ALIGN + const uint8_t *p=v; + return (((p[0]<<8) | p[1])<<16) | (p[2]<<8) | (p[3]); +#else + return be2me_32( unaligned32(v)); //original +#endif +} + +#ifdef ALT_BITSTREAM_READER +# define MIN_CACHE_BITS 25 + +# define OPEN_READER(name, gb)\ + int name##_index= (gb)->index;\ + int name##_cache= 0;\ + +# define CLOSE_READER(name, gb)\ + (gb)->index= name##_index;\ + +# define UPDATE_CACHE(name, gb)\ + name##_cache= unaligned32_be( ((uint8_t *)(gb)->buffer)+(name##_index>>3) ) << (name##_index&0x07);\ + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +// FIXME name? +# define SKIP_COUNTER(name, gb, num)\ + name##_index += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) ; + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return s->index; +} +#elif defined LIBMPEG2_BITSTREAM_READER +//libmpeg2 like reader + +# define MIN_CACHE_BITS 17 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + int name##_cache= (gb)->cache;\ + uint8_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache= name##_cache;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +#ifdef LIBMPEG2_BITSTREAM_READER_HACK + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= (int)be2me_16(*(uint16_t*)name##_buffer_ptr) << name##_bit_count;\ + ((uint16_t*)name##_buffer_ptr)++;\ + name##_bit_count-= 16;\ + }\ + +#else + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count >= 0){\ + name##_cache+= ((name##_buffer_ptr[0]<<8) + name##_buffer_ptr[1]) << name##_bit_count;\ + name##_buffer_ptr+=2;\ + name##_bit_count-= 16;\ + }\ + +#endif + +# define SKIP_CACHE(name, gb, num)\ + name##_cache <<= (num);\ + +# define SKIP_COUNTER(name, gb, num)\ + name##_bit_count += (num);\ + +# define SKIP_BITS(name, gb, num)\ + {\ + SKIP_CACHE(name, gb, num)\ + SKIP_COUNTER(name, gb, num)\ + }\ + +# define LAST_SKIP_BITS(name, gb, num) SKIP_BITS(name, gb, num) +# define LAST_SKIP_CACHE(name, gb, num) SKIP_CACHE(name, gb, num) + +# define SHOW_UBITS(name, gb, num)\ + NEG_USR32(name##_cache, num) + +# define SHOW_SBITS(name, gb, num)\ + NEG_SSR32(name##_cache, num) + +# define GET_CACHE(name, gb)\ + ((uint32_t)name##_cache) + +static inline int get_bits_count(GetBitContext *s){ + return (s->buffer_ptr - s->buffer)*8 - 16 + s->bit_count; +} + +#elif defined A32_BITSTREAM_READER + +# define MIN_CACHE_BITS 32 + +# define OPEN_READER(name, gb)\ + int name##_bit_count=(gb)->bit_count;\ + uint32_t name##_cache0= (gb)->cache0;\ + uint32_t name##_cache1= (gb)->cache1;\ + uint32_t * name##_buffer_ptr=(gb)->buffer_ptr;\ + +# define CLOSE_READER(name, gb)\ + (gb)->bit_count= name##_bit_count;\ + (gb)->cache0= name##_cache0;\ + (gb)->cache1= name##_cache1;\ + (gb)->buffer_ptr= name##_buffer_ptr;\ + +# define UPDATE_CACHE(name, gb)\ + if(name##_bit_count > 0){\ + const uint32_t next= be2me_32( *name##_buffer_ptr );\ + name##_cache0 |= NEG_USR32(next,name##_bit_count);\ + name##_cache1 |= next<buffer_ptr - s->buffer)*8 - 32 + s->bit_count; +} + +#endif + +/** + * read mpeg1 dc style vlc (sign bit + mantisse with no MSB). + * if MSB not set it is negative + * @param n length in bits + * @author BERO + */ +static inline int get_xbits(GetBitContext *s, int n){ + register int tmp; + register int32_t cache; + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + cache = GET_CACHE(re,s); + if ((int32_t)cache<0) { //MSB=1 + tmp = NEG_USR32(cache,n); + } else { + // tmp = (-1<index+=n for the ALT_READER :)) + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + LAST_SKIP_BITS(re, s, n) + CLOSE_READER(re, s) +} + +static inline unsigned int get_bits1(GetBitContext *s){ +#ifdef ALT_BITSTREAM_READER + int index= s->index; + uint8_t result= s->buffer[ index>>3 ]; + result<<= (index&0x07); + result>>= 8 - 1; + index++; + s->index= index; + + return result; +#else + return get_bits(s, 1); +#endif +} + +static inline unsigned int show_bits1(GetBitContext *s){ + return show_bits(s, 1); +} + +static inline void skip_bits1(GetBitContext *s){ + skip_bits(s, 1); +} + +void init_get_bits(GetBitContext *s, + const uint8_t *buffer, int buffer_size); + +int check_marker(GetBitContext *s, const char *msg); +void align_get_bits(GetBitContext *s); +int init_vlc(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size); +void free_vlc(VLC *vlc); + +/** + * + * if the vlc code is invalid and max_depth=1 than no bits will be removed + * if the vlc code is invalid and max_depth>1 than the number of bits removed + * is undefined + */ +#define GET_VLC(code, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + code = table[index][0];\ + n = table[index][1];\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + if(max_depth > 2 && n < 0){\ + LAST_SKIP_BITS(name, gb, nb_bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + code;\ + code = table[index][0];\ + n = table[index][1];\ + }\ + }\ + SKIP_BITS(name, gb, n)\ +} + +#define GET_RL_VLC(level, run, name, gb, table, bits, max_depth)\ +{\ + int n, index, nb_bits;\ +\ + index= SHOW_UBITS(name, gb, bits);\ + level = table[index].level;\ + n = table[index].len;\ +\ + if(max_depth > 1 && n < 0){\ + LAST_SKIP_BITS(name, gb, bits)\ + UPDATE_CACHE(name, gb)\ +\ + nb_bits = -n;\ +\ + index= SHOW_UBITS(name, gb, nb_bits) + level;\ + level = table[index].level;\ + n = table[index].len;\ + }\ + run= table[index].run;\ + SKIP_BITS(name, gb, n)\ +} + +// deprecated, dont use get_vlc for new code, use get_vlc2 instead or use GET_VLC directly +static inline int get_vlc(GetBitContext *s, VLC *vlc) +{ + int code; + VLC_TYPE (*table)[2]= vlc->table; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, vlc->bits, 3) + + CLOSE_READER(re, s) + return code; +} + +/** + * parses a vlc code, faster then get_vlc() + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be readed to completly + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + */ +static always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s) + UPDATE_CACHE(re, s) + + GET_VLC(code, re, s, table, bits, max_depth) + + CLOSE_READER(re, s) + return code; +} + +//#define TRACE + +#ifdef TRACE + +static inline void print_bin(int bits, int n){ + int i; + + for(i=n-1; i>=0; i--){ + DEBUG_LOG("%d", (bits>>i)&1); + } + for(i=n; i<24; i++) + DEBUG_LOG(" "); +} + +static inline int get_bits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int r= get_bits(s, n); + + print_bin(r, n); + DEBUG_LOG("%5d %2d %3d bit @%5d in %s %s:%d\n", r, n, r, get_bits_count(s)-n, file, func, line); + return r; +} +static inline int get_vlc_trace(GetBitContext *s, VLC_TYPE (*table)[2], int bits, int max_depth, char *file, char *func, int line){ + int show= show_bits(s, 24); + int pos= get_bits_count(s); + int r= get_vlc2(s, table, bits, max_depth); + int len= get_bits_count(s) - pos; + int bits2= show>>(24-len); + + print_bin(bits2, len); + + DEBUG_LOG("%5d %2d %3d vlc @%5d in %s %s:%d\n", bits2, len, r, pos, file, func, line); + return r; +} +static inline int get_xbits_trace(GetBitContext *s, int n, char *file, char *func, int line){ + int show= show_bits(s, n); + int r= get_xbits(s, n); + + print_bin(show, n); + DEBUG_LOG("%5d %2d %3d xbt @%5d in %s %s:%d\n", show, n, r, get_bits_count(s)-n, file, func, line); + return r; +} + +#define get_bits(s, n) get_bits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_bits1(s) get_bits_trace(s, 1, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_xbits(s, n) get_xbits_trace(s, n, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc(s, vlc) get_vlc_trace(s, (vlc)->table, (vlc)->bits, 3, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define get_vlc2(s, tab, bits, max) get_vlc_trace(s, tab, bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__) + +#define tprintf printf + +#else //TRACE +#define tprintf(_arg...) {} +#endif + +/* define it to include statistics code (useful only for optimizing + codec efficiency */ +//#define STATS + +#ifdef STATS + +enum { + ST_UNKNOWN, + ST_DC, + ST_INTRA_AC, + ST_INTER_AC, + ST_INTRA_MB, + ST_INTER_MB, + ST_MV, + ST_NB, +}; + +extern int st_current_index; +extern unsigned int st_bit_counts[ST_NB]; +extern unsigned int st_out_bit_counts[ST_NB]; + +void print_stats(void); +#endif + +/* misc math functions */ +extern const uint8_t ff_log2_tab[256]; + +static inline int av_log2(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + +static inline int av_log2_16bit(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + + +/* median of 3 */ +static inline int mid_pred(int a, int b, int c) +{ + int vmin, vmax; + vmax = vmin = a; + if (b < vmin) + vmin = b; + else + vmax = b; + + if (c < vmin) + vmin = c; + else if (c > vmax) + vmax = c; + + return a + b + c - vmin - vmax; +} + +static inline int clip(int a, int amin, int amax) +{ + if (a < amin) + return amin; + else if (a > amax) + return amax; + else + return a; +} + +/* math */ +extern const uint8_t ff_sqrt_tab[128]; + +int64_t ff_gcd(int64_t a, int64_t b); + +static inline int ff_sqrt(int a) +{ + int ret=0; + int s; + int ret_sq=0; + + if(a<128) return ff_sqrt_tab[a]; + + for(s=15; s>=0; s--){ + int b= ret_sq + (1<<(s*2)) + (ret<>31;\ + level= (level^mask)-mask; +#endif + + +#if __CPU__ >= 686 && !defined(RUNTIME_CPUDETECT) +#define COPY3_IF_LT(x,y,a,b,c,d)\ +asm volatile (\ + "cmpl %0, %3 \n\t"\ + "cmovl %3, %0 \n\t"\ + "cmovl %4, %1 \n\t"\ + "cmovl %5, %2 \n\t"\ + : "+r" (x), "+r" (a), "+r" (c)\ + : "r" (y), "r" (b), "r" (d)\ +); +#else +#define COPY3_IF_LT(x,y,a,b,c,d)\ +if((y)<(x)){\ + (x)=(y);\ + (a)=(b);\ + (c)=(d);\ +} +#endif + +#ifdef ARCH_X86 +static inline long long rdtsc() +{ + long long l; + asm volatile( "rdtsc\n\t" + : "=A" (l) + ); + return l; +} + +#define START_TIMER \ +static uint64_t tsum=0;\ +static int tcount=0;\ +static int tskip_count=0;\ +uint64_t tend;\ +uint64_t tstart= rdtsc();\ + +#define STOP_TIMER(id) \ +tend= rdtsc();\ +if(tcount<2 || tend - tstart < 4*tsum/tcount){\ + tsum+= tend - tstart;\ + tcount++;\ +}else\ + tskip_count++;\ +if(256*256*256*64%(tcount+tskip_count)==0){\ + fprintf(stderr, "%Ld dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\ +} +#endif + +#define CLAMP_TO_8BIT(d) ((d > 0xff) ? 0xff : (d < 0) ? 0 : d) + +/* avoid usage of various functions */ +#define malloc please_use_av_malloc +#define free please_use_av_free +#define realloc please_use_av_realloc + +#define CHECKED_ALLOCZ(p, size)\ +{\ + p= av_mallocz(size);\ + if(p==NULL && (size)!=0){\ + perror("malloc");\ + goto fail;\ + }\ +} + +#endif /* HAVE_AV_CONFIG_H */ + +#endif /* COMMON_H */ diff --git a/plugins/zerogs/opengl/common/PS2Edefs.h b/plugins/zerogs/opengl/common/PS2Edefs.h new file mode 100644 index 0000000000..1f65fc02b9 --- /dev/null +++ b/plugins/zerogs/opengl/common/PS2Edefs.h @@ -0,0 +1,885 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/zerogs/opengl/common/PS2Etypes.h b/plugins/zerogs/opengl/common/PS2Etypes.h new file mode 100644 index 0000000000..59be1c3de4 --- /dev/null +++ b/plugins/zerogs/opengl/common/PS2Etypes.h @@ -0,0 +1,219 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/zerogs/opengl/compile b/plugins/zerogs/opengl/compile new file mode 100644 index 0000000000..973c773214 --- /dev/null +++ b/plugins/zerogs/opengl/compile @@ -0,0 +1 @@ +link /usr/share/automake-1.9/compile \ No newline at end of file diff --git a/plugins/zerogs/opengl/configure b/plugins/zerogs/opengl/configure new file mode 100644 index 0000000000..1f401f9f6e --- /dev/null +++ b/plugins/zerogs/opengl/configure @@ -0,0 +1,6701 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.63 for ZeroGSogl 0.96.2. +# +# Report bugs to . +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell bug-autoconf@gnu.org about your system, + echo including any error possibly output before this message. + echo This can help us improve future autoconf versions. + echo Configuration will now proceed without shell functions. +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME='ZeroGSogl' +PACKAGE_TARNAME='zerogsogl' +PACKAGE_VERSION='0.96.2' +PACKAGE_STRING='ZeroGSogl 0.96.2' +PACKAGE_BUGREPORT='zerofrog@gmail.com' + +ac_subst_vars='LTLIBOBJS +LIBOBJS +SHARED_LDFLAGS +so_ext +GTK_CONFIG +X86_64_FALSE +X86_64_TRUE +SSE2_FALSE +SSE2_TRUE +RELEASE_TO_PUBLIC_FALSE +RELEASE_TO_PUBLIC_TRUE +ZEROGS_SONAME +ZEROGS_RELEASE +ZEROGS_AGE +ZEROGS_REVISION +ZEROGS_CURRENT +am__fastdepCCAS_FALSE +am__fastdepCCAS_TRUE +CCASDEPMODE +CCASFLAGS +CCAS +RANLIB +CPP +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_dependency_tracking +enable_debug +enable_devbuild +enable_sse2 +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CPP +CCAS +CCASFLAGS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { $as_echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { $as_echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2 + { (exit 1); exit 1; }; } ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { $as_echo "$as_me: error: working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { $as_echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures ZeroGSogl 0.96.2 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/zerogsogl] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of ZeroGSogl 0.96.2:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-debug debug build + --enable-devbuild Special Build for developers that simplifies testing + and adds extra checks + --enable-sse2 Enable sse2 instructions + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + CCAS assembler compiler command (defaults to CC) + CCASFLAGS assembler compiler flags (defaults to CFLAGS) + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +ZeroGSogl configure 0.96.2 +generated by GNU Autoconf 2.63 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by ZeroGSogl $as_me 0.96.2, which was +generated by GNU Autoconf 2.63. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test -r "$ac_site_file"; then + { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +am__api_version='1.10' + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +$as_echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + +done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { $as_echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +$as_echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { $as_echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +$as_echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +{ $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +{ $as_echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done +done +IFS=$as_save_IFS + +fi + + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + test -d ./--version && rmdir ./--version + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:$LINENO: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:$LINENO: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + { { $as_echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +$as_echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=ZeroGSogl + VERSION=0.96.2 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:$LINENO: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in gcc g++ cl KCC CC cxx cc++ xlC aCC c++ + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:$LINENO: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in gcc g++ cl KCC CC cxx cc++ xlC aCC c++ +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + + +test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } + +# Provide some information about the compiler. +$as_echo "$as_me:$LINENO: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +if test -z "$ac_file"; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } + fi + fi +fi +{ $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } +fi + +rm -f conftest$ac_cv_exeext +{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:$LINENO: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:$LINENO: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +{ $as_echo "$as_me:$LINENO: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in gcc g++ cl KCC CC cxx cc++ xlC aCC c++ + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:$LINENO: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in gcc g++ cl KCC CC cxx cc++ xlC aCC c++ +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:$LINENO: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test "x$CC" != xcc; then + { $as_echo "$as_me:$LINENO: checking whether $CC and cc understand -c and -o together" >&5 +$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } +else + { $as_echo "$as_me:$LINENO: checking whether cc understands -c and -o together" >&5 +$as_echo_n "checking whether cc understands -c and -o together... " >&6; } +fi +set dummy $CC; ac_cc=`$as_echo "$2" | + sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +if { as_var=ac_cv_prog_cc_${ac_cc}_c_o; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' +rm -f conftest2.* +if { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + test -f conftest2.$ac_objext && { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; +then + eval ac_cv_prog_cc_${ac_cc}_c_o=yes + if test "x$CC" != xcc; then + # Test first that cc exists at all. + if { ac_try='cc -c conftest.$ac_ext >&5' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' + rm -f conftest2.* + if { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + test -f conftest2.$ac_objext && { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; + then + # cc works too. + : + else + # cc exists but doesn't like -o. + eval ac_cv_prog_cc_${ac_cc}_c_o=no + fi + fi + fi +else + eval ac_cv_prog_cc_${ac_cc}_c_o=no +fi +rm -f core conftest* + +fi +if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + +cat >>confdefs.h <<\_ACEOF +#define NO_MINUS_C_MINUS_O 1 +_ACEOF + +fi + +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi + + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + +done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +# By default we simply use the C compiler to build assembly code. + +test "${CCAS+set}" = set || CCAS=$CC +test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS + + + +depcc="$CCAS" am_compiler_list= + +{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CCAS_dependencies_compiler_type+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CCAS_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CCAS_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CCAS_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $am_cv_CCAS_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CCAS_dependencies_compiler_type" >&6; } +CCASDEPMODE=depmode=$am_cv_CCAS_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CCAS_dependencies_compiler_type" = gcc3; then + am__fastdepCCAS_TRUE= + am__fastdepCCAS_FALSE='#' +else + am__fastdepCCAS_TRUE='#' + am__fastdepCCAS_FALSE= +fi + + + +ZEROGS_CURRENT=0 +ZEROGS_REVISION=96 +ZEROGS_AGE=2 +ZEROGS_SONAME=libZeroGSogl.so.$ZEROGS_CURRENT.$ZEROGS_REVISION.$ZEROGS_AGE +ZEROGS_RELEASE=$ZEROGS_CURRENT.$ZEROGS_REVISION.$ZEROGS_AGE + + + + + + + +CFLAGS=" -I/opt/cg/include -L/opt/cg/lib " +CPPFLAGS=" -I/opt/cg/include -L/opt/cg/lib " +CXXFLAGS=" -I/opt/cg/include -L/opt/cg/lib " + +{ $as_echo "$as_me:$LINENO: checking debug build" >&5 +$as_echo_n "checking debug build... " >&6; } +# Check whether --enable-debug was given. +if test "${enable_debug+set}" = set; then + enableval=$enable_debug; debug=$enableval +else + debug=no +fi + +if test "x$debug" == xyes +then + +cat >>confdefs.h <<\_ACEOF +#define _DEBUG 1 +_ACEOF + + CFLAGS+="-g " + CPPFLAGS+="-g -fpermissive " + CXXFLAGS+="-g- fpermissive " +else + +cat >>confdefs.h <<\_ACEOF +#define NDEBUG 1 +_ACEOF + + CFLAGS+="-O3 -fomit-frame-pointer " + CPPFLAGS+="-O3 -fomit-frame-pointer " + CXXFLAGS+="-O3 -fomit-frame-pointer -fpermissive " +fi +{ $as_echo "$as_me:$LINENO: result: $debug" >&5 +$as_echo "$debug" >&6; } + + + + +for ac_func in _aligned_malloc _aligned_free +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + cat >>confdefs.h <<\_ACEOF +#define HAVE_ALIGNED_MALLOC 1 +_ACEOF + +fi +done + + +{ $as_echo "$as_me:$LINENO: checking for development build..." >&5 +$as_echo_n "checking for development build...... " >&6; } +# Check whether --enable-devbuild was given. +if test "${enable_devbuild+set}" = set; then + enableval=$enable_devbuild; devbuild=$enableval +else + devbuild=no +fi + +if test "x$devbuild" == xno +then + +cat >>confdefs.h <<\_ACEOF +#define RELEASE_TO_PUBLIC 1 +_ACEOF + +fi +{ $as_echo "$as_me:$LINENO: result: $devbuild" >&5 +$as_echo "$devbuild" >&6; } + if test x$devbuild = xno; then + RELEASE_TO_PUBLIC_TRUE= + RELEASE_TO_PUBLIC_FALSE='#' +else + RELEASE_TO_PUBLIC_TRUE='#' + RELEASE_TO_PUBLIC_FALSE= +fi + + +{ $as_echo "$as_me:$LINENO: checking check for sse2..." >&5 +$as_echo_n "checking check for sse2...... " >&6; } +# Check whether --enable-sse2 was given. +if test "${enable_sse2+set}" = set; then + enableval=$enable_sse2; sse2=$enableval +else + sse2=no +fi + +if test "x$sse2" == xyes +then + +cat >>confdefs.h <<\_ACEOF +#define ZEROGS_SSE2 1 +_ACEOF + +fi +{ $as_echo "$as_me:$LINENO: result: $sse2" >&5 +$as_echo "$sse2" >&6; } + if test x$sse2 = xyes; then + SSE2_TRUE= + SSE2_FALSE='#' +else + SSE2_TRUE='#' + SSE2_FALSE= +fi + + +{ $as_echo "$as_me:$LINENO: checking for a x86-64 CPU" >&5 +$as_echo_n "checking for a x86-64 CPU... " >&6; } +if test "$cross_compiling" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot run test program while cross compiling +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot run test program while cross compiling +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int main() +{ +int a = 0; +int*pa = &a; +asm(".intel_syntax\n" + "mov %%rax, %0\n" + "mov %%eax, [%%rax]\n" + ".att_syntax\n" + : : "r"(pa) : "%rax"); +return 0; +} + +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cpu64=yes +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +cpu64=no +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +if test "x$cpu64" == xyes +then + +cat >>confdefs.h <<\_ACEOF +#define __x86_64__ 1 +_ACEOF + +fi +{ $as_echo "$as_me:$LINENO: result: $cpu64" >&5 +$as_echo "$cpu64" >&6; } + if test x$cpu64 = xyes; then + X86_64_TRUE= + X86_64_FALSE='#' +else + X86_64_TRUE='#' + X86_64_FALSE= +fi + + +{ $as_echo "$as_me:$LINENO: checking gtk2+" >&5 +$as_echo_n "checking gtk2+... " >&6; } +# Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_GTK_CONFIG+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$GTK_CONFIG"; then + ac_cv_prog_GTK_CONFIG="$GTK_CONFIG" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_GTK_CONFIG="pkg-config" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +GTK_CONFIG=$ac_cv_prog_GTK_CONFIG +if test -n "$GTK_CONFIG"; then + { $as_echo "$as_me:$LINENO: result: $GTK_CONFIG" >&5 +$as_echo "$GTK_CONFIG" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +LIBS+=$(pkg-config --libs gtk+-2.0) + + +so_ext=".so.$ZEROGS_RELEASE" +SHARED_LDFLAGS="-shared" + + + +{ $as_echo "$as_me:$LINENO: checking OpenGL" >&5 +$as_echo_n "checking OpenGL... " >&6; } + + + +for ac_header in GL/gl.h GL/glu.h GL/glext.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#if HAVE_GL_GL_H + #include + #endif + #if HAVE_GL_GLU_H + #include + #endif + + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:$LINENO: checking for main in -lGL" >&5 +$as_echo_n "checking for main in -lGL... " >&6; } +if test "${ac_cv_lib_GL_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lGL $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_GL_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_GL_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_GL_main" >&5 +$as_echo "$ac_cv_lib_GL_main" >&6; } +if test "x$ac_cv_lib_GL_main" = x""yes; then + LIBS="$LIBS -lGL" +fi + +{ $as_echo "$as_me:$LINENO: checking for main in -lGLU" >&5 +$as_echo_n "checking for main in -lGLU... " >&6; } +if test "${ac_cv_lib_GLU_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lGLU $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_GLU_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_GLU_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_GLU_main" >&5 +$as_echo "$ac_cv_lib_GLU_main" >&6; } +if test "x$ac_cv_lib_GLU_main" = x""yes; then + LIBS="$LIBS -lGLU" +fi + +{ $as_echo "$as_me:$LINENO: checking for main in -lGLEW" >&5 +$as_echo_n "checking for main in -lGLEW... " >&6; } +if test "${ac_cv_lib_GLEW_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lGLEW $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_GLEW_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_GLEW_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_GLEW_main" >&5 +$as_echo "$ac_cv_lib_GLEW_main" >&6; } +if test "x$ac_cv_lib_GLEW_main" = x""yes; then + LIBS="$LIBS -lGLEW" +fi + +{ $as_echo "$as_me:$LINENO: checking Cg" >&5 +$as_echo_n "checking Cg... " >&6; } +#AC_CHECK_HEADERS([Cg/cg.h Cg/cgGL.h]) + +{ $as_echo "$as_me:$LINENO: checking for main in -ljpeg" >&5 +$as_echo_n "checking for main in -ljpeg... " >&6; } +if test "${ac_cv_lib_jpeg_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ljpeg $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_jpeg_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_jpeg_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_jpeg_main" >&5 +$as_echo "$ac_cv_lib_jpeg_main" >&6; } +if test "x$ac_cv_lib_jpeg_main" = x""yes; then + LIBS="$LIBS -ljpeg" +fi + +{ $as_echo "$as_me:$LINENO: checking for main in -lpthread" >&5 +$as_echo_n "checking for main in -lpthread... " >&6; } +if test "${ac_cv_lib_pthread_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_pthread_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_pthread_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_main" >&5 +$as_echo "$ac_cv_lib_pthread_main" >&6; } +if test "x$ac_cv_lib_pthread_main" = x""yes; then + LIBS="$LIBS -lpthread" +fi + +{ $as_echo "$as_me:$LINENO: checking for main in -lstdc++" >&5 +$as_echo_n "checking for main in -lstdc++... " >&6; } +if test "${ac_cv_lib_stdcpp_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lstdc++ $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_stdcpp_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_stdcpp_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_stdcpp_main" >&5 +$as_echo "$ac_cv_lib_stdcpp_main" >&6; } +if test "x$ac_cv_lib_stdcpp_main" = x""yes; then + LIBS="$LIBS -lstdc++" +fi + +{ $as_echo "$as_me:$LINENO: checking for main in -lz" >&5 +$as_echo_n "checking for main in -lz... " >&6; } +if test "${ac_cv_lib_z_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lz $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_z_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_z_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_z_main" >&5 +$as_echo "$ac_cv_lib_z_main" >&6; } +if test "x$ac_cv_lib_z_main" = x""yes; then + LIBS="$LIBS -lz" +fi + +{ $as_echo "$as_me:$LINENO: checking for main in -ldl" >&5 +$as_echo_n "checking for main in -ldl... " >&6; } +if test "${ac_cv_lib_dl_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_dl_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dl_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_main" >&5 +$as_echo "$ac_cv_lib_dl_main" >&6; } +if test "x$ac_cv_lib_dl_main" = x""yes; then + LIBS="$LIBS -ldl" +fi + +{ $as_echo "$as_me:$LINENO: checking for main in -lXxf86vm" >&5 +$as_echo_n "checking for main in -lXxf86vm... " >&6; } +if test "${ac_cv_lib_Xxf86vm_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lXxf86vm $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_Xxf86vm_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_Xxf86vm_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_Xxf86vm_main" >&5 +$as_echo "$ac_cv_lib_Xxf86vm_main" >&6; } +if test "x$ac_cv_lib_Xxf86vm_main" = x""yes; then + LIBS="$LIBS -lXxf86vm" +fi + + +LIBS+=" -lCg -lCgGL" + +ac_config_files="$ac_config_files Makefile Linux/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCCAS_TRUE}" && test -z "${am__fastdepCCAS_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCCAS\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"am__fastdepCCAS\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${RELEASE_TO_PUBLIC_TRUE}" && test -z "${RELEASE_TO_PUBLIC_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"RELEASE_TO_PUBLIC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"RELEASE_TO_PUBLIC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${SSE2_TRUE}" && test -z "${SSE2_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"SSE2\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"SSE2\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${X86_64_TRUE}" && test -z "${X86_64_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"X86_64\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"X86_64\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by ZeroGSogl $as_me 0.96.2, which was +generated by GNU Autoconf 2.63. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTION]... [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_version="\\ +ZeroGSogl config.status 0.96.2 +configured by $0, generated by GNU Autoconf 2.63, + with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + CONFIG_FILES="$CONFIG_FILES '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { $as_echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "Linux/Makefile") CONFIG_FILES="$CONFIG_FILES Linux/Makefile" ;; + + *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + $as_echo "$as_me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=' ' +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\).*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\).*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5 +$as_echo "$as_me: error: could not setup config files machinery" >&2;} + { (exit 1); exit 1; }; } +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5 +$as_echo "$as_me: error: invalid tag $ac_tag" >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + ac_file_inputs="$ac_file_inputs '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:$LINENO: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +$as_echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + ;; + + + :C) { $as_echo "$as_me:$LINENO: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || # Autoconf 2.62 quotes --file arguments for eval, but not when files +# are listed without --file. Let's play safe and only enable the eval +# if we detect the quoting. +case $CONFIG_FILES in +*\'*) eval set x "$CONFIG_FILES" ;; +*) set x $CONFIG_FILES ;; +esac +shift +for mf +do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir=$dirpart/$fdir + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +$as_echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + + esac +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + +echo "Configuration:" +echo " Target system type: $target" +echo " x86-64 build? $cpu64" +echo " Debug build? $debug" +echo " Dev build? $devbuild" +echo " SSE2 enabled? $sse2" diff --git a/plugins/zerogs/opengl/configure.ac b/plugins/zerogs/opengl/configure.ac new file mode 100644 index 0000000000..e627f8f829 --- /dev/null +++ b/plugins/zerogs/opengl/configure.ac @@ -0,0 +1,150 @@ +AC_INIT(ZeroGSogl,0.96.2,zerofrog@gmail.com) + +AM_INIT_AUTOMAKE(ZeroGSogl,0.96.2) + +AC_PROG_CC([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CXX([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CPP([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AM_PROG_CC_C_O + +AC_PROG_INSTALL +AC_PROG_RANLIB + +dnl necessary for compiling assembly +AM_PROG_AS + +ZEROGS_CURRENT=0 +ZEROGS_REVISION=96 +ZEROGS_AGE=2 +ZEROGS_SONAME=libZeroGSogl.so.[$ZEROGS_CURRENT].[$ZEROGS_REVISION].[$ZEROGS_AGE] +ZEROGS_RELEASE=[$ZEROGS_CURRENT].[$ZEROGS_REVISION].[$ZEROGS_AGE] + +AC_SUBST(ZEROGS_CURRENT) +AC_SUBST(ZEROGS_REVISION) +AC_SUBST(ZEROGS_AGE) +AC_SUBST(ZEROGS_RELEASE) +AC_SUBST(ZEROGS_SONAME) + +CFLAGS=" -I/opt/cg/include -L/opt/cg/lib " +CPPFLAGS=" -I/opt/cg/include -L/opt/cg/lib " +CXXFLAGS=" -I/opt/cg/include -L/opt/cg/lib " + +dnl Check for debug build +AC_MSG_CHECKING(debug build) +AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [debug build]), + debug=$enableval,debug=no) +if test "x$debug" == xyes +then + AC_DEFINE(_DEBUG,1,[_DEBUG]) + CFLAGS+="-g " + CPPFLAGS+="-g -fpermissive " + CXXFLAGS+="-g- fpermissive " +else + AC_DEFINE(NDEBUG,1,[NDEBUG]) + CFLAGS+="-O3 -fomit-frame-pointer " + CPPFLAGS+="-O3 -fomit-frame-pointer " + CXXFLAGS+="-O3 -fomit-frame-pointer -fpermissive " +fi +AC_MSG_RESULT($debug) + +AC_CHECK_FUNCS([ _aligned_malloc _aligned_free ], AC_DEFINE(HAVE_ALIGNED_MALLOC)) + +dnl Check for dev build +AC_MSG_CHECKING(for development build...) +AC_ARG_ENABLE(devbuild, AC_HELP_STRING([--enable-devbuild], [Special Build for developers that simplifies testing and adds extra checks]), + devbuild=$enableval,devbuild=no) +if test "x$devbuild" == xno +then + AC_DEFINE(RELEASE_TO_PUBLIC,1,[RELEASE_TO_PUBLIC]) +fi +AC_MSG_RESULT($devbuild) +AM_CONDITIONAL(RELEASE_TO_PUBLIC, test x$devbuild = xno) + +dnl Check for recompilation +AC_MSG_CHECKING(check for sse2...) +AC_ARG_ENABLE(sse2, AC_HELP_STRING([--enable-sse2], [Enable sse2 instructions]), + sse2=$enableval,sse2=no) +if test "x$sse2" == xyes +then + AC_DEFINE(ZEROGS_SSE2,1,[ZEROGS_SSE2]) +fi +AC_MSG_RESULT($sse2) +AM_CONDITIONAL(SSE2, test x$sse2 = xyes) + +dnl Check for 64bit CPU +AC_MSG_CHECKING(for a x86-64 CPU) +dnl if test "$build_os" == "target_os" +dnl then +AC_TRY_RUN([ +int main() +{ +int a = 0; +int*pa = &a; +asm(".intel_syntax\n" + "mov %%rax, %0\n" + "mov %%eax, [%%rax]\n" + ".att_syntax\n" + : : "r"(pa) : "%rax"); +return 0; +} +],cpu64=yes,cpu64=no,) +dnl else +dnl cpu64=no +dnl fi +if test "x$cpu64" == xyes +then +AC_DEFINE(__x86_64__,1,[__x86_64__]) +fi +AC_MSG_RESULT($cpu64) +AM_CONDITIONAL(X86_64, test x$cpu64 = xyes) + +dnl gtk +AC_MSG_CHECKING(gtk2+) +AC_CHECK_PROG(GTK_CONFIG, pkg-config, pkg-config) +LIBS+=$(pkg-config --libs gtk+-2.0) + +dnl bindir = pcsx2exe + +dnl assuming linux environment +so_ext=".so.$ZEROGS_RELEASE" +SHARED_LDFLAGS="-shared" +AC_SUBST(so_ext) +AC_SUBST(SHARED_LDFLAGS) + +AC_MSG_CHECKING(OpenGL) +AC_CHECK_HEADERS([GL/gl.h GL/glu.h GL/glext.h],,, + [[#if HAVE_GL_GL_H + #include + #endif + #if HAVE_GL_GLU_H + #include + #endif + ]]) +AC_CHECK_LIB(GL,main,[LIBS="$LIBS -lGL"]) +AC_CHECK_LIB(GLU,main,[LIBS="$LIBS -lGLU"]) +AC_CHECK_LIB(GLEW,main,[LIBS="$LIBS -lGLEW"]) +AC_MSG_CHECKING(Cg) +#AC_CHECK_HEADERS([Cg/cg.h Cg/cgGL.h]) + +AC_CHECK_LIB(jpeg,main,[LIBS="$LIBS -ljpeg"]) +AC_CHECK_LIB(pthread,main,[LIBS="$LIBS -lpthread"]) +AC_CHECK_LIB(stdc++,main,[LIBS="$LIBS -lstdc++"]) +AC_CHECK_LIB(z,main,[LIBS="$LIBS -lz"]) +AC_CHECK_LIB(dl,main,[LIBS="$LIBS -ldl"]) +AC_CHECK_LIB(Xxf86vm,main,[LIBS="$LIBS -lXxf86vm"]) + +dnl AC_CHECK_LIB(Cg,cgCreateContext,[LIBS="$LIBS -lCg"]) +dnl AC_CHECK_LIB(CgGL,cgGLEnableProfile,[LIBS="$LIBS -lCgGL"]) +LIBS+=" -lCg -lCgGL" + +AC_OUTPUT([ + Makefile + Linux/Makefile + ]) + +echo "Configuration:" +echo " Target system type: $target" +echo " x86-64 build? $cpu64" +echo " Debug build? $debug" +echo " Dev build? $devbuild" +echo " SSE2 enabled? $sse2" diff --git a/plugins/zerogs/opengl/ctx0/ps2hw_ctx.fx b/plugins/zerogs/opengl/ctx0/ps2hw_ctx.fx new file mode 100644 index 0000000000..7988a22bb7 --- /dev/null +++ b/plugins/zerogs/opengl/ctx0/ps2hw_ctx.fx @@ -0,0 +1,24 @@ +// main ps2 memory, each pixel is stored in 32bit color +uniform samplerRECT g_sMemory : register(s0); + +// per context pixel shader constants +uniform half4 fTexAlpha2 : register(c2); + +uniform float4 g_fTexOffset : register(c4); // converts the page and block offsets into the mem addr/1024 +uniform float4 g_fTexDims : register(c6); // mult by tex dims when accessing the block texture +uniform float4 g_fTexBlock : register(c8); + +uniform float4 g_fClampExts : register(c10); // if clamping the texture, use (minu, minv, maxu, maxv) +uniform float4 TexWrapMode : register(c12); // 0 - repeat/clamp, 1 - region rep (use fRegRepMask) + +uniform float4 g_fRealTexDims : register(c14); // tex dims used for linear filtering (w,h,1/w,1/h) + +// (alpha0, alpha1, 1 if highlight2 and tcc is rgba, 1-y) +uniform half4 g_fTestBlack : register(c16); // used for aem bit + +uniform float4 g_fPageOffset : register(c18); + +uniform half4 fTexAlpha : register(c20); + +// vertex shader constants +uniform float4 g_fPosXY : register(c2); \ No newline at end of file diff --git a/plugins/zerogs/opengl/ctx1/ps2hw_ctx.fx b/plugins/zerogs/opengl/ctx1/ps2hw_ctx.fx new file mode 100644 index 0000000000..c6332c1a59 --- /dev/null +++ b/plugins/zerogs/opengl/ctx1/ps2hw_ctx.fx @@ -0,0 +1,23 @@ +uniform samplerRECT g_sMemory : register(s1); + +// per context pixel shader constants +uniform half4 fTexAlpha2 : register(c3); + +uniform float4 g_fTexOffset : register(c5); // converts the page and block offsets into the mem addr/1024 +uniform float4 g_fTexDims : register(c7); // mult by tex dims when accessing the block texture +uniform float4 g_fTexBlock : register(c9); + +uniform float4 g_fClampExts : register(c11); // if clamping the texture, use (minu, minv, maxu, maxv) +uniform float4 TexWrapMode : register(c13); // 0 - repeat/clamp, 1 - region rep (use fRegRepMask) + +uniform float4 g_fRealTexDims : register(c15); // tex dims used for linear filtering (w,h,1/w,1/h) + +// (alpha0, alpha1, 1 if highlight2 and tcc is rgba, 1-y) +uniform half4 g_fTestBlack : register(c17); // used for aem bit + +uniform float4 g_fPageOffset : register(c19); + +uniform half4 fTexAlpha : register(c21); + +// vertex shader constants +uniform float4 g_fPosXY : register(c3); \ No newline at end of file diff --git a/plugins/zerogs/opengl/depcomp b/plugins/zerogs/opengl/depcomp new file mode 100644 index 0000000000..88b3a13969 --- /dev/null +++ b/plugins/zerogs/opengl/depcomp @@ -0,0 +1,529 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/zerogs/opengl/glprocs.c b/plugins/zerogs/opengl/glprocs.c new file mode 100644 index 0000000000..da82208f15 --- /dev/null +++ b/plugins/zerogs/opengl/glprocs.c @@ -0,0 +1,17864 @@ +/* +** GLprocs utility for getting function addresses for OpenGL(R) 1.2, +** OpenGL 1.3, OpenGL 1.4, OpenGL 1.5 and OpenGL extension functions. +** +** Version: 1.1 +** +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.1 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: This software was created using the +** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has +** not been independently verified as being compliant with the OpenGL(R) +** version 1.2.1 Specification. +** +** Initial version of glprocs.{c,h} contributed by Intel(R) Corporation. +*/ + +#include +#include + +#ifdef _WIN32 + #include + #include //"gl.h" /* Include local "gl.h". Don't include vc32 . */ + #include "glprocs.h" +#else /* GLX */ + #include + #include + #include +#include "glprocs.h"// +// #define wglGetProcAddress glXGetProcAddress +inline void* wglGetProcAddress(const char* x) { + return (void*)glXGetProcAddress((const GLubyte*)x); +} + +#endif + +#define _ASSERT(a) assert(a) + +static void APIENTRY InitBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendColor"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendColor = extproc; + + glBlendColor(red, green, blue, alpha); +} + +static void APIENTRY InitBlendEquation (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendEquation"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendEquation = extproc; + + glBlendEquation(mode); +} + +static void APIENTRY InitDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElements"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElements = extproc; + + glDrawRangeElements(mode, start, end, count, type, indices); +} + +static void APIENTRY InitColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTable = extproc; + + glColorTable(target, internalformat, width, format, type, table); +} + +static void APIENTRY InitColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameterfv = extproc; + + glColorTableParameterfv(target, pname, params); +} + +static void APIENTRY InitColorTableParameteriv (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameteriv = extproc; + + glColorTableParameteriv(target, pname, params); +} + +static void APIENTRY InitCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorTable = extproc; + + glCopyColorTable(target, internalformat, x, y, width); +} + +static void APIENTRY InitGetColorTable (GLenum target, GLenum format, GLenum type, GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTable = extproc; + + glGetColorTable(target, format, type, table); +} + +static void APIENTRY InitGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterfv = extproc; + + glGetColorTableParameterfv(target, pname, params); +} + +static void APIENTRY InitGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameteriv = extproc; + + glGetColorTableParameteriv(target, pname, params); +} + +static void APIENTRY InitColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorSubTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorSubTable = extproc; + + glColorSubTable(target, start, count, format, type, data); +} + +static void APIENTRY InitCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorSubTable"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorSubTable = extproc; + + glCopyColorSubTable(target, start, x, y, width); +} + +static void APIENTRY InitConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter1D = extproc; + + glConvolutionFilter1D(target, internalformat, width, format, type, image); +} + +static void APIENTRY InitConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter2D = extproc; + + glConvolutionFilter2D(target, internalformat, width, height, format, type, image); +} + +static void APIENTRY InitConvolutionParameterf (GLenum target, GLenum pname, GLfloat params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterf = extproc; + + glConvolutionParameterf(target, pname, params); +} + +static void APIENTRY InitConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterfv = extproc; + + glConvolutionParameterfv(target, pname, params); +} + +static void APIENTRY InitConvolutionParameteri (GLenum target, GLenum pname, GLint params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameteri"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameteri = extproc; + + glConvolutionParameteri(target, pname, params); +} + +static void APIENTRY InitConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameteriv = extproc; + + glConvolutionParameteriv(target, pname, params); +} + +static void APIENTRY InitCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter1D = extproc; + + glCopyConvolutionFilter1D(target, internalformat, x, y, width); +} + +static void APIENTRY InitCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter2D = extproc; + + glCopyConvolutionFilter2D(target, internalformat, x, y, width, height); +} + +static void APIENTRY InitGetConvolutionFilter (GLenum target, GLenum format, GLenum type, GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionFilter"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionFilter = extproc; + + glGetConvolutionFilter(target, format, type, image); +} + +static void APIENTRY InitGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameterfv = extproc; + + glGetConvolutionParameterfv(target, pname, params); +} + +static void APIENTRY InitGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameteriv = extproc; + + glGetConvolutionParameteriv(target, pname, params); +} + +static void APIENTRY InitGetSeparableFilter (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetSeparableFilter"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetSeparableFilter = extproc; + + glGetSeparableFilter(target, format, type, row, column, span); +} + +static void APIENTRY InitSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSeparableFilter2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSeparableFilter2D = extproc; + + glSeparableFilter2D(target, internalformat, width, height, format, type, row, column); +} + +static void APIENTRY InitGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogram"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogram = extproc; + + glGetHistogram(target, reset, format, type, values); +} + +static void APIENTRY InitGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameterfv = extproc; + + glGetHistogramParameterfv(target, pname, params); +} + +static void APIENTRY InitGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameteriv = extproc; + + glGetHistogramParameteriv(target, pname, params); +} + +static void APIENTRY InitGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmax"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmax = extproc; + + glGetMinmax(target, reset, format, type, values); +} + +static void APIENTRY InitGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameterfv = extproc; + + glGetMinmaxParameterfv(target, pname, params); +} + +static void APIENTRY InitGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameteriv = extproc; + + glGetMinmaxParameteriv(target, pname, params); +} + +static void APIENTRY InitHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glHistogram"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glHistogram = extproc; + + glHistogram(target, width, internalformat, sink); +} + +static void APIENTRY InitMinmax (GLenum target, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMinmax"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMinmax = extproc; + + glMinmax(target, internalformat, sink); +} + +static void APIENTRY InitResetHistogram (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetHistogram"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetHistogram = extproc; + + glResetHistogram(target); +} + +static void APIENTRY InitResetMinmax (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetMinmax"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetMinmax = extproc; + + glResetMinmax(target); +} + +static void APIENTRY InitTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexImage3D = extproc; + + glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); +} + +static void APIENTRY InitTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage3D = extproc; + + glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); +} + +static void APIENTRY InitCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage3D = extproc; + + glCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); +} + +static void APIENTRY InitActiveTexture (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glActiveTexture"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glActiveTexture = extproc; + + glActiveTexture(texture); +} + +static void APIENTRY InitClientActiveTexture (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glClientActiveTexture"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glClientActiveTexture = extproc; + + glClientActiveTexture(texture); +} + +static void APIENTRY InitMultiTexCoord1d (GLenum target, GLdouble s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1d = extproc; + + glMultiTexCoord1d(target, s); +} + +static void APIENTRY InitMultiTexCoord1dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1dv = extproc; + + glMultiTexCoord1dv(target, v); +} + +static void APIENTRY InitMultiTexCoord1f (GLenum target, GLfloat s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1f = extproc; + + glMultiTexCoord1f(target, s); +} + +static void APIENTRY InitMultiTexCoord1fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1fv = extproc; + + glMultiTexCoord1fv(target, v); +} + +static void APIENTRY InitMultiTexCoord1i (GLenum target, GLint s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1i = extproc; + + glMultiTexCoord1i(target, s); +} + +static void APIENTRY InitMultiTexCoord1iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1iv = extproc; + + glMultiTexCoord1iv(target, v); +} + +static void APIENTRY InitMultiTexCoord1s (GLenum target, GLshort s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1s = extproc; + + glMultiTexCoord1s(target, s); +} + +static void APIENTRY InitMultiTexCoord1sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1sv = extproc; + + glMultiTexCoord1sv(target, v); +} + +static void APIENTRY InitMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2d = extproc; + + glMultiTexCoord2d(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2dv = extproc; + + glMultiTexCoord2dv(target, v); +} + +static void APIENTRY InitMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2f = extproc; + + glMultiTexCoord2f(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2fv = extproc; + + glMultiTexCoord2fv(target, v); +} + +static void APIENTRY InitMultiTexCoord2i (GLenum target, GLint s, GLint t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2i = extproc; + + glMultiTexCoord2i(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2iv = extproc; + + glMultiTexCoord2iv(target, v); +} + +static void APIENTRY InitMultiTexCoord2s (GLenum target, GLshort s, GLshort t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2s = extproc; + + glMultiTexCoord2s(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2sv = extproc; + + glMultiTexCoord2sv(target, v); +} + +static void APIENTRY InitMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3d = extproc; + + glMultiTexCoord3d(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3dv = extproc; + + glMultiTexCoord3dv(target, v); +} + +static void APIENTRY InitMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3f = extproc; + + glMultiTexCoord3f(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3fv = extproc; + + glMultiTexCoord3fv(target, v); +} + +static void APIENTRY InitMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3i = extproc; + + glMultiTexCoord3i(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3iv = extproc; + + glMultiTexCoord3iv(target, v); +} + +static void APIENTRY InitMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3s = extproc; + + glMultiTexCoord3s(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3sv = extproc; + + glMultiTexCoord3sv(target, v); +} + +static void APIENTRY InitMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4d = extproc; + + glMultiTexCoord4d(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4dv (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4dv = extproc; + + glMultiTexCoord4dv(target, v); +} + +static void APIENTRY InitMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4f = extproc; + + glMultiTexCoord4f(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4fv (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4fv = extproc; + + glMultiTexCoord4fv(target, v); +} + +static void APIENTRY InitMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4i = extproc; + + glMultiTexCoord4i(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4iv (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4iv = extproc; + + glMultiTexCoord4iv(target, v); +} + +static void APIENTRY InitMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4s = extproc; + + glMultiTexCoord4s(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4sv (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4sv = extproc; + + glMultiTexCoord4sv(target, v); +} + +static void APIENTRY InitLoadTransposeMatrixf (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixf = extproc; + + glLoadTransposeMatrixf(m); +} + +static void APIENTRY InitLoadTransposeMatrixd (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixd"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixd = extproc; + + glLoadTransposeMatrixd(m); +} + +static void APIENTRY InitMultTransposeMatrixf (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixf = extproc; + + glMultTransposeMatrixf(m); +} + +static void APIENTRY InitMultTransposeMatrixd (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixd"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixd = extproc; + + glMultTransposeMatrixd(m); +} + +static void APIENTRY InitSampleCoverage (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleCoverage"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleCoverage = extproc; + + glSampleCoverage(value, invert); +} + +static void APIENTRY InitCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage3D = extproc; + + glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage2D = extproc; + + glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage1D = extproc; + + glCompressedTexImage1D(target, level, internalformat, width, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage3D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage3D = extproc; + + glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage2D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage2D = extproc; + + glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage1D"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage1D = extproc; + + glCompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, data); +} + +static void APIENTRY InitGetCompressedTexImage (GLenum target, GLint level, GLvoid *img) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCompressedTexImage"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCompressedTexImage = extproc; + + glGetCompressedTexImage(target, level, img); +} + +static void APIENTRY InitBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendFuncSeparate"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendFuncSeparate = extproc; + + glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +} + +static void APIENTRY InitFogCoordf (GLfloat coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordf = extproc; + + glFogCoordf(coord); +} + +static void APIENTRY InitFogCoordfv (const GLfloat *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordfv = extproc; + + glFogCoordfv(coord); +} + +static void APIENTRY InitFogCoordd (GLdouble coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordd"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordd = extproc; + + glFogCoordd(coord); +} + +static void APIENTRY InitFogCoorddv (const GLdouble *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoorddv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoorddv = extproc; + + glFogCoorddv(coord); +} + +static void APIENTRY InitFogCoordPointer (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordPointer"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordPointer = extproc; + + glFogCoordPointer(type, stride, pointer); +} + +static void APIENTRY InitMultiDrawArrays (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawArrays"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawArrays = extproc; + + glMultiDrawArrays(mode, first, count, primcount); +} + +static void APIENTRY InitMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawElements"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawElements = extproc; + + glMultiDrawElements(mode, count, type, indices, primcount); +} + +static void APIENTRY InitPointParameterf (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterf"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterf = extproc; + + glPointParameterf(pname, param); +} + +static void APIENTRY InitPointParameterfv (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfv = extproc; + + glPointParameterfv(pname, params); +} + +static void APIENTRY InitPointParameteri (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameteri"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameteri = extproc; + + glPointParameteri(pname, param); +} + +static void APIENTRY InitPointParameteriv (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameteriv = extproc; + + glPointParameteriv(pname, params); +} + +static void APIENTRY InitSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3b"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3b = extproc; + + glSecondaryColor3b(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3bv (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3bv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3bv = extproc; + + glSecondaryColor3bv(v); +} + +static void APIENTRY InitSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3d = extproc; + + glSecondaryColor3d(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3dv (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3dv = extproc; + + glSecondaryColor3dv(v); +} + +static void APIENTRY InitSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3f = extproc; + + glSecondaryColor3f(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3fv (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3fv = extproc; + + glSecondaryColor3fv(v); +} + +static void APIENTRY InitSecondaryColor3i (GLint red, GLint green, GLint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3i = extproc; + + glSecondaryColor3i(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3iv (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3iv = extproc; + + glSecondaryColor3iv(v); +} + +static void APIENTRY InitSecondaryColor3s (GLshort red, GLshort green, GLshort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3s = extproc; + + glSecondaryColor3s(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3sv (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3sv = extproc; + + glSecondaryColor3sv(v); +} + +static void APIENTRY InitSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ub"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ub = extproc; + + glSecondaryColor3ub(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3ubv (const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ubv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ubv = extproc; + + glSecondaryColor3ubv(v); +} + +static void APIENTRY InitSecondaryColor3ui (GLuint red, GLuint green, GLuint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ui"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ui = extproc; + + glSecondaryColor3ui(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3uiv (const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3uiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3uiv = extproc; + + glSecondaryColor3uiv(v); +} + +static void APIENTRY InitSecondaryColor3us (GLushort red, GLushort green, GLushort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3us"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3us = extproc; + + glSecondaryColor3us(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3usv (const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3usv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3usv = extproc; + + glSecondaryColor3usv(v); +} + +static void APIENTRY InitSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColorPointer"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColorPointer = extproc; + + glSecondaryColorPointer(size, type, stride, pointer); +} + +static void APIENTRY InitWindowPos2d (GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2d = extproc; + + glWindowPos2d(x, y); +} + +static void APIENTRY InitWindowPos2dv (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dv = extproc; + + glWindowPos2dv(v); +} + +static void APIENTRY InitWindowPos2f (GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2f = extproc; + + glWindowPos2f(x, y); +} + +static void APIENTRY InitWindowPos2fv (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fv = extproc; + + glWindowPos2fv(v); +} + +static void APIENTRY InitWindowPos2i (GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2i = extproc; + + glWindowPos2i(x, y); +} + +static void APIENTRY InitWindowPos2iv (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2iv = extproc; + + glWindowPos2iv(v); +} + +static void APIENTRY InitWindowPos2s (GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2s = extproc; + + glWindowPos2s(x, y); +} + +static void APIENTRY InitWindowPos2sv (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2sv = extproc; + + glWindowPos2sv(v); +} + +static void APIENTRY InitWindowPos3d (GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3d"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3d = extproc; + + glWindowPos3d(x, y, z); +} + +static void APIENTRY InitWindowPos3dv (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dv = extproc; + + glWindowPos3dv(v); +} + +static void APIENTRY InitWindowPos3f (GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3f"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3f = extproc; + + glWindowPos3f(x, y, z); +} + +static void APIENTRY InitWindowPos3fv (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fv = extproc; + + glWindowPos3fv(v); +} + +static void APIENTRY InitWindowPos3i (GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3i"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3i = extproc; + + glWindowPos3i(x, y, z); +} + +static void APIENTRY InitWindowPos3iv (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3iv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3iv = extproc; + + glWindowPos3iv(v); +} + +static void APIENTRY InitWindowPos3s (GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3s"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3s = extproc; + + glWindowPos3s(x, y, z); +} + +static void APIENTRY InitWindowPos3sv (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3sv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3sv = extproc; + + glWindowPos3sv(v); +} + +static void APIENTRY InitGenQueries (GLsizei n, GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenQueries"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenQueries = extproc; + + glGenQueries(n, ids); +} + +static void APIENTRY InitDeleteQueries (GLsizei n, const GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteQueries"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteQueries = extproc; + + glDeleteQueries(n, ids); +} + +static GLboolean APIENTRY InitIsQuery (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsQuery"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsQuery = extproc; + + return glIsQuery(id); +} + +static void APIENTRY InitBeginQuery (GLenum target, GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginQuery"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginQuery = extproc; + + glBeginQuery(target, id); +} + +static void APIENTRY InitEndQuery (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndQuery"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndQuery = extproc; + + glEndQuery(target); +} + +static void APIENTRY InitGetQueryiv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryiv = extproc; + + glGetQueryiv(target, pname, params); +} + +static void APIENTRY InitGetQueryObjectiv (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectiv = extproc; + + glGetQueryObjectiv(id, pname, params); +} + +static void APIENTRY InitGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectuiv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectuiv = extproc; + + glGetQueryObjectuiv(id, pname, params); +} + +static void APIENTRY InitBindBuffer (GLenum target, GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindBuffer = extproc; + + glBindBuffer(target, buffer); +} + +static void APIENTRY InitDeleteBuffers (GLsizei n, const GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteBuffers"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteBuffers = extproc; + + glDeleteBuffers(n, buffers); +} + +static void APIENTRY InitGenBuffers (GLsizei n, GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenBuffers"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenBuffers = extproc; + + glGenBuffers(n, buffers); +} + +static GLboolean APIENTRY InitIsBuffer (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsBuffer = extproc; + + return glIsBuffer(buffer); +} + +static void APIENTRY InitBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferData"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferData = extproc; + + glBufferData(target, size, data, usage); +} + +static void APIENTRY InitBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferSubData"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferSubData = extproc; + + glBufferSubData(target, offset, size, data); +} + +static void APIENTRY InitGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferSubData"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferSubData = extproc; + + glGetBufferSubData(target, offset, size, data); +} + +static GLvoid* APIENTRY InitMapBuffer (GLenum target, GLenum access) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glMapBuffer = extproc; + + return glMapBuffer(target, access); +} + +static GLboolean APIENTRY InitUnmapBuffer (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnmapBuffer"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glUnmapBuffer = extproc; + + return glUnmapBuffer(target); +} + +static void APIENTRY InitGetBufferParameteriv (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferParameteriv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferParameteriv = extproc; + + glGetBufferParameteriv(target, pname, params); +} + +static void APIENTRY InitGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferPointerv"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferPointerv = extproc; + + glGetBufferPointerv(target, pname, params); +} + +static void APIENTRY InitActiveTextureARB (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glActiveTextureARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glActiveTextureARB = extproc; + + glActiveTextureARB(texture); +} + +static void APIENTRY InitClientActiveTextureARB (GLenum texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glClientActiveTextureARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glClientActiveTextureARB = extproc; + + glClientActiveTextureARB(texture); +} + +static void APIENTRY InitMultiTexCoord1dARB (GLenum target, GLdouble s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1dARB = extproc; + + glMultiTexCoord1dARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1dvARB = extproc; + + glMultiTexCoord1dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord1fARB (GLenum target, GLfloat s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1fARB = extproc; + + glMultiTexCoord1fARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1fvARB = extproc; + + glMultiTexCoord1fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord1iARB (GLenum target, GLint s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1iARB = extproc; + + glMultiTexCoord1iARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1ivARB = extproc; + + glMultiTexCoord1ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord1sARB (GLenum target, GLshort s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1sARB = extproc; + + glMultiTexCoord1sARB(target, s); +} + +static void APIENTRY InitMultiTexCoord1svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1svARB = extproc; + + glMultiTexCoord1svARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2dARB = extproc; + + glMultiTexCoord2dARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2dvARB = extproc; + + glMultiTexCoord2dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2fARB = extproc; + + glMultiTexCoord2fARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2fvARB = extproc; + + glMultiTexCoord2fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2iARB (GLenum target, GLint s, GLint t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2iARB = extproc; + + glMultiTexCoord2iARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2ivARB = extproc; + + glMultiTexCoord2ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2sARB = extproc; + + glMultiTexCoord2sARB(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2svARB = extproc; + + glMultiTexCoord2svARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3dARB = extproc; + + glMultiTexCoord3dARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3dvARB = extproc; + + glMultiTexCoord3dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3fARB = extproc; + + glMultiTexCoord3fARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3fvARB = extproc; + + glMultiTexCoord3fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3iARB = extproc; + + glMultiTexCoord3iARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3ivARB = extproc; + + glMultiTexCoord3ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3sARB = extproc; + + glMultiTexCoord3sARB(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3svARB = extproc; + + glMultiTexCoord3svARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4dARB = extproc; + + glMultiTexCoord4dARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4dvARB (GLenum target, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4dvARB = extproc; + + glMultiTexCoord4dvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4fARB = extproc; + + glMultiTexCoord4fARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4fvARB (GLenum target, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4fvARB = extproc; + + glMultiTexCoord4fvARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4iARB = extproc; + + glMultiTexCoord4iARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4ivARB (GLenum target, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4ivARB = extproc; + + glMultiTexCoord4ivARB(target, v); +} + +static void APIENTRY InitMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4sARB = extproc; + + glMultiTexCoord4sARB(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4svARB (GLenum target, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4svARB = extproc; + + glMultiTexCoord4svARB(target, v); +} + +static void APIENTRY InitLoadTransposeMatrixfARB (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixfARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixfARB = extproc; + + glLoadTransposeMatrixfARB(m); +} + +static void APIENTRY InitLoadTransposeMatrixdARB (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadTransposeMatrixdARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadTransposeMatrixdARB = extproc; + + glLoadTransposeMatrixdARB(m); +} + +static void APIENTRY InitMultTransposeMatrixfARB (const GLfloat *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixfARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixfARB = extproc; + + glMultTransposeMatrixfARB(m); +} + +static void APIENTRY InitMultTransposeMatrixdARB (const GLdouble *m) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultTransposeMatrixdARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultTransposeMatrixdARB = extproc; + + glMultTransposeMatrixdARB(m); +} + +static void APIENTRY InitSampleCoverageARB (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleCoverageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleCoverageARB = extproc; + + glSampleCoverageARB(value, invert); +} + +static void APIENTRY InitCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage3DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage3DARB = extproc; + + glCompressedTexImage3DARB(target, level, internalformat, width, height, depth, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage2DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage2DARB = extproc; + + glCompressedTexImage2DARB(target, level, internalformat, width, height, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexImage1DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexImage1DARB = extproc; + + glCompressedTexImage1DARB(target, level, internalformat, width, border, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage3DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage3DARB = extproc; + + glCompressedTexSubImage3DARB(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage2DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage2DARB = extproc; + + glCompressedTexSubImage2DARB(target, level, xoffset, yoffset, width, height, format, imageSize, data); +} + +static void APIENTRY InitCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompressedTexSubImage1DARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompressedTexSubImage1DARB = extproc; + + glCompressedTexSubImage1DARB(target, level, xoffset, width, format, imageSize, data); +} + +static void APIENTRY InitGetCompressedTexImageARB (GLenum target, GLint level, GLvoid *img) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCompressedTexImageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCompressedTexImageARB = extproc; + + glGetCompressedTexImageARB(target, level, img); +} + +static void APIENTRY InitPointParameterfARB (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfARB = extproc; + + glPointParameterfARB(pname, param); +} + +static void APIENTRY InitPointParameterfvARB (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfvARB = extproc; + + glPointParameterfvARB(pname, params); +} + +static void APIENTRY InitWeightbvARB (GLint size, const GLbyte *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightbvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightbvARB = extproc; + + glWeightbvARB(size, weights); +} + +static void APIENTRY InitWeightsvARB (GLint size, const GLshort *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightsvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightsvARB = extproc; + + glWeightsvARB(size, weights); +} + +static void APIENTRY InitWeightivARB (GLint size, const GLint *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightivARB = extproc; + + glWeightivARB(size, weights); +} + +static void APIENTRY InitWeightfvARB (GLint size, const GLfloat *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightfvARB = extproc; + + glWeightfvARB(size, weights); +} + +static void APIENTRY InitWeightdvARB (GLint size, const GLdouble *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightdvARB = extproc; + + glWeightdvARB(size, weights); +} + +static void APIENTRY InitWeightubvARB (GLint size, const GLubyte *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightubvARB = extproc; + + glWeightubvARB(size, weights); +} + +static void APIENTRY InitWeightusvARB (GLint size, const GLushort *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightusvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightusvARB = extproc; + + glWeightusvARB(size, weights); +} + +static void APIENTRY InitWeightuivARB (GLint size, const GLuint *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightuivARB = extproc; + + glWeightuivARB(size, weights); +} + +static void APIENTRY InitWeightPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWeightPointerARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWeightPointerARB = extproc; + + glWeightPointerARB(size, type, stride, pointer); +} + +static void APIENTRY InitVertexBlendARB (GLint count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexBlendARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexBlendARB = extproc; + + glVertexBlendARB(count); +} + +static void APIENTRY InitCurrentPaletteMatrixARB (GLint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCurrentPaletteMatrixARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCurrentPaletteMatrixARB = extproc; + + glCurrentPaletteMatrixARB(index); +} + +static void APIENTRY InitMatrixIndexubvARB (GLint size, const GLubyte *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexubvARB = extproc; + + glMatrixIndexubvARB(size, indices); +} + +static void APIENTRY InitMatrixIndexusvARB (GLint size, const GLushort *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexusvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexusvARB = extproc; + + glMatrixIndexusvARB(size, indices); +} + +static void APIENTRY InitMatrixIndexuivARB (GLint size, const GLuint *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexuivARB = extproc; + + glMatrixIndexuivARB(size, indices); +} + +static void APIENTRY InitMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMatrixIndexPointerARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMatrixIndexPointerARB = extproc; + + glMatrixIndexPointerARB(size, type, stride, pointer); +} + +static void APIENTRY InitWindowPos2dARB (GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dARB = extproc; + + glWindowPos2dARB(x, y); +} + +static void APIENTRY InitWindowPos2dvARB (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dvARB = extproc; + + glWindowPos2dvARB(v); +} + +static void APIENTRY InitWindowPos2fARB (GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fARB = extproc; + + glWindowPos2fARB(x, y); +} + +static void APIENTRY InitWindowPos2fvARB (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fvARB = extproc; + + glWindowPos2fvARB(v); +} + +static void APIENTRY InitWindowPos2iARB (GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2iARB = extproc; + + glWindowPos2iARB(x, y); +} + +static void APIENTRY InitWindowPos2ivARB (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2ivARB = extproc; + + glWindowPos2ivARB(v); +} + +static void APIENTRY InitWindowPos2sARB (GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2sARB = extproc; + + glWindowPos2sARB(x, y); +} + +static void APIENTRY InitWindowPos2svARB (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2svARB = extproc; + + glWindowPos2svARB(v); +} + +static void APIENTRY InitWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dARB = extproc; + + glWindowPos3dARB(x, y, z); +} + +static void APIENTRY InitWindowPos3dvARB (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dvARB = extproc; + + glWindowPos3dvARB(v); +} + +static void APIENTRY InitWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fARB = extproc; + + glWindowPos3fARB(x, y, z); +} + +static void APIENTRY InitWindowPos3fvARB (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fvARB = extproc; + + glWindowPos3fvARB(v); +} + +static void APIENTRY InitWindowPos3iARB (GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3iARB = extproc; + + glWindowPos3iARB(x, y, z); +} + +static void APIENTRY InitWindowPos3ivARB (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3ivARB = extproc; + + glWindowPos3ivARB(v); +} + +static void APIENTRY InitWindowPos3sARB (GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3sARB = extproc; + + glWindowPos3sARB(x, y, z); +} + +static void APIENTRY InitWindowPos3svARB (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3svARB = extproc; + + glWindowPos3svARB(v); +} + +static void APIENTRY InitVertexAttrib1dARB (GLuint index, GLdouble x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dARB = extproc; + + glVertexAttrib1dARB(index, x); +} + +static void APIENTRY InitVertexAttrib1dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dvARB = extproc; + + glVertexAttrib1dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib1fARB (GLuint index, GLfloat x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fARB = extproc; + + glVertexAttrib1fARB(index, x); +} + +static void APIENTRY InitVertexAttrib1fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fvARB = extproc; + + glVertexAttrib1fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib1sARB (GLuint index, GLshort x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1sARB = extproc; + + glVertexAttrib1sARB(index, x); +} + +static void APIENTRY InitVertexAttrib1svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1svARB = extproc; + + glVertexAttrib1svARB(index, v); +} + +static void APIENTRY InitVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dARB = extproc; + + glVertexAttrib2dARB(index, x, y); +} + +static void APIENTRY InitVertexAttrib2dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dvARB = extproc; + + glVertexAttrib2dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fARB = extproc; + + glVertexAttrib2fARB(index, x, y); +} + +static void APIENTRY InitVertexAttrib2fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fvARB = extproc; + + glVertexAttrib2fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib2sARB (GLuint index, GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2sARB = extproc; + + glVertexAttrib2sARB(index, x, y); +} + +static void APIENTRY InitVertexAttrib2svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2svARB = extproc; + + glVertexAttrib2svARB(index, v); +} + +static void APIENTRY InitVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dARB = extproc; + + glVertexAttrib3dARB(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dvARB = extproc; + + glVertexAttrib3dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fARB = extproc; + + glVertexAttrib3fARB(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fvARB = extproc; + + glVertexAttrib3fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3sARB = extproc; + + glVertexAttrib3sARB(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3svARB = extproc; + + glVertexAttrib3svARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NbvARB (GLuint index, const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NbvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NbvARB = extproc; + + glVertexAttrib4NbvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NivARB (GLuint index, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NivARB = extproc; + + glVertexAttrib4NivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NsvARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NsvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NsvARB = extproc; + + glVertexAttrib4NsvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NubARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NubARB = extproc; + + glVertexAttrib4NubARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4NubvARB (GLuint index, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NubvARB = extproc; + + glVertexAttrib4NubvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NuivARB (GLuint index, const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NuivARB = extproc; + + glVertexAttrib4NuivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4NusvARB (GLuint index, const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4NusvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4NusvARB = extproc; + + glVertexAttrib4NusvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4bvARB (GLuint index, const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4bvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4bvARB = extproc; + + glVertexAttrib4bvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dARB = extproc; + + glVertexAttrib4dARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4dvARB (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dvARB = extproc; + + glVertexAttrib4dvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fARB = extproc; + + glVertexAttrib4fARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4fvARB (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fvARB = extproc; + + glVertexAttrib4fvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4ivARB (GLuint index, const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ivARB = extproc; + + glVertexAttrib4ivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4sARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4sARB = extproc; + + glVertexAttrib4sARB(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4svARB (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4svARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4svARB = extproc; + + glVertexAttrib4svARB(index, v); +} + +static void APIENTRY InitVertexAttrib4ubvARB (GLuint index, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ubvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ubvARB = extproc; + + glVertexAttrib4ubvARB(index, v); +} + +static void APIENTRY InitVertexAttrib4uivARB (GLuint index, const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4uivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4uivARB = extproc; + + glVertexAttrib4uivARB(index, v); +} + +static void APIENTRY InitVertexAttrib4usvARB (GLuint index, const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4usvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4usvARB = extproc; + + glVertexAttrib4usvARB(index, v); +} + +static void APIENTRY InitVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribPointerARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribPointerARB = extproc; + + glVertexAttribPointerARB(index, size, type, normalized, stride, pointer); +} + +static void APIENTRY InitEnableVertexAttribArrayARB (GLuint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEnableVertexAttribArrayARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEnableVertexAttribArrayARB = extproc; + + glEnableVertexAttribArrayARB(index); +} + +static void APIENTRY InitDisableVertexAttribArrayARB (GLuint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDisableVertexAttribArrayARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDisableVertexAttribArrayARB = extproc; + + glDisableVertexAttribArrayARB(index); +} + +static void APIENTRY InitProgramStringARB (GLenum target, GLenum format, GLsizei len, const GLvoid *string) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramStringARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramStringARB = extproc; + + glProgramStringARB(target, format, len, string); +} + +static void APIENTRY InitBindProgramARB (GLenum target, GLuint program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindProgramARB = extproc; + + glBindProgramARB(target, program); +} + +static void APIENTRY InitDeleteProgramsARB (GLsizei n, const GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteProgramsARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteProgramsARB = extproc; + + glDeleteProgramsARB(n, programs); +} + +static void APIENTRY InitGenProgramsARB (GLsizei n, GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenProgramsARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenProgramsARB = extproc; + + glGenProgramsARB(n, programs); +} + +static void APIENTRY InitProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4dARB = extproc; + + glProgramEnvParameter4dARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4dvARB = extproc; + + glProgramEnvParameter4dvARB(target, index, params); +} + +static void APIENTRY InitProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4fARB = extproc; + + glProgramEnvParameter4fARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramEnvParameter4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramEnvParameter4fvARB = extproc; + + glProgramEnvParameter4fvARB(target, index, params); +} + +static void APIENTRY InitProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4dARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4dARB = extproc; + + glProgramLocalParameter4dARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4dvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4dvARB = extproc; + + glProgramLocalParameter4dvARB(target, index, params); +} + +static void APIENTRY InitProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4fARB = extproc; + + glProgramLocalParameter4fARB(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramLocalParameter4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramLocalParameter4fvARB = extproc; + + glProgramLocalParameter4fvARB(target, index, params); +} + +static void APIENTRY InitGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramEnvParameterdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramEnvParameterdvARB = extproc; + + glGetProgramEnvParameterdvARB(target, index, params); +} + +static void APIENTRY InitGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramEnvParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramEnvParameterfvARB = extproc; + + glGetProgramEnvParameterfvARB(target, index, params); +} + +static void APIENTRY InitGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramLocalParameterdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramLocalParameterdvARB = extproc; + + glGetProgramLocalParameterdvARB(target, index, params); +} + +static void APIENTRY InitGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramLocalParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramLocalParameterfvARB = extproc; + + glGetProgramLocalParameterfvARB(target, index, params); +} + +static void APIENTRY InitGetProgramivARB (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramivARB = extproc; + + glGetProgramivARB(target, pname, params); +} + +static void APIENTRY InitGetProgramStringARB (GLenum target, GLenum pname, GLvoid *string) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramStringARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramStringARB = extproc; + + glGetProgramStringARB(target, pname, string); +} + +static void APIENTRY InitGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribdvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribdvARB = extproc; + + glGetVertexAttribdvARB(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribfvARB = extproc; + + glGetVertexAttribfvARB(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribivARB = extproc; + + glGetVertexAttribivARB(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribPointervARB (GLuint index, GLenum pname, GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribPointervARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribPointervARB = extproc; + + glGetVertexAttribPointervARB(index, pname, pointer); +} + +static GLboolean APIENTRY InitIsProgramARB (GLuint program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsProgramARB = extproc; + + return glIsProgramARB(program); +} + +static void APIENTRY InitBindBufferARB (GLenum target, GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindBufferARB = extproc; + + glBindBufferARB(target, buffer); +} + +static void APIENTRY InitDeleteBuffersARB (GLsizei n, const GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteBuffersARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteBuffersARB = extproc; + + glDeleteBuffersARB(n, buffers); +} + +static void APIENTRY InitGenBuffersARB (GLsizei n, GLuint *buffers) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenBuffersARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenBuffersARB = extproc; + + glGenBuffersARB(n, buffers); +} + +static GLboolean APIENTRY InitIsBufferARB (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsBufferARB = extproc; + + return glIsBufferARB(buffer); +} + +static void APIENTRY InitBufferDataARB (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferDataARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferDataARB = extproc; + + glBufferDataARB(target, size, data, usage); +} + +static void APIENTRY InitBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBufferSubDataARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBufferSubDataARB = extproc; + + glBufferSubDataARB(target, offset, size, data); +} + +static void APIENTRY InitGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferSubDataARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferSubDataARB = extproc; + + glGetBufferSubDataARB(target, offset, size, data); +} + +static GLvoid* APIENTRY InitMapBufferARB (GLenum target, GLenum access) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glMapBufferARB = extproc; + + return glMapBufferARB(target, access); +} + +static GLboolean APIENTRY InitUnmapBufferARB (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnmapBufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glUnmapBufferARB = extproc; + + return glUnmapBufferARB(target); +} + +static void APIENTRY InitGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferParameterivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferParameterivARB = extproc; + + glGetBufferParameterivARB(target, pname, params); +} + +static void APIENTRY InitGetBufferPointervARB (GLenum target, GLenum pname, GLvoid* *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetBufferPointervARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetBufferPointervARB = extproc; + + glGetBufferPointervARB(target, pname, params); +} + +static void APIENTRY InitGenQueriesARB (GLsizei n, GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenQueriesARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenQueriesARB = extproc; + + glGenQueriesARB(n, ids); +} + +static void APIENTRY InitDeleteQueriesARB (GLsizei n, const GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteQueriesARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteQueriesARB = extproc; + + glDeleteQueriesARB(n, ids); +} + +static GLboolean APIENTRY InitIsQueryARB (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsQueryARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsQueryARB = extproc; + + return glIsQueryARB(id); +} + +static void APIENTRY InitBeginQueryARB (GLenum target, GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginQueryARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginQueryARB = extproc; + + glBeginQueryARB(target, id); +} + +static void APIENTRY InitEndQueryARB (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndQueryARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndQueryARB = extproc; + + glEndQueryARB(target); +} + +static void APIENTRY InitGetQueryivARB (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryivARB = extproc; + + glGetQueryivARB(target, pname, params); +} + +static void APIENTRY InitGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectivARB = extproc; + + glGetQueryObjectivARB(id, pname, params); +} + +static void APIENTRY InitGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetQueryObjectuivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetQueryObjectuivARB = extproc; + + glGetQueryObjectuivARB(id, pname, params); +} + +static void APIENTRY InitDeleteObjectARB (GLhandleARB obj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteObjectARB = extproc; + + glDeleteObjectARB(obj); +} + +static GLhandleARB APIENTRY InitGetHandleARB (GLenum pname) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHandleARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetHandleARB = extproc; + + return glGetHandleARB(pname); +} + +static void APIENTRY InitDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDetachObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDetachObjectARB = extproc; + + glDetachObjectARB(containerObj, attachedObj); +} + +static GLhandleARB APIENTRY InitCreateShaderObjectARB (GLenum shaderType) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCreateShaderObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glCreateShaderObjectARB = extproc; + + return glCreateShaderObjectARB(shaderType); +} + +static void APIENTRY InitShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderSourceARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderSourceARB = extproc; + + glShaderSourceARB(shaderObj, count, string, length); +} + +static void APIENTRY InitCompileShaderARB (GLhandleARB shaderObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCompileShaderARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCompileShaderARB = extproc; + + glCompileShaderARB(shaderObj); +} + +static GLhandleARB APIENTRY InitCreateProgramObjectARB (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCreateProgramObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glCreateProgramObjectARB = extproc; + + return glCreateProgramObjectARB(); +} + +static void APIENTRY InitAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAttachObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAttachObjectARB = extproc; + + glAttachObjectARB(containerObj, obj); +} + +static void APIENTRY InitLinkProgramARB (GLhandleARB programObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLinkProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLinkProgramARB = extproc; + + glLinkProgramARB(programObj); +} + +static void APIENTRY InitUseProgramObjectARB (GLhandleARB programObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUseProgramObjectARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUseProgramObjectARB = extproc; + + glUseProgramObjectARB(programObj); +} + +static void APIENTRY InitValidateProgramARB (GLhandleARB programObj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glValidateProgramARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glValidateProgramARB = extproc; + + glValidateProgramARB(programObj); +} + +static void APIENTRY InitUniform1fARB (GLint location, GLfloat v0) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1fARB = extproc; + + glUniform1fARB(location, v0); +} + +static void APIENTRY InitUniform2fARB (GLint location, GLfloat v0, GLfloat v1) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2fARB = extproc; + + glUniform2fARB(location, v0, v1); +} + +static void APIENTRY InitUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3fARB = extproc; + + glUniform3fARB(location, v0, v1, v2); +} + +static void APIENTRY InitUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4fARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4fARB = extproc; + + glUniform4fARB(location, v0, v1, v2, v3); +} + +static void APIENTRY InitUniform1iARB (GLint location, GLint v0) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1iARB = extproc; + + glUniform1iARB(location, v0); +} + +static void APIENTRY InitUniform2iARB (GLint location, GLint v0, GLint v1) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2iARB = extproc; + + glUniform2iARB(location, v0, v1); +} + +static void APIENTRY InitUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3iARB = extproc; + + glUniform3iARB(location, v0, v1, v2); +} + +static void APIENTRY InitUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4iARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4iARB = extproc; + + glUniform4iARB(location, v0, v1, v2, v3); +} + +static void APIENTRY InitUniform1fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1fvARB = extproc; + + glUniform1fvARB(location, count, value); +} + +static void APIENTRY InitUniform2fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2fvARB = extproc; + + glUniform2fvARB(location, count, value); +} + +static void APIENTRY InitUniform3fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3fvARB = extproc; + + glUniform3fvARB(location, count, value); +} + +static void APIENTRY InitUniform4fvARB (GLint location, GLsizei count, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4fvARB = extproc; + + glUniform4fvARB(location, count, value); +} + +static void APIENTRY InitUniform1ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform1ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform1ivARB = extproc; + + glUniform1ivARB(location, count, value); +} + +static void APIENTRY InitUniform2ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform2ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform2ivARB = extproc; + + glUniform2ivARB(location, count, value); +} + +static void APIENTRY InitUniform3ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform3ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform3ivARB = extproc; + + glUniform3ivARB(location, count, value); +} + +static void APIENTRY InitUniform4ivARB (GLint location, GLsizei count, const GLint *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniform4ivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniform4ivARB = extproc; + + glUniform4ivARB(location, count, value); +} + +static void APIENTRY InitUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniformMatrix2fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniformMatrix2fvARB = extproc; + + glUniformMatrix2fvARB(location, count, transpose, value); +} + +static void APIENTRY InitUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniformMatrix3fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniformMatrix3fvARB = extproc; + + glUniformMatrix3fvARB(location, count, transpose, value); +} + +static void APIENTRY InitUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUniformMatrix4fvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUniformMatrix4fvARB = extproc; + + glUniformMatrix4fvARB(location, count, transpose, value); +} + +static void APIENTRY InitGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectParameterfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectParameterfvARB = extproc; + + glGetObjectParameterfvARB(obj, pname, params); +} + +static void APIENTRY InitGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectParameterivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectParameterivARB = extproc; + + glGetObjectParameterivARB(obj, pname, params); +} + +static void APIENTRY InitGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInfoLogARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInfoLogARB = extproc; + + glGetInfoLogARB(obj, maxLength, length, infoLog); +} + +static void APIENTRY InitGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetAttachedObjectsARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetAttachedObjectsARB = extproc; + + glGetAttachedObjectsARB(containerObj, maxCount, count, obj); +} + +static GLint APIENTRY InitGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetUniformLocationARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetUniformLocationARB = extproc; + + return glGetUniformLocationARB(programObj, name); +} + +static void APIENTRY InitGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetActiveUniformARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetActiveUniformARB = extproc; + + glGetActiveUniformARB(programObj, index, maxLength, length, size, type, name); +} + +static void APIENTRY InitGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetUniformfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetUniformfvARB = extproc; + + glGetUniformfvARB(programObj, location, params); +} + +static void APIENTRY InitGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetUniformivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetUniformivARB = extproc; + + glGetUniformivARB(programObj, location, params); +} + +static void APIENTRY InitGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetShaderSourceARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetShaderSourceARB = extproc; + + glGetShaderSourceARB(obj, maxLength, length, source); +} + +static void APIENTRY InitBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindAttribLocationARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindAttribLocationARB = extproc; + + glBindAttribLocationARB(programObj, index, name); +} + +static void APIENTRY InitGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetActiveAttribARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetActiveAttribARB = extproc; + + glGetActiveAttribARB(programObj, index, maxLength, length, size, type, name); +} + +static GLint APIENTRY InitGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetAttribLocationARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetAttribLocationARB = extproc; + + return glGetAttribLocationARB(programObj, name); +} + +static void APIENTRY InitBlendColorEXT (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendColorEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendColorEXT = extproc; + + glBlendColorEXT(red, green, blue, alpha); +} + +static void APIENTRY InitPolygonOffsetEXT (GLfloat factor, GLfloat bias) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPolygonOffsetEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPolygonOffsetEXT = extproc; + + glPolygonOffsetEXT(factor, bias); +} + +static void APIENTRY InitTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexImage3DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexImage3DEXT = extproc; + + glTexImage3DEXT(target, level, internalformat, width, height, depth, border, format, type, pixels); +} + +static void APIENTRY InitTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage3DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage3DEXT = extproc; + + glTexSubImage3DEXT(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); +} + +static void APIENTRY InitGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTexFilterFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTexFilterFuncSGIS = extproc; + + glGetTexFilterFuncSGIS(target, filter, weights); +} + +static void APIENTRY InitTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexFilterFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexFilterFuncSGIS = extproc; + + glTexFilterFuncSGIS(target, filter, n, weights); +} + +static void APIENTRY InitTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage1DEXT = extproc; + + glTexSubImage1DEXT(target, level, xoffset, width, format, type, pixels); +} + +static void APIENTRY InitTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage2DEXT = extproc; + + glTexSubImage2DEXT(target, level, xoffset, yoffset, width, height, format, type, pixels); +} + +static void APIENTRY InitCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexImage1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexImage1DEXT = extproc; + + glCopyTexImage1DEXT(target, level, internalformat, x, y, width, border); +} + +static void APIENTRY InitCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexImage2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexImage2DEXT = extproc; + + glCopyTexImage2DEXT(target, level, internalformat, x, y, width, height, border); +} + +static void APIENTRY InitCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage1DEXT = extproc; + + glCopyTexSubImage1DEXT(target, level, xoffset, x, y, width); +} + +static void APIENTRY InitCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage2DEXT = extproc; + + glCopyTexSubImage2DEXT(target, level, xoffset, yoffset, x, y, width, height); +} + +static void APIENTRY InitCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyTexSubImage3DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyTexSubImage3DEXT = extproc; + + glCopyTexSubImage3DEXT(target, level, xoffset, yoffset, zoffset, x, y, width, height); +} + +static void APIENTRY InitGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramEXT = extproc; + + glGetHistogramEXT(target, reset, format, type, values); +} + +static void APIENTRY InitGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameterfvEXT = extproc; + + glGetHistogramParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetHistogramParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetHistogramParameterivEXT = extproc; + + glGetHistogramParameterivEXT(target, pname, params); +} + +static void APIENTRY InitGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxEXT = extproc; + + glGetMinmaxEXT(target, reset, format, type, values); +} + +static void APIENTRY InitGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameterfvEXT = extproc; + + glGetMinmaxParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMinmaxParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMinmaxParameterivEXT = extproc; + + glGetMinmaxParameterivEXT(target, pname, params); +} + +static void APIENTRY InitHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glHistogramEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glHistogramEXT = extproc; + + glHistogramEXT(target, width, internalformat, sink); +} + +static void APIENTRY InitMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMinmaxEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMinmaxEXT = extproc; + + glMinmaxEXT(target, internalformat, sink); +} + +static void APIENTRY InitResetHistogramEXT (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetHistogramEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetHistogramEXT = extproc; + + glResetHistogramEXT(target); +} + +static void APIENTRY InitResetMinmaxEXT (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResetMinmaxEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResetMinmaxEXT = extproc; + + glResetMinmaxEXT(target); +} + +static void APIENTRY InitConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter1DEXT = extproc; + + glConvolutionFilter1DEXT(target, internalformat, width, format, type, image); +} + +static void APIENTRY InitConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionFilter2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionFilter2DEXT = extproc; + + glConvolutionFilter2DEXT(target, internalformat, width, height, format, type, image); +} + +static void APIENTRY InitConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterfEXT = extproc; + + glConvolutionParameterfEXT(target, pname, params); +} + +static void APIENTRY InitConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterfvEXT = extproc; + + glConvolutionParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameteriEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameteriEXT = extproc; + + glConvolutionParameteriEXT(target, pname, params); +} + +static void APIENTRY InitConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glConvolutionParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glConvolutionParameterivEXT = extproc; + + glConvolutionParameterivEXT(target, pname, params); +} + +static void APIENTRY InitCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter1DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter1DEXT = extproc; + + glCopyConvolutionFilter1DEXT(target, internalformat, x, y, width); +} + +static void APIENTRY InitCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyConvolutionFilter2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyConvolutionFilter2DEXT = extproc; + + glCopyConvolutionFilter2DEXT(target, internalformat, x, y, width, height); +} + +static void APIENTRY InitGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *image) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionFilterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionFilterEXT = extproc; + + glGetConvolutionFilterEXT(target, format, type, image); +} + +static void APIENTRY InitGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameterfvEXT = extproc; + + glGetConvolutionParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetConvolutionParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetConvolutionParameterivEXT = extproc; + + glGetConvolutionParameterivEXT(target, pname, params); +} + +static void APIENTRY InitGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetSeparableFilterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetSeparableFilterEXT = extproc; + + glGetSeparableFilterEXT(target, format, type, row, column, span); +} + +static void APIENTRY InitSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSeparableFilter2DEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSeparableFilter2DEXT = extproc; + + glSeparableFilter2DEXT(target, internalformat, width, height, format, type, row, column); +} + +static void APIENTRY InitColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableSGI = extproc; + + glColorTableSGI(target, internalformat, width, format, type, table); +} + +static void APIENTRY InitColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameterfvSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameterfvSGI = extproc; + + glColorTableParameterfvSGI(target, pname, params); +} + +static void APIENTRY InitColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableParameterivSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableParameterivSGI = extproc; + + glColorTableParameterivSGI(target, pname, params); +} + +static void APIENTRY InitCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorTableSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorTableSGI = extproc; + + glCopyColorTableSGI(target, internalformat, x, y, width); +} + +static void APIENTRY InitGetColorTableSGI (GLenum target, GLenum format, GLenum type, GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableSGI = extproc; + + glGetColorTableSGI(target, format, type, table); +} + +static void APIENTRY InitGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterfvSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterfvSGI = extproc; + + glGetColorTableParameterfvSGI(target, pname, params); +} + +static void APIENTRY InitGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterivSGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterivSGI = extproc; + + glGetColorTableParameterivSGI(target, pname, params); +} + +static void APIENTRY InitPixelTexGenSGIX (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenSGIX = extproc; + + glPixelTexGenSGIX(mode); +} + +static void APIENTRY InitPixelTexGenParameteriSGIS (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameteriSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameteriSGIS = extproc; + + glPixelTexGenParameteriSGIS(pname, param); +} + +static void APIENTRY InitPixelTexGenParameterivSGIS (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameterivSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameterivSGIS = extproc; + + glPixelTexGenParameterivSGIS(pname, params); +} + +static void APIENTRY InitPixelTexGenParameterfSGIS (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameterfSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameterfSGIS = extproc; + + glPixelTexGenParameterfSGIS(pname, param); +} + +static void APIENTRY InitPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTexGenParameterfvSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTexGenParameterfvSGIS = extproc; + + glPixelTexGenParameterfvSGIS(pname, params); +} + +static void APIENTRY InitGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetPixelTexGenParameterivSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetPixelTexGenParameterivSGIS = extproc; + + glGetPixelTexGenParameterivSGIS(pname, params); +} + +static void APIENTRY InitGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetPixelTexGenParameterfvSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetPixelTexGenParameterfvSGIS = extproc; + + glGetPixelTexGenParameterfvSGIS(pname, params); +} + +static void APIENTRY InitTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexImage4DSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexImage4DSGIS = extproc; + + glTexImage4DSGIS(target, level, internalformat, width, height, depth, size4d, border, format, type, pixels); +} + +static void APIENTRY InitTexSubImage4DSGIS (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 GLvoid *pixels) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexSubImage4DSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexSubImage4DSGIS = extproc; + + glTexSubImage4DSGIS(target, level, xoffset, yoffset, zoffset, woffset, width, height, depth, size4d, format, type, pixels); +} + +static GLboolean APIENTRY InitAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAreTexturesResidentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glAreTexturesResidentEXT = extproc; + + return glAreTexturesResidentEXT(n, textures, residences); +} + +static void APIENTRY InitBindTextureEXT (GLenum target, GLuint texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindTextureEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindTextureEXT = extproc; + + glBindTextureEXT(target, texture); +} + +static void APIENTRY InitDeleteTexturesEXT (GLsizei n, const GLuint *textures) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteTexturesEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteTexturesEXT = extproc; + + glDeleteTexturesEXT(n, textures); +} + +static void APIENTRY InitGenTexturesEXT (GLsizei n, GLuint *textures) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenTexturesEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenTexturesEXT = extproc; + + glGenTexturesEXT(n, textures); +} + +static GLboolean APIENTRY InitIsTextureEXT (GLuint texture) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsTextureEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsTextureEXT = extproc; + + return glIsTextureEXT(texture); +} + +static void APIENTRY InitPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPrioritizeTexturesEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPrioritizeTexturesEXT = extproc; + + glPrioritizeTexturesEXT(n, textures, priorities); +} + +static void APIENTRY InitDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDetailTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDetailTexFuncSGIS = extproc; + + glDetailTexFuncSGIS(target, n, points); +} + +static void APIENTRY InitGetDetailTexFuncSGIS (GLenum target, GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetDetailTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetDetailTexFuncSGIS = extproc; + + glGetDetailTexFuncSGIS(target, points); +} + +static void APIENTRY InitSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSharpenTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSharpenTexFuncSGIS = extproc; + + glSharpenTexFuncSGIS(target, n, points); +} + +static void APIENTRY InitGetSharpenTexFuncSGIS (GLenum target, GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetSharpenTexFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetSharpenTexFuncSGIS = extproc; + + glGetSharpenTexFuncSGIS(target, points); +} + +static void APIENTRY InitSampleMaskSGIS (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleMaskSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleMaskSGIS = extproc; + + glSampleMaskSGIS(value, invert); +} + +static void APIENTRY InitSamplePatternSGIS (GLenum pattern) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSamplePatternSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSamplePatternSGIS = extproc; + + glSamplePatternSGIS(pattern); +} + +static void APIENTRY InitArrayElementEXT (GLint i) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glArrayElementEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glArrayElementEXT = extproc; + + glArrayElementEXT(i); +} + +static void APIENTRY InitColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorPointerEXT = extproc; + + glColorPointerEXT(size, type, stride, count, pointer); +} + +static void APIENTRY InitDrawArraysEXT (GLenum mode, GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawArraysEXT = extproc; + + glDrawArraysEXT(mode, first, count); +} + +static void APIENTRY InitEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEdgeFlagPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEdgeFlagPointerEXT = extproc; + + glEdgeFlagPointerEXT(stride, count, pointer); +} + +static void APIENTRY InitGetPointervEXT (GLenum pname, GLvoid* *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetPointervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetPointervEXT = extproc; + + glGetPointervEXT(pname, params); +} + +static void APIENTRY InitIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexPointerEXT = extproc; + + glIndexPointerEXT(type, stride, count, pointer); +} + +static void APIENTRY InitNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalPointerEXT = extproc; + + glNormalPointerEXT(type, stride, count, pointer); +} + +static void APIENTRY InitTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoordPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoordPointerEXT = extproc; + + glTexCoordPointerEXT(size, type, stride, count, pointer); +} + +static void APIENTRY InitVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexPointerEXT = extproc; + + glVertexPointerEXT(size, type, stride, count, pointer); +} + +static void APIENTRY InitBlendEquationEXT (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendEquationEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendEquationEXT = extproc; + + glBlendEquationEXT(mode); +} + +static void APIENTRY InitSpriteParameterfSGIX (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameterfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameterfSGIX = extproc; + + glSpriteParameterfSGIX(pname, param); +} + +static void APIENTRY InitSpriteParameterfvSGIX (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameterfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameterfvSGIX = extproc; + + glSpriteParameterfvSGIX(pname, params); +} + +static void APIENTRY InitSpriteParameteriSGIX (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameteriSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameteriSGIX = extproc; + + glSpriteParameteriSGIX(pname, param); +} + +static void APIENTRY InitSpriteParameterivSGIX (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSpriteParameterivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSpriteParameterivSGIX = extproc; + + glSpriteParameterivSGIX(pname, params); +} + +static void APIENTRY InitPointParameterfEXT (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfEXT = extproc; + + glPointParameterfEXT(pname, param); +} + +static void APIENTRY InitPointParameterfvEXT (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfvEXT = extproc; + + glPointParameterfvEXT(pname, params); +} + +static void APIENTRY InitPointParameterfSGIS (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfSGIS = extproc; + + glPointParameterfSGIS(pname, param); +} + +static void APIENTRY InitPointParameterfvSGIS (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterfvSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterfvSGIS = extproc; + + glPointParameterfvSGIS(pname, params); +} + +static GLint APIENTRY InitGetInstrumentsSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGetInstrumentsSGIX = extproc; + + return glGetInstrumentsSGIX(); +} + +static void APIENTRY InitInstrumentsBufferSGIX (GLsizei size, GLint *buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glInstrumentsBufferSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glInstrumentsBufferSGIX = extproc; + + glInstrumentsBufferSGIX(size, buffer); +} + +static GLint APIENTRY InitPollInstrumentsSGIX (GLint *marker_p) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPollInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glPollInstrumentsSGIX = extproc; + + return glPollInstrumentsSGIX(marker_p); +} + +static void APIENTRY InitReadInstrumentsSGIX (GLint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReadInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReadInstrumentsSGIX = extproc; + + glReadInstrumentsSGIX(marker); +} + +static void APIENTRY InitStartInstrumentsSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStartInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStartInstrumentsSGIX = extproc; + + glStartInstrumentsSGIX(); +} + +static void APIENTRY InitStopInstrumentsSGIX (GLint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStopInstrumentsSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStopInstrumentsSGIX = extproc; + + glStopInstrumentsSGIX(marker); +} + +static void APIENTRY InitFrameZoomSGIX (GLint factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFrameZoomSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFrameZoomSGIX = extproc; + + glFrameZoomSGIX(factor); +} + +static void APIENTRY InitTagSampleBufferSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTagSampleBufferSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTagSampleBufferSGIX = extproc; + + glTagSampleBufferSGIX(); +} + +static void APIENTRY InitDeformationMap3dSGIX (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) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeformationMap3dSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeformationMap3dSGIX = extproc; + + glDeformationMap3dSGIX(target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, w1, w2, wstride, worder, points); +} + +static void APIENTRY InitDeformationMap3fSGIX (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) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeformationMap3fSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeformationMap3fSGIX = extproc; + + glDeformationMap3fSGIX(target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, w1, w2, wstride, worder, points); +} + +static void APIENTRY InitDeformSGIX (GLbitfield mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeformSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeformSGIX = extproc; + + glDeformSGIX(mask); +} + +static void APIENTRY InitLoadIdentityDeformationMapSGIX (GLbitfield mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadIdentityDeformationMapSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadIdentityDeformationMapSGIX = extproc; + + glLoadIdentityDeformationMapSGIX(mask); +} + +static void APIENTRY InitReferencePlaneSGIX (const GLdouble *equation) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReferencePlaneSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReferencePlaneSGIX = extproc; + + glReferencePlaneSGIX(equation); +} + +static void APIENTRY InitFlushRasterSGIX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushRasterSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushRasterSGIX = extproc; + + glFlushRasterSGIX(); +} + +static void APIENTRY InitFogFuncSGIS (GLsizei n, const GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogFuncSGIS = extproc; + + glFogFuncSGIS(n, points); +} + +static void APIENTRY InitGetFogFuncSGIS (GLfloat *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFogFuncSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFogFuncSGIS = extproc; + + glGetFogFuncSGIS(points); +} + +static void APIENTRY InitImageTransformParameteriHP (GLenum target, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameteriHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameteriHP = extproc; + + glImageTransformParameteriHP(target, pname, param); +} + +static void APIENTRY InitImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameterfHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameterfHP = extproc; + + glImageTransformParameterfHP(target, pname, param); +} + +static void APIENTRY InitImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameterivHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameterivHP = extproc; + + glImageTransformParameterivHP(target, pname, params); +} + +static void APIENTRY InitImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glImageTransformParameterfvHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glImageTransformParameterfvHP = extproc; + + glImageTransformParameterfvHP(target, pname, params); +} + +static void APIENTRY InitGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetImageTransformParameterivHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetImageTransformParameterivHP = extproc; + + glGetImageTransformParameterivHP(target, pname, params); +} + +static void APIENTRY InitGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetImageTransformParameterfvHP"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetImageTransformParameterfvHP = extproc; + + glGetImageTransformParameterfvHP(target, pname, params); +} + +static void APIENTRY InitColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorSubTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorSubTableEXT = extproc; + + glColorSubTableEXT(target, start, count, format, type, data); +} + +static void APIENTRY InitCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCopyColorSubTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCopyColorSubTableEXT = extproc; + + glCopyColorSubTableEXT(target, start, x, y, width); +} + +static void APIENTRY InitHintPGI (GLenum target, GLint mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glHintPGI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glHintPGI = extproc; + + glHintPGI(target, mode); +} + +static void APIENTRY InitColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorTableEXT = extproc; + + glColorTableEXT(target, internalFormat, width, format, type, table); +} + +static void APIENTRY InitGetColorTableEXT (GLenum target, GLenum format, GLenum type, GLvoid *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableEXT = extproc; + + glGetColorTableEXT(target, format, type, data); +} + +static void APIENTRY InitGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterivEXT = extproc; + + glGetColorTableParameterivEXT(target, pname, params); +} + +static void APIENTRY InitGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetColorTableParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetColorTableParameterfvEXT = extproc; + + glGetColorTableParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetListParameterfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetListParameterfvSGIX = extproc; + + glGetListParameterfvSGIX(list, pname, params); +} + +static void APIENTRY InitGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetListParameterivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetListParameterivSGIX = extproc; + + glGetListParameterivSGIX(list, pname, params); +} + +static void APIENTRY InitListParameterfSGIX (GLuint list, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameterfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameterfSGIX = extproc; + + glListParameterfSGIX(list, pname, param); +} + +static void APIENTRY InitListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameterfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameterfvSGIX = extproc; + + glListParameterfvSGIX(list, pname, params); +} + +static void APIENTRY InitListParameteriSGIX (GLuint list, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameteriSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameteriSGIX = extproc; + + glListParameteriSGIX(list, pname, param); +} + +static void APIENTRY InitListParameterivSGIX (GLuint list, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glListParameterivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glListParameterivSGIX = extproc; + + glListParameterivSGIX(list, pname, params); +} + +static void APIENTRY InitIndexMaterialEXT (GLenum face, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexMaterialEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexMaterialEXT = extproc; + + glIndexMaterialEXT(face, mode); +} + +static void APIENTRY InitIndexFuncEXT (GLenum func, GLclampf ref) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexFuncEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexFuncEXT = extproc; + + glIndexFuncEXT(func, ref); +} + +static void APIENTRY InitLockArraysEXT (GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLockArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLockArraysEXT = extproc; + + glLockArraysEXT(first, count); +} + +static void APIENTRY InitUnlockArraysEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnlockArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUnlockArraysEXT = extproc; + + glUnlockArraysEXT(); +} + +static void APIENTRY InitCullParameterdvEXT (GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCullParameterdvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCullParameterdvEXT = extproc; + + glCullParameterdvEXT(pname, params); +} + +static void APIENTRY InitCullParameterfvEXT (GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCullParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCullParameterfvEXT = extproc; + + glCullParameterfvEXT(pname, params); +} + +static void APIENTRY InitFragmentColorMaterialSGIX (GLenum face, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentColorMaterialSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentColorMaterialSGIX = extproc; + + glFragmentColorMaterialSGIX(face, mode); +} + +static void APIENTRY InitFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightfSGIX = extproc; + + glFragmentLightfSGIX(light, pname, param); +} + +static void APIENTRY InitFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightfvSGIX = extproc; + + glFragmentLightfvSGIX(light, pname, params); +} + +static void APIENTRY InitFragmentLightiSGIX (GLenum light, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightiSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightiSGIX = extproc; + + glFragmentLightiSGIX(light, pname, param); +} + +static void APIENTRY InitFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightivSGIX = extproc; + + glFragmentLightivSGIX(light, pname, params); +} + +static void APIENTRY InitFragmentLightModelfSGIX (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModelfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModelfSGIX = extproc; + + glFragmentLightModelfSGIX(pname, param); +} + +static void APIENTRY InitFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModelfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModelfvSGIX = extproc; + + glFragmentLightModelfvSGIX(pname, params); +} + +static void APIENTRY InitFragmentLightModeliSGIX (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModeliSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModeliSGIX = extproc; + + glFragmentLightModeliSGIX(pname, param); +} + +static void APIENTRY InitFragmentLightModelivSGIX (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentLightModelivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentLightModelivSGIX = extproc; + + glFragmentLightModelivSGIX(pname, params); +} + +static void APIENTRY InitFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialfSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialfSGIX = extproc; + + glFragmentMaterialfSGIX(face, pname, param); +} + +static void APIENTRY InitFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialfvSGIX = extproc; + + glFragmentMaterialfvSGIX(face, pname, params); +} + +static void APIENTRY InitFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialiSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialiSGIX = extproc; + + glFragmentMaterialiSGIX(face, pname, param); +} + +static void APIENTRY InitFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFragmentMaterialivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFragmentMaterialivSGIX = extproc; + + glFragmentMaterialivSGIX(face, pname, params); +} + +static void APIENTRY InitGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentLightfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentLightfvSGIX = extproc; + + glGetFragmentLightfvSGIX(light, pname, params); +} + +static void APIENTRY InitGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentLightivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentLightivSGIX = extproc; + + glGetFragmentLightivSGIX(light, pname, params); +} + +static void APIENTRY InitGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentMaterialfvSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentMaterialfvSGIX = extproc; + + glGetFragmentMaterialfvSGIX(face, pname, params); +} + +static void APIENTRY InitGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFragmentMaterialivSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFragmentMaterialivSGIX = extproc; + + glGetFragmentMaterialivSGIX(face, pname, params); +} + +static void APIENTRY InitLightEnviSGIX (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLightEnviSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLightEnviSGIX = extproc; + + glLightEnviSGIX(pname, param); +} + +static void APIENTRY InitDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElementsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElementsEXT = extproc; + + glDrawRangeElementsEXT(mode, start, end, count, type, indices); +} + +static void APIENTRY InitApplyTextureEXT (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glApplyTextureEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glApplyTextureEXT = extproc; + + glApplyTextureEXT(mode); +} + +static void APIENTRY InitTextureLightEXT (GLenum pname) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureLightEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureLightEXT = extproc; + + glTextureLightEXT(pname); +} + +static void APIENTRY InitTextureMaterialEXT (GLenum face, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureMaterialEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureMaterialEXT = extproc; + + glTextureMaterialEXT(face, mode); +} + +static void APIENTRY InitAsyncMarkerSGIX (GLuint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAsyncMarkerSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAsyncMarkerSGIX = extproc; + + glAsyncMarkerSGIX(marker); +} + +static GLint APIENTRY InitFinishAsyncSGIX (GLuint *markerp) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishAsyncSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glFinishAsyncSGIX = extproc; + + return glFinishAsyncSGIX(markerp); +} + +static GLint APIENTRY InitPollAsyncSGIX (GLuint *markerp) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPollAsyncSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glPollAsyncSGIX = extproc; + + return glPollAsyncSGIX(markerp); +} + +static GLuint APIENTRY InitGenAsyncMarkersSGIX (GLsizei range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenAsyncMarkersSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenAsyncMarkersSGIX = extproc; + + return glGenAsyncMarkersSGIX(range); +} + +static void APIENTRY InitDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteAsyncMarkersSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteAsyncMarkersSGIX = extproc; + + glDeleteAsyncMarkersSGIX(marker, range); +} + +static GLboolean APIENTRY InitIsAsyncMarkerSGIX (GLuint marker) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsAsyncMarkerSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsAsyncMarkerSGIX = extproc; + + return glIsAsyncMarkerSGIX(marker); +} + +static void APIENTRY InitVertexPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexPointervINTEL = extproc; + + glVertexPointervINTEL(size, type, pointer); +} + +static void APIENTRY InitNormalPointervINTEL (GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalPointervINTEL = extproc; + + glNormalPointervINTEL(type, pointer); +} + +static void APIENTRY InitColorPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorPointervINTEL = extproc; + + glColorPointervINTEL(size, type, pointer); +} + +static void APIENTRY InitTexCoordPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoordPointervINTEL"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoordPointervINTEL = extproc; + + glTexCoordPointervINTEL(size, type, pointer); +} + +static void APIENTRY InitPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameteriEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameteriEXT = extproc; + + glPixelTransformParameteriEXT(target, pname, param); +} + +static void APIENTRY InitPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameterfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameterfEXT = extproc; + + glPixelTransformParameterfEXT(target, pname, param); +} + +static void APIENTRY InitPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameterivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameterivEXT = extproc; + + glPixelTransformParameterivEXT(target, pname, params); +} + +static void APIENTRY InitPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelTransformParameterfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelTransformParameterfvEXT = extproc; + + glPixelTransformParameterfvEXT(target, pname, params); +} + +static void APIENTRY InitSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3bEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3bEXT = extproc; + + glSecondaryColor3bEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3bvEXT (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3bvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3bvEXT = extproc; + + glSecondaryColor3bvEXT(v); +} + +static void APIENTRY InitSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3dEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3dEXT = extproc; + + glSecondaryColor3dEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3dvEXT (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3dvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3dvEXT = extproc; + + glSecondaryColor3dvEXT(v); +} + +static void APIENTRY InitSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3fEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3fEXT = extproc; + + glSecondaryColor3fEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3fvEXT (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3fvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3fvEXT = extproc; + + glSecondaryColor3fvEXT(v); +} + +static void APIENTRY InitSecondaryColor3iEXT (GLint red, GLint green, GLint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3iEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3iEXT = extproc; + + glSecondaryColor3iEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3ivEXT (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ivEXT = extproc; + + glSecondaryColor3ivEXT(v); +} + +static void APIENTRY InitSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3sEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3sEXT = extproc; + + glSecondaryColor3sEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3svEXT (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3svEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3svEXT = extproc; + + glSecondaryColor3svEXT(v); +} + +static void APIENTRY InitSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ubEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ubEXT = extproc; + + glSecondaryColor3ubEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3ubvEXT (const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3ubvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3ubvEXT = extproc; + + glSecondaryColor3ubvEXT(v); +} + +static void APIENTRY InitSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3uiEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3uiEXT = extproc; + + glSecondaryColor3uiEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3uivEXT (const GLuint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3uivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3uivEXT = extproc; + + glSecondaryColor3uivEXT(v); +} + +static void APIENTRY InitSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3usEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3usEXT = extproc; + + glSecondaryColor3usEXT(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3usvEXT (const GLushort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3usvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3usvEXT = extproc; + + glSecondaryColor3usvEXT(v); +} + +static void APIENTRY InitSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColorPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColorPointerEXT = extproc; + + glSecondaryColorPointerEXT(size, type, stride, pointer); +} + +static void APIENTRY InitTextureNormalEXT (GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureNormalEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureNormalEXT = extproc; + + glTextureNormalEXT(mode); +} + +static void APIENTRY InitMultiDrawArraysEXT (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawArraysEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawArraysEXT = extproc; + + glMultiDrawArraysEXT(mode, first, count, primcount); +} + +static void APIENTRY InitMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawElementsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawElementsEXT = extproc; + + glMultiDrawElementsEXT(mode, count, type, indices, primcount); +} + +static void APIENTRY InitFogCoordfEXT (GLfloat coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordfEXT = extproc; + + glFogCoordfEXT(coord); +} + +static void APIENTRY InitFogCoordfvEXT (const GLfloat *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordfvEXT = extproc; + + glFogCoordfvEXT(coord); +} + +static void APIENTRY InitFogCoorddEXT (GLdouble coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoorddEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoorddEXT = extproc; + + glFogCoorddEXT(coord); +} + +static void APIENTRY InitFogCoorddvEXT (const GLdouble *coord) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoorddvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoorddvEXT = extproc; + + glFogCoorddvEXT(coord); +} + +static void APIENTRY InitFogCoordPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordPointerEXT = extproc; + + glFogCoordPointerEXT(type, stride, pointer); +} + +static void APIENTRY InitTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3bEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3bEXT = extproc; + + glTangent3bEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3bvEXT (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3bvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3bvEXT = extproc; + + glTangent3bvEXT(v); +} + +static void APIENTRY InitTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3dEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3dEXT = extproc; + + glTangent3dEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3dvEXT (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3dvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3dvEXT = extproc; + + glTangent3dvEXT(v); +} + +static void APIENTRY InitTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3fEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3fEXT = extproc; + + glTangent3fEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3fvEXT (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3fvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3fvEXT = extproc; + + glTangent3fvEXT(v); +} + +static void APIENTRY InitTangent3iEXT (GLint tx, GLint ty, GLint tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3iEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3iEXT = extproc; + + glTangent3iEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3ivEXT (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3ivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3ivEXT = extproc; + + glTangent3ivEXT(v); +} + +static void APIENTRY InitTangent3sEXT (GLshort tx, GLshort ty, GLshort tz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3sEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3sEXT = extproc; + + glTangent3sEXT(tx, ty, tz); +} + +static void APIENTRY InitTangent3svEXT (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangent3svEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangent3svEXT = extproc; + + glTangent3svEXT(v); +} + +static void APIENTRY InitBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3bEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3bEXT = extproc; + + glBinormal3bEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3bvEXT (const GLbyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3bvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3bvEXT = extproc; + + glBinormal3bvEXT(v); +} + +static void APIENTRY InitBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3dEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3dEXT = extproc; + + glBinormal3dEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3dvEXT (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3dvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3dvEXT = extproc; + + glBinormal3dvEXT(v); +} + +static void APIENTRY InitBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3fEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3fEXT = extproc; + + glBinormal3fEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3fvEXT (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3fvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3fvEXT = extproc; + + glBinormal3fvEXT(v); +} + +static void APIENTRY InitBinormal3iEXT (GLint bx, GLint by, GLint bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3iEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3iEXT = extproc; + + glBinormal3iEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3ivEXT (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3ivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3ivEXT = extproc; + + glBinormal3ivEXT(v); +} + +static void APIENTRY InitBinormal3sEXT (GLshort bx, GLshort by, GLshort bz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3sEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3sEXT = extproc; + + glBinormal3sEXT(bx, by, bz); +} + +static void APIENTRY InitBinormal3svEXT (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormal3svEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormal3svEXT = extproc; + + glBinormal3svEXT(v); +} + +static void APIENTRY InitTangentPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTangentPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTangentPointerEXT = extproc; + + glTangentPointerEXT(type, stride, pointer); +} + +static void APIENTRY InitBinormalPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBinormalPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBinormalPointerEXT = extproc; + + glBinormalPointerEXT(type, stride, pointer); +} + +static void APIENTRY InitFinishTextureSUNX (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishTextureSUNX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishTextureSUNX = extproc; + + glFinishTextureSUNX(); +} + +static void APIENTRY InitGlobalAlphaFactorbSUN (GLbyte factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorbSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorbSUN = extproc; + + glGlobalAlphaFactorbSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorsSUN (GLshort factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorsSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorsSUN = extproc; + + glGlobalAlphaFactorsSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactoriSUN (GLint factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactoriSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactoriSUN = extproc; + + glGlobalAlphaFactoriSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorfSUN (GLfloat factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorfSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorfSUN = extproc; + + glGlobalAlphaFactorfSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactordSUN (GLdouble factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactordSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactordSUN = extproc; + + glGlobalAlphaFactordSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorubSUN (GLubyte factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorubSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorubSUN = extproc; + + glGlobalAlphaFactorubSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactorusSUN (GLushort factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactorusSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactorusSUN = extproc; + + glGlobalAlphaFactorusSUN(factor); +} + +static void APIENTRY InitGlobalAlphaFactoruiSUN (GLuint factor) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGlobalAlphaFactoruiSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGlobalAlphaFactoruiSUN = extproc; + + glGlobalAlphaFactoruiSUN(factor); +} + +static void APIENTRY InitReplacementCodeuiSUN (GLuint code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiSUN = extproc; + + glReplacementCodeuiSUN(code); +} + +static void APIENTRY InitReplacementCodeusSUN (GLushort code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeusSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeusSUN = extproc; + + glReplacementCodeusSUN(code); +} + +static void APIENTRY InitReplacementCodeubSUN (GLubyte code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeubSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeubSUN = extproc; + + glReplacementCodeubSUN(code); +} + +static void APIENTRY InitReplacementCodeuivSUN (const GLuint *code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuivSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuivSUN = extproc; + + glReplacementCodeuivSUN(code); +} + +static void APIENTRY InitReplacementCodeusvSUN (const GLushort *code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeusvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeusvSUN = extproc; + + glReplacementCodeusvSUN(code); +} + +static void APIENTRY InitReplacementCodeubvSUN (const GLubyte *code) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeubvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeubvSUN = extproc; + + glReplacementCodeubvSUN(code); +} + +static void APIENTRY InitReplacementCodePointerSUN (GLenum type, GLsizei stride, const GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodePointerSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodePointerSUN = extproc; + + glReplacementCodePointerSUN(type, stride, pointer); +} + +static void APIENTRY InitColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex2fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex2fSUN = extproc; + + glColor4ubVertex2fSUN(r, g, b, a, x, y); +} + +static void APIENTRY InitColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex2fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex2fvSUN = extproc; + + glColor4ubVertex2fvSUN(c, v); +} + +static void APIENTRY InitColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex3fSUN = extproc; + + glColor4ubVertex3fSUN(r, g, b, a, x, y, z); +} + +static void APIENTRY InitColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4ubVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4ubVertex3fvSUN = extproc; + + glColor4ubVertex3fvSUN(c, v); +} + +static void APIENTRY InitColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3fVertex3fSUN = extproc; + + glColor3fVertex3fSUN(r, g, b, x, y, z); +} + +static void APIENTRY InitColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3fVertex3fvSUN = extproc; + + glColor3fVertex3fvSUN(c, v); +} + +static void APIENTRY InitNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3fVertex3fSUN = extproc; + + glNormal3fVertex3fSUN(nx, ny, nz, x, y, z); +} + +static void APIENTRY InitNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3fVertex3fvSUN = extproc; + + glNormal3fVertex3fvSUN(n, v); +} + +static void APIENTRY InitColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4fNormal3fVertex3fSUN = extproc; + + glColor4fNormal3fVertex3fSUN(r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4fNormal3fVertex3fvSUN = extproc; + + glColor4fNormal3fVertex3fvSUN(c, n, v); +} + +static void APIENTRY InitTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fVertex3fSUN = extproc; + + glTexCoord2fVertex3fSUN(s, t, x, y, z); +} + +static void APIENTRY InitTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fVertex3fvSUN = extproc; + + glTexCoord2fVertex3fvSUN(tc, v); +} + +static void APIENTRY InitTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fVertex4fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fVertex4fSUN = extproc; + + glTexCoord4fVertex4fSUN(s, t, p, q, x, y, z, w); +} + +static void APIENTRY InitTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fVertex4fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fVertex4fvSUN = extproc; + + glTexCoord4fVertex4fvSUN(tc, v); +} + +static void APIENTRY InitTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4ubVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4ubVertex3fSUN = extproc; + + glTexCoord2fColor4ubVertex3fSUN(s, t, r, g, b, a, x, y, z); +} + +static void APIENTRY InitTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4ubVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4ubVertex3fvSUN = extproc; + + glTexCoord2fColor4ubVertex3fvSUN(tc, c, v); +} + +static void APIENTRY InitTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor3fVertex3fSUN = extproc; + + glTexCoord2fColor3fVertex3fSUN(s, t, r, g, b, x, y, z); +} + +static void APIENTRY InitTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor3fVertex3fvSUN = extproc; + + glTexCoord2fColor3fVertex3fvSUN(tc, c, v); +} + +static void APIENTRY InitTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fNormal3fVertex3fSUN = extproc; + + glTexCoord2fNormal3fVertex3fSUN(s, t, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fNormal3fVertex3fvSUN = extproc; + + glTexCoord2fNormal3fVertex3fvSUN(tc, n, v); +} + +static void APIENTRY InitTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4fNormal3fVertex3fSUN = extproc; + + glTexCoord2fColor4fNormal3fVertex3fSUN(s, t, r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2fColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2fColor4fNormal3fVertex3fvSUN = extproc; + + glTexCoord2fColor4fNormal3fVertex3fvSUN(tc, c, n, v); +} + +static void APIENTRY InitTexCoord4fColor4fNormal3fVertex4fSUN (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) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fColor4fNormal3fVertex4fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fColor4fNormal3fVertex4fSUN = extproc; + + glTexCoord4fColor4fNormal3fVertex4fSUN(s, t, p, q, r, g, b, a, nx, ny, nz, x, y, z, w); +} + +static void APIENTRY InitTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4fColor4fNormal3fVertex4fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4fColor4fNormal3fVertex4fvSUN = extproc; + + glTexCoord4fColor4fNormal3fVertex4fvSUN(tc, c, n, v); +} + +static void APIENTRY InitReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiVertex3fSUN = extproc; + + glReplacementCodeuiVertex3fSUN(rc, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiVertex3fvSUN = extproc; + + glReplacementCodeuiVertex3fvSUN(rc, v); +} + +static void APIENTRY InitReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4ubVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4ubVertex3fSUN = extproc; + + glReplacementCodeuiColor4ubVertex3fSUN(rc, r, g, b, a, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4ubVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4ubVertex3fvSUN = extproc; + + glReplacementCodeuiColor4ubVertex3fvSUN(rc, c, v); +} + +static void APIENTRY InitReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor3fVertex3fSUN = extproc; + + glReplacementCodeuiColor3fVertex3fSUN(rc, r, g, b, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor3fVertex3fvSUN = extproc; + + glReplacementCodeuiColor3fVertex3fvSUN(rc, c, v); +} + +static void APIENTRY InitReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiNormal3fVertex3fSUN(rc, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiNormal3fVertex3fvSUN(rc, n, v); +} + +static void APIENTRY InitReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4fNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiColor4fNormal3fVertex3fSUN(rc, r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiColor4fNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiColor4fNormal3fVertex3fvSUN(rc, c, n, v); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fVertex3fSUN = extproc; + + glReplacementCodeuiTexCoord2fVertex3fSUN(rc, s, t, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fVertex3fvSUN = extproc; + + glReplacementCodeuiTexCoord2fVertex3fvSUN(rc, tc, v); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN(rc, s, t, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN(rc, tc, n, v); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (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) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN = extproc; + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN(rc, s, t, r, g, b, a, nx, ny, nz, x, y, z); +} + +static void APIENTRY InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN = extproc; + + glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN(rc, tc, c, n, v); +} + +static void APIENTRY InitBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendFuncSeparateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendFuncSeparateEXT = extproc; + + glBlendFuncSeparateEXT(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +} + +static void APIENTRY InitBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendFuncSeparateINGR"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendFuncSeparateINGR = extproc; + + glBlendFuncSeparateINGR(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +} + +static void APIENTRY InitVertexWeightfEXT (GLfloat weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeightfEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeightfEXT = extproc; + + glVertexWeightfEXT(weight); +} + +static void APIENTRY InitVertexWeightfvEXT (const GLfloat *weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeightfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeightfvEXT = extproc; + + glVertexWeightfvEXT(weight); +} + +static void APIENTRY InitVertexWeightPointerEXT (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeightPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeightPointerEXT = extproc; + + glVertexWeightPointerEXT(size, type, stride, pointer); +} + +static void APIENTRY InitFlushVertexArrayRangeNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushVertexArrayRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushVertexArrayRangeNV = extproc; + + glFlushVertexArrayRangeNV(); +} + +static void APIENTRY InitVertexArrayRangeNV (GLsizei length, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexArrayRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexArrayRangeNV = extproc; + + glVertexArrayRangeNV(length, pointer); +} + +static void APIENTRY InitCombinerParameterfvNV (GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameterfvNV = extproc; + + glCombinerParameterfvNV(pname, params); +} + +static void APIENTRY InitCombinerParameterfNV (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameterfNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameterfNV = extproc; + + glCombinerParameterfNV(pname, param); +} + +static void APIENTRY InitCombinerParameterivNV (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameterivNV = extproc; + + glCombinerParameterivNV(pname, params); +} + +static void APIENTRY InitCombinerParameteriNV (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerParameteriNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerParameteriNV = extproc; + + glCombinerParameteriNV(pname, param); +} + +static void APIENTRY InitCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerInputNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerInputNV = extproc; + + glCombinerInputNV(stage, portion, variable, input, mapping, componentUsage); +} + +static void APIENTRY InitCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerOutputNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerOutputNV = extproc; + + glCombinerOutputNV(stage, portion, abOutput, cdOutput, sumOutput, scale, bias, abDotProduct, cdDotProduct, muxSum); +} + +static void APIENTRY InitFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinalCombinerInputNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinalCombinerInputNV = extproc; + + glFinalCombinerInputNV(variable, input, mapping, componentUsage); +} + +static void APIENTRY InitGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerInputParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerInputParameterfvNV = extproc; + + glGetCombinerInputParameterfvNV(stage, portion, variable, pname, params); +} + +static void APIENTRY InitGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerInputParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerInputParameterivNV = extproc; + + glGetCombinerInputParameterivNV(stage, portion, variable, pname, params); +} + +static void APIENTRY InitGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerOutputParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerOutputParameterfvNV = extproc; + + glGetCombinerOutputParameterfvNV(stage, portion, pname, params); +} + +static void APIENTRY InitGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerOutputParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerOutputParameterivNV = extproc; + + glGetCombinerOutputParameterivNV(stage, portion, pname, params); +} + +static void APIENTRY InitGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFinalCombinerInputParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFinalCombinerInputParameterfvNV = extproc; + + glGetFinalCombinerInputParameterfvNV(variable, pname, params); +} + +static void APIENTRY InitGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFinalCombinerInputParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFinalCombinerInputParameterivNV = extproc; + + glGetFinalCombinerInputParameterivNV(variable, pname, params); +} + +static void APIENTRY InitResizeBuffersMESA (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glResizeBuffersMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glResizeBuffersMESA = extproc; + + glResizeBuffersMESA(); +} + +static void APIENTRY InitWindowPos2dMESA (GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dMESA = extproc; + + glWindowPos2dMESA(x, y); +} + +static void APIENTRY InitWindowPos2dvMESA (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2dvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2dvMESA = extproc; + + glWindowPos2dvMESA(v); +} + +static void APIENTRY InitWindowPos2fMESA (GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fMESA = extproc; + + glWindowPos2fMESA(x, y); +} + +static void APIENTRY InitWindowPos2fvMESA (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2fvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2fvMESA = extproc; + + glWindowPos2fvMESA(v); +} + +static void APIENTRY InitWindowPos2iMESA (GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2iMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2iMESA = extproc; + + glWindowPos2iMESA(x, y); +} + +static void APIENTRY InitWindowPos2ivMESA (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2ivMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2ivMESA = extproc; + + glWindowPos2ivMESA(v); +} + +static void APIENTRY InitWindowPos2sMESA (GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2sMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2sMESA = extproc; + + glWindowPos2sMESA(x, y); +} + +static void APIENTRY InitWindowPos2svMESA (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos2svMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos2svMESA = extproc; + + glWindowPos2svMESA(v); +} + +static void APIENTRY InitWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dMESA = extproc; + + glWindowPos3dMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3dvMESA (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3dvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3dvMESA = extproc; + + glWindowPos3dvMESA(v); +} + +static void APIENTRY InitWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fMESA = extproc; + + glWindowPos3fMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3fvMESA (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3fvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3fvMESA = extproc; + + glWindowPos3fvMESA(v); +} + +static void APIENTRY InitWindowPos3iMESA (GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3iMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3iMESA = extproc; + + glWindowPos3iMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3ivMESA (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3ivMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3ivMESA = extproc; + + glWindowPos3ivMESA(v); +} + +static void APIENTRY InitWindowPos3sMESA (GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3sMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3sMESA = extproc; + + glWindowPos3sMESA(x, y, z); +} + +static void APIENTRY InitWindowPos3svMESA (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos3svMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos3svMESA = extproc; + + glWindowPos3svMESA(v); +} + +static void APIENTRY InitWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4dMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4dMESA = extproc; + + glWindowPos4dMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4dvMESA (const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4dvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4dvMESA = extproc; + + glWindowPos4dvMESA(v); +} + +static void APIENTRY InitWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4fMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4fMESA = extproc; + + glWindowPos4fMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4fvMESA (const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4fvMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4fvMESA = extproc; + + glWindowPos4fvMESA(v); +} + +static void APIENTRY InitWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4iMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4iMESA = extproc; + + glWindowPos4iMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4ivMESA (const GLint *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4ivMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4ivMESA = extproc; + + glWindowPos4ivMESA(v); +} + +static void APIENTRY InitWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4sMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4sMESA = extproc; + + glWindowPos4sMESA(x, y, z, w); +} + +static void APIENTRY InitWindowPos4svMESA (const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWindowPos4svMESA"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWindowPos4svMESA = extproc; + + glWindowPos4svMESA(v); +} + +static void APIENTRY InitMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiModeDrawArraysIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiModeDrawArraysIBM = extproc; + + glMultiModeDrawArraysIBM(mode, first, count, primcount, modestride); +} + +static void APIENTRY InitMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiModeDrawElementsIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiModeDrawElementsIBM = extproc; + + glMultiModeDrawElementsIBM(mode, count, type, indices, primcount, modestride); +} + +static void APIENTRY InitColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorPointerListIBM = extproc; + + glColorPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColorPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColorPointerListIBM = extproc; + + glSecondaryColorPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitEdgeFlagPointerListIBM (GLint stride, const GLboolean* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEdgeFlagPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEdgeFlagPointerListIBM = extproc; + + glEdgeFlagPointerListIBM(stride, pointer, ptrstride); +} + +static void APIENTRY InitFogCoordPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordPointerListIBM = extproc; + + glFogCoordPointerListIBM(type, stride, pointer, ptrstride); +} + +static void APIENTRY InitIndexPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIndexPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIndexPointerListIBM = extproc; + + glIndexPointerListIBM(type, stride, pointer, ptrstride); +} + +static void APIENTRY InitNormalPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalPointerListIBM = extproc; + + glNormalPointerListIBM(type, stride, pointer, ptrstride); +} + +static void APIENTRY InitTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoordPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoordPointerListIBM = extproc; + + glTexCoordPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitVertexPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexPointerListIBM"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexPointerListIBM = extproc; + + glVertexPointerListIBM(size, type, stride, pointer, ptrstride); +} + +static void APIENTRY InitTbufferMask3DFX (GLuint mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTbufferMask3DFX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTbufferMask3DFX = extproc; + + glTbufferMask3DFX(mask); +} + +static void APIENTRY InitSampleMaskEXT (GLclampf value, GLboolean invert) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleMaskEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleMaskEXT = extproc; + + glSampleMaskEXT(value, invert); +} + +static void APIENTRY InitSamplePatternEXT (GLenum pattern) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSamplePatternEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSamplePatternEXT = extproc; + + glSamplePatternEXT(pattern); +} + +static void APIENTRY InitTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTextureColorMaskSGIS"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTextureColorMaskSGIS = extproc; + + glTextureColorMaskSGIS(red, green, blue, alpha); +} + +static void APIENTRY InitIglooInterfaceSGIX (GLenum pname, const GLvoid *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIglooInterfaceSGIX"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glIglooInterfaceSGIX = extproc; + + glIglooInterfaceSGIX(pname, params); +} + +static void APIENTRY InitDeleteFencesNV (GLsizei n, const GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteFencesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteFencesNV = extproc; + + glDeleteFencesNV(n, fences); +} + +static void APIENTRY InitGenFencesNV (GLsizei n, GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenFencesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenFencesNV = extproc; + + glGenFencesNV(n, fences); +} + +static GLboolean APIENTRY InitIsFenceNV (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsFenceNV = extproc; + + return glIsFenceNV(fence); +} + +static GLboolean APIENTRY InitTestFenceNV (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTestFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glTestFenceNV = extproc; + + return glTestFenceNV(fence); +} + +static void APIENTRY InitGetFenceivNV (GLuint fence, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetFenceivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetFenceivNV = extproc; + + glGetFenceivNV(fence, pname, params); +} + +static void APIENTRY InitFinishFenceNV (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishFenceNV = extproc; + + glFinishFenceNV(fence); +} + +static void APIENTRY InitSetFenceNV (GLuint fence, GLenum condition) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetFenceNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetFenceNV = extproc; + + glSetFenceNV(fence, condition); +} + +static void APIENTRY InitMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapControlPointsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMapControlPointsNV = extproc; + + glMapControlPointsNV(target, index, type, ustride, vstride, uorder, vorder, packed, points); +} + +static void APIENTRY InitMapParameterivNV (GLenum target, GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMapParameterivNV = extproc; + + glMapParameterivNV(target, pname, params); +} + +static void APIENTRY InitMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMapParameterfvNV = extproc; + + glMapParameterfvNV(target, pname, params); +} + +static void APIENTRY InitGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapControlPointsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapControlPointsNV = extproc; + + glGetMapControlPointsNV(target, index, type, ustride, vstride, packed, points); +} + +static void APIENTRY InitGetMapParameterivNV (GLenum target, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapParameterivNV = extproc; + + glGetMapParameterivNV(target, pname, params); +} + +static void APIENTRY InitGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapParameterfvNV = extproc; + + glGetMapParameterfvNV(target, pname, params); +} + +static void APIENTRY InitGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapAttribParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapAttribParameterivNV = extproc; + + glGetMapAttribParameterivNV(target, index, pname, params); +} + +static void APIENTRY InitGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetMapAttribParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetMapAttribParameterfvNV = extproc; + + glGetMapAttribParameterfvNV(target, index, pname, params); +} + +static void APIENTRY InitEvalMapsNV (GLenum target, GLenum mode) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEvalMapsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEvalMapsNV = extproc; + + glEvalMapsNV(target, mode); +} + +static void APIENTRY InitCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glCombinerStageParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glCombinerStageParameterfvNV = extproc; + + glCombinerStageParameterfvNV(stage, pname, params); +} + +static void APIENTRY InitGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetCombinerStageParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetCombinerStageParameterfvNV = extproc; + + glGetCombinerStageParameterfvNV(stage, pname, params); +} + +static GLboolean APIENTRY InitAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAreProgramsResidentNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glAreProgramsResidentNV = extproc; + + return glAreProgramsResidentNV(n, programs, residences); +} + +static void APIENTRY InitBindProgramNV (GLenum target, GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindProgramNV = extproc; + + glBindProgramNV(target, id); +} + +static void APIENTRY InitDeleteProgramsNV (GLsizei n, const GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteProgramsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteProgramsNV = extproc; + + glDeleteProgramsNV(n, programs); +} + +static void APIENTRY InitExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glExecuteProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glExecuteProgramNV = extproc; + + glExecuteProgramNV(target, id, params); +} + +static void APIENTRY InitGenProgramsNV (GLsizei n, GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenProgramsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenProgramsNV = extproc; + + glGenProgramsNV(n, programs); +} + +static void APIENTRY InitGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramParameterdvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramParameterdvNV = extproc; + + glGetProgramParameterdvNV(target, index, pname, params); +} + +static void APIENTRY InitGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramParameterfvNV = extproc; + + glGetProgramParameterfvNV(target, index, pname, params); +} + +static void APIENTRY InitGetProgramivNV (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramivNV = extproc; + + glGetProgramivNV(id, pname, params); +} + +static void APIENTRY InitGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramStringNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramStringNV = extproc; + + glGetProgramStringNV(id, pname, program); +} + +static void APIENTRY InitGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTrackMatrixivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTrackMatrixivNV = extproc; + + glGetTrackMatrixivNV(target, address, pname, params); +} + +static void APIENTRY InitGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribdvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribdvNV = extproc; + + glGetVertexAttribdvNV(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribfvNV = extproc; + + glGetVertexAttribfvNV(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribivNV = extproc; + + glGetVertexAttribivNV(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribPointervNV (GLuint index, GLenum pname, GLvoid* *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribPointervNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribPointervNV = extproc; + + glGetVertexAttribPointervNV(index, pname, pointer); +} + +static GLboolean APIENTRY InitIsProgramNV (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsProgramNV = extproc; + + return glIsProgramNV(id); +} + +static void APIENTRY InitLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glLoadProgramNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glLoadProgramNV = extproc; + + glLoadProgramNV(target, id, len, program); +} + +static void APIENTRY InitProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4dNV = extproc; + + glProgramParameter4dNV(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4dvNV = extproc; + + glProgramParameter4dvNV(target, index, v); +} + +static void APIENTRY InitProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4fNV = extproc; + + glProgramParameter4fNV(target, index, x, y, z, w); +} + +static void APIENTRY InitProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameter4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameter4fvNV = extproc; + + glProgramParameter4fvNV(target, index, v); +} + +static void APIENTRY InitProgramParameters4dvNV (GLenum target, GLuint index, GLuint count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameters4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameters4dvNV = extproc; + + glProgramParameters4dvNV(target, index, count, v); +} + +static void APIENTRY InitProgramParameters4fvNV (GLenum target, GLuint index, GLuint count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramParameters4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramParameters4fvNV = extproc; + + glProgramParameters4fvNV(target, index, count, v); +} + +static void APIENTRY InitRequestResidentProgramsNV (GLsizei n, const GLuint *programs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glRequestResidentProgramsNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glRequestResidentProgramsNV = extproc; + + glRequestResidentProgramsNV(n, programs); +} + +static void APIENTRY InitTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTrackMatrixNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTrackMatrixNV = extproc; + + glTrackMatrixNV(target, address, matrix, transform); +} + +static void APIENTRY InitVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribPointerNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribPointerNV = extproc; + + glVertexAttribPointerNV(index, fsize, type, stride, pointer); +} + +static void APIENTRY InitVertexAttrib1dNV (GLuint index, GLdouble x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dNV = extproc; + + glVertexAttrib1dNV(index, x); +} + +static void APIENTRY InitVertexAttrib1dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1dvNV = extproc; + + glVertexAttrib1dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib1fNV (GLuint index, GLfloat x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fNV = extproc; + + glVertexAttrib1fNV(index, x); +} + +static void APIENTRY InitVertexAttrib1fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1fvNV = extproc; + + glVertexAttrib1fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib1sNV (GLuint index, GLshort x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1sNV = extproc; + + glVertexAttrib1sNV(index, x); +} + +static void APIENTRY InitVertexAttrib1svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1svNV = extproc; + + glVertexAttrib1svNV(index, v); +} + +static void APIENTRY InitVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dNV = extproc; + + glVertexAttrib2dNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2dvNV = extproc; + + glVertexAttrib2dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fNV = extproc; + + glVertexAttrib2fNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2fvNV = extproc; + + glVertexAttrib2fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib2sNV (GLuint index, GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2sNV = extproc; + + glVertexAttrib2sNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2svNV = extproc; + + glVertexAttrib2svNV(index, v); +} + +static void APIENTRY InitVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dNV = extproc; + + glVertexAttrib3dNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3dvNV = extproc; + + glVertexAttrib3dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fNV = extproc; + + glVertexAttrib3fNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3fvNV = extproc; + + glVertexAttrib3fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3sNV = extproc; + + glVertexAttrib3sNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3svNV = extproc; + + glVertexAttrib3svNV(index, v); +} + +static void APIENTRY InitVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dNV = extproc; + + glVertexAttrib4dNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4dvNV (GLuint index, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4dvNV = extproc; + + glVertexAttrib4dvNV(index, v); +} + +static void APIENTRY InitVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fNV = extproc; + + glVertexAttrib4fNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4fvNV (GLuint index, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4fvNV = extproc; + + glVertexAttrib4fvNV(index, v); +} + +static void APIENTRY InitVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4sNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4sNV = extproc; + + glVertexAttrib4sNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4svNV (GLuint index, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4svNV = extproc; + + glVertexAttrib4svNV(index, v); +} + +static void APIENTRY InitVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ubNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ubNV = extproc; + + glVertexAttrib4ubNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4ubvNV (GLuint index, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4ubvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4ubvNV = extproc; + + glVertexAttrib4ubvNV(index, v); +} + +static void APIENTRY InitVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1dvNV = extproc; + + glVertexAttribs1dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1fvNV = extproc; + + glVertexAttribs1fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1svNV = extproc; + + glVertexAttribs1svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2dvNV = extproc; + + glVertexAttribs2dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2fvNV = extproc; + + glVertexAttribs2fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2svNV = extproc; + + glVertexAttribs2svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3dvNV = extproc; + + glVertexAttribs3dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3fvNV = extproc; + + glVertexAttribs3fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3svNV = extproc; + + glVertexAttribs3svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4dvNV = extproc; + + glVertexAttribs4dvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4fvNV = extproc; + + glVertexAttribs4fvNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4svNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4svNV = extproc; + + glVertexAttribs4svNV(index, count, v); +} + +static void APIENTRY InitVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4ubvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4ubvNV = extproc; + + glVertexAttribs4ubvNV(index, count, v); +} + +static void APIENTRY InitTexBumpParameterivATI (GLenum pname, const GLint *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexBumpParameterivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexBumpParameterivATI = extproc; + + glTexBumpParameterivATI(pname, param); +} + +static void APIENTRY InitTexBumpParameterfvATI (GLenum pname, const GLfloat *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexBumpParameterfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexBumpParameterfvATI = extproc; + + glTexBumpParameterfvATI(pname, param); +} + +static void APIENTRY InitGetTexBumpParameterivATI (GLenum pname, GLint *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTexBumpParameterivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTexBumpParameterivATI = extproc; + + glGetTexBumpParameterivATI(pname, param); +} + +static void APIENTRY InitGetTexBumpParameterfvATI (GLenum pname, GLfloat *param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetTexBumpParameterfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetTexBumpParameterfvATI = extproc; + + glGetTexBumpParameterfvATI(pname, param); +} + +static GLuint APIENTRY InitGenFragmentShadersATI (GLuint range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenFragmentShadersATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenFragmentShadersATI = extproc; + + return glGenFragmentShadersATI(range); +} + +static void APIENTRY InitBindFragmentShaderATI (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindFragmentShaderATI = extproc; + + glBindFragmentShaderATI(id); +} + +static void APIENTRY InitDeleteFragmentShaderATI (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteFragmentShaderATI = extproc; + + glDeleteFragmentShaderATI(id); +} + +static void APIENTRY InitBeginFragmentShaderATI (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginFragmentShaderATI = extproc; + + glBeginFragmentShaderATI(); +} + +static void APIENTRY InitEndFragmentShaderATI (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndFragmentShaderATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndFragmentShaderATI = extproc; + + glEndFragmentShaderATI(); +} + +static void APIENTRY InitPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPassTexCoordATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPassTexCoordATI = extproc; + + glPassTexCoordATI(dst, coord, swizzle); +} + +static void APIENTRY InitSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSampleMapATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSampleMapATI = extproc; + + glSampleMapATI(dst, interp, swizzle); +} + +static void APIENTRY InitColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorFragmentOp1ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorFragmentOp1ATI = extproc; + + glColorFragmentOp1ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod); +} + +static void APIENTRY InitColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorFragmentOp2ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorFragmentOp2ATI = extproc; + + glColorFragmentOp2ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod); +} + +static void APIENTRY InitColorFragmentOp3ATI (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) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColorFragmentOp3ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColorFragmentOp3ATI = extproc; + + glColorFragmentOp3ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod); +} + +static void APIENTRY InitAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAlphaFragmentOp1ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAlphaFragmentOp1ATI = extproc; + + glAlphaFragmentOp1ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod); +} + +static void APIENTRY InitAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAlphaFragmentOp2ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAlphaFragmentOp2ATI = extproc; + + glAlphaFragmentOp2ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod); +} + +static void APIENTRY InitAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAlphaFragmentOp3ATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAlphaFragmentOp3ATI = extproc; + + glAlphaFragmentOp3ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod); +} + +static void APIENTRY InitSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetFragmentShaderConstantATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetFragmentShaderConstantATI = extproc; + + glSetFragmentShaderConstantATI(dst, value); +} + +static void APIENTRY InitPNTrianglesiATI (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPNTrianglesiATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPNTrianglesiATI = extproc; + + glPNTrianglesiATI(pname, param); +} + +static void APIENTRY InitPNTrianglesfATI (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPNTrianglesfATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPNTrianglesfATI = extproc; + + glPNTrianglesfATI(pname, param); +} + +static GLuint APIENTRY InitNewObjectBufferATI (GLsizei size, const GLvoid *pointer, GLenum usage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNewObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glNewObjectBufferATI = extproc; + + return glNewObjectBufferATI(size, pointer, usage); +} + +static GLboolean APIENTRY InitIsObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsObjectBufferATI = extproc; + + return glIsObjectBufferATI(buffer); +} + +static void APIENTRY InitUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUpdateObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUpdateObjectBufferATI = extproc; + + glUpdateObjectBufferATI(buffer, offset, size, pointer, preserve); +} + +static void APIENTRY InitGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectBufferfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectBufferfvATI = extproc; + + glGetObjectBufferfvATI(buffer, pname, params); +} + +static void APIENTRY InitGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetObjectBufferivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetObjectBufferivATI = extproc; + + glGetObjectBufferivATI(buffer, pname, params); +} + +static void APIENTRY InitFreeObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFreeObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFreeObjectBufferATI = extproc; + + glFreeObjectBufferATI(buffer); +} + +static void APIENTRY InitArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glArrayObjectATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glArrayObjectATI = extproc; + + glArrayObjectATI(array, size, type, stride, buffer, offset); +} + +static void APIENTRY InitGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetArrayObjectfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetArrayObjectfvATI = extproc; + + glGetArrayObjectfvATI(array, pname, params); +} + +static void APIENTRY InitGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetArrayObjectivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetArrayObjectivATI = extproc; + + glGetArrayObjectivATI(array, pname, params); +} + +static void APIENTRY InitVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantArrayObjectATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantArrayObjectATI = extproc; + + glVariantArrayObjectATI(id, type, stride, buffer, offset); +} + +static void APIENTRY InitGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantArrayObjectfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantArrayObjectfvATI = extproc; + + glGetVariantArrayObjectfvATI(id, pname, params); +} + +static void APIENTRY InitGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantArrayObjectivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantArrayObjectivATI = extproc; + + glGetVariantArrayObjectivATI(id, pname, params); +} + +static void APIENTRY InitBeginVertexShaderEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginVertexShaderEXT = extproc; + + glBeginVertexShaderEXT(); +} + +static void APIENTRY InitEndVertexShaderEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndVertexShaderEXT = extproc; + + glEndVertexShaderEXT(); +} + +static void APIENTRY InitBindVertexShaderEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindVertexShaderEXT = extproc; + + glBindVertexShaderEXT(id); +} + +static GLuint APIENTRY InitGenVertexShadersEXT (GLuint range) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenVertexShadersEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenVertexShadersEXT = extproc; + + return glGenVertexShadersEXT(range); +} + +static void APIENTRY InitDeleteVertexShaderEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteVertexShaderEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteVertexShaderEXT = extproc; + + glDeleteVertexShaderEXT(id); +} + +static void APIENTRY InitShaderOp1EXT (GLenum op, GLuint res, GLuint arg1) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderOp1EXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderOp1EXT = extproc; + + glShaderOp1EXT(op, res, arg1); +} + +static void APIENTRY InitShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderOp2EXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderOp2EXT = extproc; + + glShaderOp2EXT(op, res, arg1, arg2); +} + +static void APIENTRY InitShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glShaderOp3EXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glShaderOp3EXT = extproc; + + glShaderOp3EXT(op, res, arg1, arg2, arg3); +} + +static void APIENTRY InitSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSwizzleEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSwizzleEXT = extproc; + + glSwizzleEXT(res, in, outX, outY, outZ, outW); +} + +static void APIENTRY InitWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glWriteMaskEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glWriteMaskEXT = extproc; + + glWriteMaskEXT(res, in, outX, outY, outZ, outW); +} + +static void APIENTRY InitInsertComponentEXT (GLuint res, GLuint src, GLuint num) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glInsertComponentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glInsertComponentEXT = extproc; + + glInsertComponentEXT(res, src, num); +} + +static void APIENTRY InitExtractComponentEXT (GLuint res, GLuint src, GLuint num) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glExtractComponentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glExtractComponentEXT = extproc; + + glExtractComponentEXT(res, src, num); +} + +static GLuint APIENTRY InitGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenSymbolsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glGenSymbolsEXT = extproc; + + return glGenSymbolsEXT(datatype, storagetype, range, components); +} + +static void APIENTRY InitSetInvariantEXT (GLuint id, GLenum type, const GLvoid *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetInvariantEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetInvariantEXT = extproc; + + glSetInvariantEXT(id, type, addr); +} + +static void APIENTRY InitSetLocalConstantEXT (GLuint id, GLenum type, const GLvoid *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetLocalConstantEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetLocalConstantEXT = extproc; + + glSetLocalConstantEXT(id, type, addr); +} + +static void APIENTRY InitVariantbvEXT (GLuint id, const GLbyte *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantbvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantbvEXT = extproc; + + glVariantbvEXT(id, addr); +} + +static void APIENTRY InitVariantsvEXT (GLuint id, const GLshort *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantsvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantsvEXT = extproc; + + glVariantsvEXT(id, addr); +} + +static void APIENTRY InitVariantivEXT (GLuint id, const GLint *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantivEXT = extproc; + + glVariantivEXT(id, addr); +} + +static void APIENTRY InitVariantfvEXT (GLuint id, const GLfloat *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantfvEXT = extproc; + + glVariantfvEXT(id, addr); +} + +static void APIENTRY InitVariantdvEXT (GLuint id, const GLdouble *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantdvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantdvEXT = extproc; + + glVariantdvEXT(id, addr); +} + +static void APIENTRY InitVariantubvEXT (GLuint id, const GLubyte *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantubvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantubvEXT = extproc; + + glVariantubvEXT(id, addr); +} + +static void APIENTRY InitVariantusvEXT (GLuint id, const GLushort *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantusvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantusvEXT = extproc; + + glVariantusvEXT(id, addr); +} + +static void APIENTRY InitVariantuivEXT (GLuint id, const GLuint *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantuivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantuivEXT = extproc; + + glVariantuivEXT(id, addr); +} + +static void APIENTRY InitVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const GLvoid *addr) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVariantPointerEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVariantPointerEXT = extproc; + + glVariantPointerEXT(id, type, stride, addr); +} + +static void APIENTRY InitEnableVariantClientStateEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEnableVariantClientStateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEnableVariantClientStateEXT = extproc; + + glEnableVariantClientStateEXT(id); +} + +static void APIENTRY InitDisableVariantClientStateEXT (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDisableVariantClientStateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDisableVariantClientStateEXT = extproc; + + glDisableVariantClientStateEXT(id); +} + +static GLuint APIENTRY InitBindLightParameterEXT (GLenum light, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindLightParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindLightParameterEXT = extproc; + + return glBindLightParameterEXT(light, value); +} + +static GLuint APIENTRY InitBindMaterialParameterEXT (GLenum face, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindMaterialParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindMaterialParameterEXT = extproc; + + return glBindMaterialParameterEXT(face, value); +} + +static GLuint APIENTRY InitBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindTexGenParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindTexGenParameterEXT = extproc; + + return glBindTexGenParameterEXT(unit, coord, value); +} + +static GLuint APIENTRY InitBindTextureUnitParameterEXT (GLenum unit, GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindTextureUnitParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindTextureUnitParameterEXT = extproc; + + return glBindTextureUnitParameterEXT(unit, value); +} + +static GLuint APIENTRY InitBindParameterEXT (GLenum value) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindParameterEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glBindParameterEXT = extproc; + + return glBindParameterEXT(value); +} + +static GLboolean APIENTRY InitIsVariantEnabledEXT (GLuint id, GLenum cap) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsVariantEnabledEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsVariantEnabledEXT = extproc; + + return glIsVariantEnabledEXT(id, cap); +} + +static void APIENTRY InitGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantBooleanvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantBooleanvEXT = extproc; + + glGetVariantBooleanvEXT(id, value, data); +} + +static void APIENTRY InitGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantIntegervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantIntegervEXT = extproc; + + glGetVariantIntegervEXT(id, value, data); +} + +static void APIENTRY InitGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantFloatvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantFloatvEXT = extproc; + + glGetVariantFloatvEXT(id, value, data); +} + +static void APIENTRY InitGetVariantPointervEXT (GLuint id, GLenum value, GLvoid* *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVariantPointervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVariantPointervEXT = extproc; + + glGetVariantPointervEXT(id, value, data); +} + +static void APIENTRY InitGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInvariantBooleanvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInvariantBooleanvEXT = extproc; + + glGetInvariantBooleanvEXT(id, value, data); +} + +static void APIENTRY InitGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInvariantIntegervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInvariantIntegervEXT = extproc; + + glGetInvariantIntegervEXT(id, value, data); +} + +static void APIENTRY InitGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetInvariantFloatvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetInvariantFloatvEXT = extproc; + + glGetInvariantFloatvEXT(id, value, data); +} + +static void APIENTRY InitGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetLocalConstantBooleanvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetLocalConstantBooleanvEXT = extproc; + + glGetLocalConstantBooleanvEXT(id, value, data); +} + +static void APIENTRY InitGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetLocalConstantIntegervEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetLocalConstantIntegervEXT = extproc; + + glGetLocalConstantIntegervEXT(id, value, data); +} + +static void APIENTRY InitGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetLocalConstantFloatvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetLocalConstantFloatvEXT = extproc; + + glGetLocalConstantFloatvEXT(id, value, data); +} + +static void APIENTRY InitVertexStream1sATI (GLenum stream, GLshort x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1sATI = extproc; + + glVertexStream1sATI(stream, x); +} + +static void APIENTRY InitVertexStream1svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1svATI = extproc; + + glVertexStream1svATI(stream, coords); +} + +static void APIENTRY InitVertexStream1iATI (GLenum stream, GLint x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1iATI = extproc; + + glVertexStream1iATI(stream, x); +} + +static void APIENTRY InitVertexStream1ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1ivATI = extproc; + + glVertexStream1ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream1fATI (GLenum stream, GLfloat x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1fATI = extproc; + + glVertexStream1fATI(stream, x); +} + +static void APIENTRY InitVertexStream1fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1fvATI = extproc; + + glVertexStream1fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream1dATI (GLenum stream, GLdouble x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1dATI = extproc; + + glVertexStream1dATI(stream, x); +} + +static void APIENTRY InitVertexStream1dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream1dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream1dvATI = extproc; + + glVertexStream1dvATI(stream, coords); +} + +static void APIENTRY InitVertexStream2sATI (GLenum stream, GLshort x, GLshort y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2sATI = extproc; + + glVertexStream2sATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2svATI = extproc; + + glVertexStream2svATI(stream, coords); +} + +static void APIENTRY InitVertexStream2iATI (GLenum stream, GLint x, GLint y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2iATI = extproc; + + glVertexStream2iATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2ivATI = extproc; + + glVertexStream2ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2fATI = extproc; + + glVertexStream2fATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2fvATI = extproc; + + glVertexStream2fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2dATI = extproc; + + glVertexStream2dATI(stream, x, y); +} + +static void APIENTRY InitVertexStream2dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream2dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream2dvATI = extproc; + + glVertexStream2dvATI(stream, coords); +} + +static void APIENTRY InitVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3sATI = extproc; + + glVertexStream3sATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3svATI = extproc; + + glVertexStream3svATI(stream, coords); +} + +static void APIENTRY InitVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3iATI = extproc; + + glVertexStream3iATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3ivATI = extproc; + + glVertexStream3ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3fATI = extproc; + + glVertexStream3fATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3fvATI = extproc; + + glVertexStream3fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3dATI = extproc; + + glVertexStream3dATI(stream, x, y, z); +} + +static void APIENTRY InitVertexStream3dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream3dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream3dvATI = extproc; + + glVertexStream3dvATI(stream, coords); +} + +static void APIENTRY InitVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4sATI = extproc; + + glVertexStream4sATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4svATI = extproc; + + glVertexStream4svATI(stream, coords); +} + +static void APIENTRY InitVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4iATI = extproc; + + glVertexStream4iATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4ivATI = extproc; + + glVertexStream4ivATI(stream, coords); +} + +static void APIENTRY InitVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4fATI = extproc; + + glVertexStream4fATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4fvATI = extproc; + + glVertexStream4fvATI(stream, coords); +} + +static void APIENTRY InitVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4dATI = extproc; + + glVertexStream4dATI(stream, x, y, z, w); +} + +static void APIENTRY InitVertexStream4dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexStream4dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexStream4dvATI = extproc; + + glVertexStream4dvATI(stream, coords); +} + +static void APIENTRY InitNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3bATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3bATI = extproc; + + glNormalStream3bATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3bvATI (GLenum stream, const GLbyte *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3bvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3bvATI = extproc; + + glNormalStream3bvATI(stream, coords); +} + +static void APIENTRY InitNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3sATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3sATI = extproc; + + glNormalStream3sATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3svATI (GLenum stream, const GLshort *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3svATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3svATI = extproc; + + glNormalStream3svATI(stream, coords); +} + +static void APIENTRY InitNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3iATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3iATI = extproc; + + glNormalStream3iATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3ivATI (GLenum stream, const GLint *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3ivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3ivATI = extproc; + + glNormalStream3ivATI(stream, coords); +} + +static void APIENTRY InitNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3fATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3fATI = extproc; + + glNormalStream3fATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3fvATI (GLenum stream, const GLfloat *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3fvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3fvATI = extproc; + + glNormalStream3fvATI(stream, coords); +} + +static void APIENTRY InitNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3dATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3dATI = extproc; + + glNormalStream3dATI(stream, nx, ny, nz); +} + +static void APIENTRY InitNormalStream3dvATI (GLenum stream, const GLdouble *coords) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormalStream3dvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormalStream3dvATI = extproc; + + glNormalStream3dvATI(stream, coords); +} + +static void APIENTRY InitClientActiveVertexStreamATI (GLenum stream) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glClientActiveVertexStreamATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glClientActiveVertexStreamATI = extproc; + + glClientActiveVertexStreamATI(stream); +} + +static void APIENTRY InitVertexBlendEnviATI (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexBlendEnviATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexBlendEnviATI = extproc; + + glVertexBlendEnviATI(pname, param); +} + +static void APIENTRY InitVertexBlendEnvfATI (GLenum pname, GLfloat param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexBlendEnvfATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexBlendEnvfATI = extproc; + + glVertexBlendEnvfATI(pname, param); +} + +static void APIENTRY InitElementPointerATI (GLenum type, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glElementPointerATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glElementPointerATI = extproc; + + glElementPointerATI(type, pointer); +} + +static void APIENTRY InitDrawElementArrayATI (GLenum mode, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawElementArrayATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawElementArrayATI = extproc; + + glDrawElementArrayATI(mode, count); +} + +static void APIENTRY InitDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElementArrayATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElementArrayATI = extproc; + + glDrawRangeElementArrayATI(mode, start, end, count); +} + +static void APIENTRY InitDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawMeshArraysSUN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawMeshArraysSUN = extproc; + + glDrawMeshArraysSUN(mode, first, count, width); +} + +static void APIENTRY InitGenOcclusionQueriesNV (GLsizei n, GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenOcclusionQueriesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenOcclusionQueriesNV = extproc; + + glGenOcclusionQueriesNV(n, ids); +} + +static void APIENTRY InitDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteOcclusionQueriesNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteOcclusionQueriesNV = extproc; + + glDeleteOcclusionQueriesNV(n, ids); +} + +static GLboolean APIENTRY InitIsOcclusionQueryNV (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsOcclusionQueryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsOcclusionQueryNV = extproc; + + return glIsOcclusionQueryNV(id); +} + +static void APIENTRY InitBeginOcclusionQueryNV (GLuint id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBeginOcclusionQueryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBeginOcclusionQueryNV = extproc; + + glBeginOcclusionQueryNV(id); +} + +static void APIENTRY InitEndOcclusionQueryNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glEndOcclusionQueryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glEndOcclusionQueryNV = extproc; + + glEndOcclusionQueryNV(); +} + +static void APIENTRY InitGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetOcclusionQueryivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetOcclusionQueryivNV = extproc; + + glGetOcclusionQueryivNV(id, pname, params); +} + +static void APIENTRY InitGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetOcclusionQueryuivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetOcclusionQueryuivNV = extproc; + + glGetOcclusionQueryuivNV(id, pname, params); +} + +static void APIENTRY InitPointParameteriNV (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameteriNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameteriNV = extproc; + + glPointParameteriNV(pname, param); +} + +static void APIENTRY InitPointParameterivNV (GLenum pname, const GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPointParameterivNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPointParameterivNV = extproc; + + glPointParameterivNV(pname, params); +} + +static void APIENTRY InitActiveStencilFaceEXT (GLenum face) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glActiveStencilFaceEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glActiveStencilFaceEXT = extproc; + + glActiveStencilFaceEXT(face); +} + +static void APIENTRY InitElementPointerAPPLE (GLenum type, const GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glElementPointerAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glElementPointerAPPLE = extproc; + + glElementPointerAPPLE(type, pointer); +} + +static void APIENTRY InitDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawElementArrayAPPLE = extproc; + + glDrawElementArrayAPPLE(mode, first, count); +} + +static void APIENTRY InitDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawRangeElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawRangeElementArrayAPPLE = extproc; + + glDrawRangeElementArrayAPPLE(mode, start, end, first, count); +} + +static void APIENTRY InitMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawElementArrayAPPLE = extproc; + + glMultiDrawElementArrayAPPLE(mode, first, count, primcount); +} + +static void APIENTRY InitMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiDrawRangeElementArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiDrawRangeElementArrayAPPLE = extproc; + + glMultiDrawRangeElementArrayAPPLE(mode, start, end, first, count, primcount); +} + +static void APIENTRY InitGenFencesAPPLE (GLsizei n, GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenFencesAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenFencesAPPLE = extproc; + + glGenFencesAPPLE(n, fences); +} + +static void APIENTRY InitDeleteFencesAPPLE (GLsizei n, const GLuint *fences) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteFencesAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteFencesAPPLE = extproc; + + glDeleteFencesAPPLE(n, fences); +} + +static void APIENTRY InitSetFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSetFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSetFenceAPPLE = extproc; + + glSetFenceAPPLE(fence); +} + +static GLboolean APIENTRY InitIsFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsFenceAPPLE = extproc; + + return glIsFenceAPPLE(fence); +} + +static GLboolean APIENTRY InitTestFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTestFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glTestFenceAPPLE = extproc; + + return glTestFenceAPPLE(fence); +} + +static void APIENTRY InitFinishFenceAPPLE (GLuint fence) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishFenceAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishFenceAPPLE = extproc; + + glFinishFenceAPPLE(fence); +} + +static GLboolean APIENTRY InitTestObjectAPPLE (GLenum object, GLuint name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTestObjectAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glTestObjectAPPLE = extproc; + + return glTestObjectAPPLE(object, name); +} + +static void APIENTRY InitFinishObjectAPPLE (GLenum object, GLint name) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFinishObjectAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFinishObjectAPPLE = extproc; + + glFinishObjectAPPLE(object, name); +} + +static void APIENTRY InitBindVertexArrayAPPLE (GLuint array) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBindVertexArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBindVertexArrayAPPLE = extproc; + + glBindVertexArrayAPPLE(array); +} + +static void APIENTRY InitDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDeleteVertexArraysAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDeleteVertexArraysAPPLE = extproc; + + glDeleteVertexArraysAPPLE(n, arrays); +} + +static void APIENTRY InitGenVertexArraysAPPLE (GLsizei n, const GLuint *arrays) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGenVertexArraysAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGenVertexArraysAPPLE = extproc; + + glGenVertexArraysAPPLE(n, arrays); +} + +static GLboolean APIENTRY InitIsVertexArrayAPPLE (GLuint array) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glIsVertexArrayAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glIsVertexArrayAPPLE = extproc; + + return glIsVertexArrayAPPLE(array); +} + +static void APIENTRY InitVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexArrayRangeAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexArrayRangeAPPLE = extproc; + + glVertexArrayRangeAPPLE(length, pointer); +} + +static void APIENTRY InitFlushVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushVertexArrayRangeAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushVertexArrayRangeAPPLE = extproc; + + glFlushVertexArrayRangeAPPLE(length, pointer); +} + +static void APIENTRY InitVertexArrayParameteriAPPLE (GLenum pname, GLint param) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexArrayParameteriAPPLE"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexArrayParameteriAPPLE = extproc; + + glVertexArrayParameteriAPPLE(pname, param); +} + +static void APIENTRY InitDrawBuffersATI (GLsizei n, const GLenum *bufs) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDrawBuffersATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDrawBuffersATI = extproc; + + glDrawBuffersATI(n, bufs); +} + +static void APIENTRY InitProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4fNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4fNV = extproc; + + glProgramNamedParameter4fNV(id, len, name, x, y, z, w); +} + +static void APIENTRY InitProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4dNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4dNV = extproc; + + glProgramNamedParameter4dNV(id, len, name, x, y, z, w); +} + +static void APIENTRY InitProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4fvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4fvNV = extproc; + + glProgramNamedParameter4fvNV(id, len, name, v); +} + +static void APIENTRY InitProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glProgramNamedParameter4dvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glProgramNamedParameter4dvNV = extproc; + + glProgramNamedParameter4dvNV(id, len, name, v); +} + +static void APIENTRY InitGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramNamedParameterfvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramNamedParameterfvNV = extproc; + + glGetProgramNamedParameterfvNV(id, len, name, params); +} + +static void APIENTRY InitGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetProgramNamedParameterdvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetProgramNamedParameterdvNV = extproc; + + glGetProgramNamedParameterdvNV(id, len, name, params); +} + +static void APIENTRY InitVertex2hNV (GLhalfNV x, GLhalfNV y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex2hNV = extproc; + + glVertex2hNV(x, y); +} + +static void APIENTRY InitVertex2hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex2hvNV = extproc; + + glVertex2hvNV(v); +} + +static void APIENTRY InitVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex3hNV = extproc; + + glVertex3hNV(x, y, z); +} + +static void APIENTRY InitVertex3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex3hvNV = extproc; + + glVertex3hvNV(v); +} + +static void APIENTRY InitVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex4hNV = extproc; + + glVertex4hNV(x, y, z, w); +} + +static void APIENTRY InitVertex4hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertex4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertex4hvNV = extproc; + + glVertex4hvNV(v); +} + +static void APIENTRY InitNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3hNV = extproc; + + glNormal3hNV(nx, ny, nz); +} + +static void APIENTRY InitNormal3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glNormal3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glNormal3hvNV = extproc; + + glNormal3hvNV(v); +} + +static void APIENTRY InitColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3hNV = extproc; + + glColor3hNV(red, green, blue); +} + +static void APIENTRY InitColor3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor3hvNV = extproc; + + glColor3hvNV(v); +} + +static void APIENTRY InitColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4hNV = extproc; + + glColor4hNV(red, green, blue, alpha); +} + +static void APIENTRY InitColor4hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glColor4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glColor4hvNV = extproc; + + glColor4hvNV(v); +} + +static void APIENTRY InitTexCoord1hNV (GLhalfNV s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord1hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord1hNV = extproc; + + glTexCoord1hNV(s); +} + +static void APIENTRY InitTexCoord1hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord1hvNV = extproc; + + glTexCoord1hvNV(v); +} + +static void APIENTRY InitTexCoord2hNV (GLhalfNV s, GLhalfNV t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2hNV = extproc; + + glTexCoord2hNV(s, t); +} + +static void APIENTRY InitTexCoord2hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord2hvNV = extproc; + + glTexCoord2hvNV(v); +} + +static void APIENTRY InitTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord3hNV = extproc; + + glTexCoord3hNV(s, t, r); +} + +static void APIENTRY InitTexCoord3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord3hvNV = extproc; + + glTexCoord3hvNV(v); +} + +static void APIENTRY InitTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4hNV = extproc; + + glTexCoord4hNV(s, t, r, q); +} + +static void APIENTRY InitTexCoord4hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glTexCoord4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glTexCoord4hvNV = extproc; + + glTexCoord4hvNV(v); +} + +static void APIENTRY InitMultiTexCoord1hNV (GLenum target, GLhalfNV s) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1hNV = extproc; + + glMultiTexCoord1hNV(target, s); +} + +static void APIENTRY InitMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord1hvNV = extproc; + + glMultiTexCoord1hvNV(target, v); +} + +static void APIENTRY InitMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2hNV = extproc; + + glMultiTexCoord2hNV(target, s, t); +} + +static void APIENTRY InitMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord2hvNV = extproc; + + glMultiTexCoord2hvNV(target, v); +} + +static void APIENTRY InitMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3hNV = extproc; + + glMultiTexCoord3hNV(target, s, t, r); +} + +static void APIENTRY InitMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord3hvNV = extproc; + + glMultiTexCoord3hvNV(target, v); +} + +static void APIENTRY InitMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4hNV = extproc; + + glMultiTexCoord4hNV(target, s, t, r, q); +} + +static void APIENTRY InitMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMultiTexCoord4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glMultiTexCoord4hvNV = extproc; + + glMultiTexCoord4hvNV(target, v); +} + +static void APIENTRY InitFogCoordhNV (GLhalfNV fog) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordhNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordhNV = extproc; + + glFogCoordhNV(fog); +} + +static void APIENTRY InitFogCoordhvNV (const GLhalfNV *fog) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFogCoordhvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFogCoordhvNV = extproc; + + glFogCoordhvNV(fog); +} + +static void APIENTRY InitSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3hNV = extproc; + + glSecondaryColor3hNV(red, green, blue); +} + +static void APIENTRY InitSecondaryColor3hvNV (const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glSecondaryColor3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glSecondaryColor3hvNV = extproc; + + glSecondaryColor3hvNV(v); +} + +static void APIENTRY InitVertexWeighthNV (GLhalfNV weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeighthNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeighthNV = extproc; + + glVertexWeighthNV(weight); +} + +static void APIENTRY InitVertexWeighthvNV (const GLhalfNV *weight) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexWeighthvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexWeighthvNV = extproc; + + glVertexWeighthvNV(weight); +} + +static void APIENTRY InitVertexAttrib1hNV (GLuint index, GLhalfNV x) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1hNV = extproc; + + glVertexAttrib1hNV(index, x); +} + +static void APIENTRY InitVertexAttrib1hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib1hvNV = extproc; + + glVertexAttrib1hvNV(index, v); +} + +static void APIENTRY InitVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2hNV = extproc; + + glVertexAttrib2hNV(index, x, y); +} + +static void APIENTRY InitVertexAttrib2hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib2hvNV = extproc; + + glVertexAttrib2hvNV(index, v); +} + +static void APIENTRY InitVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3hNV = extproc; + + glVertexAttrib3hNV(index, x, y, z); +} + +static void APIENTRY InitVertexAttrib3hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib3hvNV = extproc; + + glVertexAttrib3hvNV(index, v); +} + +static void APIENTRY InitVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4hNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4hNV = extproc; + + glVertexAttrib4hNV(index, x, y, z, w); +} + +static void APIENTRY InitVertexAttrib4hvNV (GLuint index, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttrib4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttrib4hvNV = extproc; + + glVertexAttrib4hvNV(index, v); +} + +static void APIENTRY InitVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs1hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs1hvNV = extproc; + + glVertexAttribs1hvNV(index, n, v); +} + +static void APIENTRY InitVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs2hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs2hvNV = extproc; + + glVertexAttribs2hvNV(index, n, v); +} + +static void APIENTRY InitVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs3hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs3hvNV = extproc; + + glVertexAttribs3hvNV(index, n, v); +} + +static void APIENTRY InitVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribs4hvNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribs4hvNV = extproc; + + glVertexAttribs4hvNV(index, n, v); +} + +static void APIENTRY InitPixelDataRangeNV (GLenum target, GLsizei length, GLvoid *pointer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPixelDataRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPixelDataRangeNV = extproc; + + glPixelDataRangeNV(target, length, pointer); +} + +static void APIENTRY InitFlushPixelDataRangeNV (GLenum target) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glFlushPixelDataRangeNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glFlushPixelDataRangeNV = extproc; + + glFlushPixelDataRangeNV(target); +} + +static void APIENTRY InitPrimitiveRestartNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPrimitiveRestartNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPrimitiveRestartNV = extproc; + + glPrimitiveRestartNV(); +} + +static void APIENTRY InitPrimitiveRestartIndexNV (GLuint index) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glPrimitiveRestartIndexNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glPrimitiveRestartIndexNV = extproc; + + glPrimitiveRestartIndexNV(index); +} + +static GLvoid* APIENTRY InitMapObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glMapObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + glMapObjectBufferATI = extproc; + + return glMapObjectBufferATI(buffer); +} + +static void APIENTRY InitUnmapObjectBufferATI (GLuint buffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glUnmapObjectBufferATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glUnmapObjectBufferATI = extproc; + + glUnmapObjectBufferATI(buffer); +} + +static void APIENTRY InitStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStencilOpSeparateATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStencilOpSeparateATI = extproc; + + glStencilOpSeparateATI(face, sfail, dpfail, dppass); +} + +static void APIENTRY InitStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glStencilFuncSeparateATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glStencilFuncSeparateATI = extproc; + + glStencilFuncSeparateATI(frontfunc, backfunc, ref, mask); +} + +static void APIENTRY InitVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glVertexAttribArrayObjectATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glVertexAttribArrayObjectATI = extproc; + + glVertexAttribArrayObjectATI(index, size, type, normalized, stride, buffer, offset); +} + +static void APIENTRY InitGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribArrayObjectfvATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribArrayObjectfvATI = extproc; + + glGetVertexAttribArrayObjectfvATI(index, pname, params); +} + +static void APIENTRY InitGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glGetVertexAttribArrayObjectivATI"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glGetVertexAttribArrayObjectivATI = extproc; + + glGetVertexAttribArrayObjectivATI(index, pname, params); +} + +static void APIENTRY InitDepthBoundsEXT (GLclampd zmin, GLclampd zmax) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glDepthBoundsEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glDepthBoundsEXT = extproc; + + glDepthBoundsEXT(zmin, zmax); +} + +static void APIENTRY InitBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glBlendEquationSeparateEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glBlendEquationSeparateEXT = extproc; + + glBlendEquationSeparateEXT(modeRGB, modeAlpha); +} + +static void APIENTRY InitAddSwapHintRectWIN (GLint x, GLint y, GLsizei width, GLsizei height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("glAddSwapHintRectWIN"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + glAddSwapHintRectWIN = extproc; + + glAddSwapHintRectWIN(x, y, width, height); +} + +#ifdef _WIN32 + +static HANDLE WINAPI InitCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreateBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreateBufferRegionARB = extproc; + + return wglCreateBufferRegionARB(hDC, iLayerPlane, uType); +} + +static VOID WINAPI InitDeleteBufferRegionARB (HANDLE hRegion) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDeleteBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + wglDeleteBufferRegionARB = extproc; + + wglDeleteBufferRegionARB(hRegion); +} + +static BOOL WINAPI InitSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSaveBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSaveBufferRegionARB = extproc; + + return wglSaveBufferRegionARB(hRegion, x, y, width, height); +} + +static BOOL WINAPI InitRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglRestoreBufferRegionARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglRestoreBufferRegionARB = extproc; + + return wglRestoreBufferRegionARB(hRegion, x, y, width, height, xSrc, ySrc); +} + +static const WINAPI InitGetExtensionsStringARB (HDC hdc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetExtensionsStringARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetExtensionsStringARB = extproc; + + return wglGetExtensionsStringARB(hdc); +} + +static BOOL WINAPI InitGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribivARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribivARB = extproc; + + return wglGetPixelFormatAttribivARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues); +} + +static BOOL WINAPI InitGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribfvARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribfvARB = extproc; + + return wglGetPixelFormatAttribfvARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues); +} + +static BOOL WINAPI InitChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglChoosePixelFormatARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglChoosePixelFormatARB = extproc; + + return wglChoosePixelFormatARB(hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats); +} + +static BOOL WINAPI InitMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglMakeContextCurrentARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglMakeContextCurrentARB = extproc; + + return wglMakeContextCurrentARB(hDrawDC, hReadDC, hglrc); +} + +static HDC WINAPI InitGetCurrentReadDCARB (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetCurrentReadDCARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetCurrentReadDCARB = extproc; + + return wglGetCurrentReadDCARB(); +} + +static HPBUFFERARB WINAPI InitCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreatePbufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreatePbufferARB = extproc; + + return wglCreatePbufferARB(hDC, iPixelFormat, iWidth, iHeight, piAttribList); +} + +static HDC WINAPI InitGetPbufferDCARB (HPBUFFERARB hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPbufferDCARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPbufferDCARB = extproc; + + return wglGetPbufferDCARB(hPbuffer); +} + +static int WINAPI InitReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleasePbufferDCARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleasePbufferDCARB = extproc; + + return wglReleasePbufferDCARB(hPbuffer, hDC); +} + +static BOOL WINAPI InitDestroyPbufferARB (HPBUFFERARB hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyPbufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDestroyPbufferARB = extproc; + + return wglDestroyPbufferARB(hPbuffer); +} + +static BOOL WINAPI InitQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryPbufferARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryPbufferARB = extproc; + + return wglQueryPbufferARB(hPbuffer, iAttribute, piValue); +} + +static BOOL WINAPI InitBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglBindTexImageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglBindTexImageARB = extproc; + + return wglBindTexImageARB(hPbuffer, iBuffer); +} + +static BOOL WINAPI InitReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleaseTexImageARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleaseTexImageARB = extproc; + + return wglReleaseTexImageARB(hPbuffer, iBuffer); +} + +static BOOL WINAPI InitSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetPbufferAttribARB"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetPbufferAttribARB = extproc; + + return wglSetPbufferAttribARB(hPbuffer, piAttribList); +} + +static GLboolean WINAPI InitCreateDisplayColorTableEXT (GLushort id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreateDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreateDisplayColorTableEXT = extproc; + + return wglCreateDisplayColorTableEXT(id); +} + +static GLboolean WINAPI InitLoadDisplayColorTableEXT (const GLushort *table, GLuint length) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglLoadDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglLoadDisplayColorTableEXT = extproc; + + return wglLoadDisplayColorTableEXT(table, length); +} + +static GLboolean WINAPI InitBindDisplayColorTableEXT (GLushort id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglBindDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglBindDisplayColorTableEXT = extproc; + + return wglBindDisplayColorTableEXT(id); +} + +static VOID WINAPI InitDestroyDisplayColorTableEXT (GLushort id) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyDisplayColorTableEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + wglDestroyDisplayColorTableEXT = extproc; + + wglDestroyDisplayColorTableEXT(id); +} + +static const WINAPI InitGetExtensionsStringEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetExtensionsStringEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetExtensionsStringEXT = extproc; + + return wglGetExtensionsStringEXT(); +} + +static BOOL WINAPI InitMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglMakeContextCurrentEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglMakeContextCurrentEXT = extproc; + + return wglMakeContextCurrentEXT(hDrawDC, hReadDC, hglrc); +} + +static HDC WINAPI InitGetCurrentReadDCEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetCurrentReadDCEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetCurrentReadDCEXT = extproc; + + return wglGetCurrentReadDCEXT(); +} + +static HPBUFFEREXT WINAPI InitCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreatePbufferEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreatePbufferEXT = extproc; + + return wglCreatePbufferEXT(hDC, iPixelFormat, iWidth, iHeight, piAttribList); +} + +static HDC WINAPI InitGetPbufferDCEXT (HPBUFFEREXT hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPbufferDCEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPbufferDCEXT = extproc; + + return wglGetPbufferDCEXT(hPbuffer); +} + +static int WINAPI InitReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleasePbufferDCEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleasePbufferDCEXT = extproc; + + return wglReleasePbufferDCEXT(hPbuffer, hDC); +} + +static BOOL WINAPI InitDestroyPbufferEXT (HPBUFFEREXT hPbuffer) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyPbufferEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDestroyPbufferEXT = extproc; + + return wglDestroyPbufferEXT(hPbuffer); +} + +static BOOL WINAPI InitQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryPbufferEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryPbufferEXT = extproc; + + return wglQueryPbufferEXT(hPbuffer, iAttribute, piValue); +} + +static BOOL WINAPI InitGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribivEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribivEXT = extproc; + + return wglGetPixelFormatAttribivEXT(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues); +} + +static BOOL WINAPI InitGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetPixelFormatAttribfvEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetPixelFormatAttribfvEXT = extproc; + + return wglGetPixelFormatAttribfvEXT(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues); +} + +static BOOL WINAPI InitChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglChoosePixelFormatEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglChoosePixelFormatEXT = extproc; + + return wglChoosePixelFormatEXT(hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats); +} + +static BOOL WINAPI InitSwapIntervalEXT (int interval) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSwapIntervalEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSwapIntervalEXT = extproc; + + return wglSwapIntervalEXT(interval); +} + +static int WINAPI InitGetSwapIntervalEXT (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetSwapIntervalEXT"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetSwapIntervalEXT = extproc; + + return wglGetSwapIntervalEXT(); +} + +static void* WINAPI InitAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglAllocateMemoryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglAllocateMemoryNV = extproc; + + return wglAllocateMemoryNV(size, readfreq, writefreq, priority); +} + +static void WINAPI InitFreeMemoryNV (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglFreeMemoryNV"); + + if (extproc == NULL) { + _ASSERT(0); + return; + } + + wglFreeMemoryNV = extproc; + + wglFreeMemoryNV(); +} + +static BOOL WINAPI InitGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetSyncValuesOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetSyncValuesOML = extproc; + + return wglGetSyncValuesOML(hdc, ust, msc, sbc); +} + +static BOOL WINAPI InitGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetMscRateOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetMscRateOML = extproc; + + return wglGetMscRateOML(hdc, numerator, denominator); +} + +static INT64 WINAPI InitSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSwapBuffersMscOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSwapBuffersMscOML = extproc; + + return wglSwapBuffersMscOML(hdc, target_msc, divisor, remainder); +} + +static INT64 WINAPI InitSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSwapLayerBuffersMscOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSwapLayerBuffersMscOML = extproc; + + return wglSwapLayerBuffersMscOML(hdc, fuPlanes, target_msc, divisor, remainder); +} + +static BOOL WINAPI InitWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglWaitForMscOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglWaitForMscOML = extproc; + + return wglWaitForMscOML(hdc, target_msc, divisor, remainder, ust, msc, sbc); +} + +static BOOL WINAPI InitWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglWaitForSbcOML"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglWaitForSbcOML = extproc; + + return wglWaitForSbcOML(hdc, target_sbc, ust, msc, sbc); +} + +static BOOL WINAPI InitGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetDigitalVideoParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetDigitalVideoParametersI3D = extproc; + + return wglGetDigitalVideoParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetDigitalVideoParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetDigitalVideoParametersI3D = extproc; + + return wglSetDigitalVideoParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGammaTableParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGammaTableParametersI3D = extproc; + + return wglGetGammaTableParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetGammaTableParametersI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetGammaTableParametersI3D = extproc; + + return wglSetGammaTableParametersI3D(hDC, iAttribute, piValue); +} + +static BOOL WINAPI InitGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGammaTableI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGammaTableI3D = extproc; + + return wglGetGammaTableI3D(hDC, iEntries, puRed, puGreen, puBlue); +} + +static BOOL WINAPI InitSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglSetGammaTableI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglSetGammaTableI3D = extproc; + + return wglSetGammaTableI3D(hDC, iEntries, puRed, puGreen, puBlue); +} + +static BOOL WINAPI InitEnableGenlockI3D (HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglEnableGenlockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglEnableGenlockI3D = extproc; + + return wglEnableGenlockI3D(hDC); +} + +static BOOL WINAPI InitDisableGenlockI3D (HDC hDC) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDisableGenlockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDisableGenlockI3D = extproc; + + return wglDisableGenlockI3D(hDC); +} + +static BOOL WINAPI InitIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglIsEnabledGenlockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglIsEnabledGenlockI3D = extproc; + + return wglIsEnabledGenlockI3D(hDC, pFlag); +} + +static BOOL WINAPI InitGenlockSourceI3D (HDC hDC, UINT uSource) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSourceI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSourceI3D = extproc; + + return wglGenlockSourceI3D(hDC, uSource); +} + +static BOOL WINAPI InitGetGenlockSourceI3D (HDC hDC, UINT *uSource) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSourceI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSourceI3D = extproc; + + return wglGetGenlockSourceI3D(hDC, uSource); +} + +static BOOL WINAPI InitGenlockSourceEdgeI3D (HDC hDC, UINT uEdge) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSourceEdgeI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSourceEdgeI3D = extproc; + + return wglGenlockSourceEdgeI3D(hDC, uEdge); +} + +static BOOL WINAPI InitGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSourceEdgeI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSourceEdgeI3D = extproc; + + return wglGetGenlockSourceEdgeI3D(hDC, uEdge); +} + +static BOOL WINAPI InitGenlockSampleRateI3D (HDC hDC, UINT uRate) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSampleRateI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSampleRateI3D = extproc; + + return wglGenlockSampleRateI3D(hDC, uRate); +} + +static BOOL WINAPI InitGetGenlockSampleRateI3D (HDC hDC, UINT *uRate) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSampleRateI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSampleRateI3D = extproc; + + return wglGetGenlockSampleRateI3D(hDC, uRate); +} + +static BOOL WINAPI InitGenlockSourceDelayI3D (HDC hDC, UINT uDelay) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGenlockSourceDelayI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGenlockSourceDelayI3D = extproc; + + return wglGenlockSourceDelayI3D(hDC, uDelay); +} + +static BOOL WINAPI InitGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetGenlockSourceDelayI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetGenlockSourceDelayI3D = extproc; + + return wglGetGenlockSourceDelayI3D(hDC, uDelay); +} + +static BOOL WINAPI InitQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryGenlockMaxSourceDelayI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryGenlockMaxSourceDelayI3D = extproc; + + return wglQueryGenlockMaxSourceDelayI3D(hDC, uMaxLineDelay, uMaxPixelDelay); +} + +static LPVOID WINAPI InitCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglCreateImageBufferI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglCreateImageBufferI3D = extproc; + + return wglCreateImageBufferI3D(hDC, dwSize, uFlags); +} + +static BOOL WINAPI InitDestroyImageBufferI3D (HDC hDC, LPVOID pAddress) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDestroyImageBufferI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDestroyImageBufferI3D = extproc; + + return wglDestroyImageBufferI3D(hDC, pAddress); +} + +static BOOL WINAPI InitAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglAssociateImageBufferEventsI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglAssociateImageBufferEventsI3D = extproc; + + return wglAssociateImageBufferEventsI3D(hDC, pEvent, pAddress, pSize, count); +} + +static BOOL WINAPI InitReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglReleaseImageBufferEventsI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglReleaseImageBufferEventsI3D = extproc; + + return wglReleaseImageBufferEventsI3D(hDC, pAddress, count); +} + +static BOOL WINAPI InitEnableFrameLockI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglEnableFrameLockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglEnableFrameLockI3D = extproc; + + return wglEnableFrameLockI3D(); +} + +static BOOL WINAPI InitDisableFrameLockI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglDisableFrameLockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglDisableFrameLockI3D = extproc; + + return wglDisableFrameLockI3D(); +} + +static BOOL WINAPI InitIsEnabledFrameLockI3D (BOOL *pFlag) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglIsEnabledFrameLockI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglIsEnabledFrameLockI3D = extproc; + + return wglIsEnabledFrameLockI3D(pFlag); +} + +static BOOL WINAPI InitQueryFrameLockMasterI3D (BOOL *pFlag) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryFrameLockMasterI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryFrameLockMasterI3D = extproc; + + return wglQueryFrameLockMasterI3D(pFlag); +} + +static BOOL WINAPI InitGetFrameUsageI3D (float *pUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglGetFrameUsageI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglGetFrameUsageI3D = extproc; + + return wglGetFrameUsageI3D(pUsage); +} + +static BOOL WINAPI InitBeginFrameTrackingI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglBeginFrameTrackingI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglBeginFrameTrackingI3D = extproc; + + return wglBeginFrameTrackingI3D(); +} + +static BOOL WINAPI InitEndFrameTrackingI3D (void) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglEndFrameTrackingI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglEndFrameTrackingI3D = extproc; + + return wglEndFrameTrackingI3D(); +} + +static BOOL WINAPI InitQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage) +{ + void *extproc; + + extproc = (void *) wglGetProcAddress("wglQueryFrameTrackingI3D"); + + if (extproc == NULL) { + _ASSERT(0); + return 0; + } + + wglQueryFrameTrackingI3D = extproc; + + return wglQueryFrameTrackingI3D(pFrameCount, pMissedFrames, pLastMissedUsage); +} + +#endif /* _WIN32 */ + +_GLextensionProcs _extensionProcs = { + InitBlendColor, + InitBlendEquation, + InitDrawRangeElements, + InitColorTable, + InitColorTableParameterfv, + InitColorTableParameteriv, + InitCopyColorTable, + InitGetColorTable, + InitGetColorTableParameterfv, + InitGetColorTableParameteriv, + InitColorSubTable, + InitCopyColorSubTable, + InitConvolutionFilter1D, + InitConvolutionFilter2D, + InitConvolutionParameterf, + InitConvolutionParameterfv, + InitConvolutionParameteri, + InitConvolutionParameteriv, + InitCopyConvolutionFilter1D, + InitCopyConvolutionFilter2D, + InitGetConvolutionFilter, + InitGetConvolutionParameterfv, + InitGetConvolutionParameteriv, + InitGetSeparableFilter, + InitSeparableFilter2D, + InitGetHistogram, + InitGetHistogramParameterfv, + InitGetHistogramParameteriv, + InitGetMinmax, + InitGetMinmaxParameterfv, + InitGetMinmaxParameteriv, + InitHistogram, + InitMinmax, + InitResetHistogram, + InitResetMinmax, + InitTexImage3D, + InitTexSubImage3D, + InitCopyTexSubImage3D, + InitActiveTexture, + InitClientActiveTexture, + InitMultiTexCoord1d, + InitMultiTexCoord1dv, + InitMultiTexCoord1f, + InitMultiTexCoord1fv, + InitMultiTexCoord1i, + InitMultiTexCoord1iv, + InitMultiTexCoord1s, + InitMultiTexCoord1sv, + InitMultiTexCoord2d, + InitMultiTexCoord2dv, + InitMultiTexCoord2f, + InitMultiTexCoord2fv, + InitMultiTexCoord2i, + InitMultiTexCoord2iv, + InitMultiTexCoord2s, + InitMultiTexCoord2sv, + InitMultiTexCoord3d, + InitMultiTexCoord3dv, + InitMultiTexCoord3f, + InitMultiTexCoord3fv, + InitMultiTexCoord3i, + InitMultiTexCoord3iv, + InitMultiTexCoord3s, + InitMultiTexCoord3sv, + InitMultiTexCoord4d, + InitMultiTexCoord4dv, + InitMultiTexCoord4f, + InitMultiTexCoord4fv, + InitMultiTexCoord4i, + InitMultiTexCoord4iv, + InitMultiTexCoord4s, + InitMultiTexCoord4sv, + InitLoadTransposeMatrixf, + InitLoadTransposeMatrixd, + InitMultTransposeMatrixf, + InitMultTransposeMatrixd, + InitSampleCoverage, + InitCompressedTexImage3D, + InitCompressedTexImage2D, + InitCompressedTexImage1D, + InitCompressedTexSubImage3D, + InitCompressedTexSubImage2D, + InitCompressedTexSubImage1D, + InitGetCompressedTexImage, + InitBlendFuncSeparate, + InitFogCoordf, + InitFogCoordfv, + InitFogCoordd, + InitFogCoorddv, + InitFogCoordPointer, + InitMultiDrawArrays, + InitMultiDrawElements, + InitPointParameterf, + InitPointParameterfv, + InitPointParameteri, + InitPointParameteriv, + InitSecondaryColor3b, + InitSecondaryColor3bv, + InitSecondaryColor3d, + InitSecondaryColor3dv, + InitSecondaryColor3f, + InitSecondaryColor3fv, + InitSecondaryColor3i, + InitSecondaryColor3iv, + InitSecondaryColor3s, + InitSecondaryColor3sv, + InitSecondaryColor3ub, + InitSecondaryColor3ubv, + InitSecondaryColor3ui, + InitSecondaryColor3uiv, + InitSecondaryColor3us, + InitSecondaryColor3usv, + InitSecondaryColorPointer, + InitWindowPos2d, + InitWindowPos2dv, + InitWindowPos2f, + InitWindowPos2fv, + InitWindowPos2i, + InitWindowPos2iv, + InitWindowPos2s, + InitWindowPos2sv, + InitWindowPos3d, + InitWindowPos3dv, + InitWindowPos3f, + InitWindowPos3fv, + InitWindowPos3i, + InitWindowPos3iv, + InitWindowPos3s, + InitWindowPos3sv, + InitGenQueries, + InitDeleteQueries, + InitIsQuery, + InitBeginQuery, + InitEndQuery, + InitGetQueryiv, + InitGetQueryObjectiv, + InitGetQueryObjectuiv, + InitBindBuffer, + InitDeleteBuffers, + InitGenBuffers, + InitIsBuffer, + InitBufferData, + InitBufferSubData, + InitGetBufferSubData, + InitMapBuffer, + InitUnmapBuffer, + InitGetBufferParameteriv, + InitGetBufferPointerv, + InitActiveTextureARB, + InitClientActiveTextureARB, + InitMultiTexCoord1dARB, + InitMultiTexCoord1dvARB, + InitMultiTexCoord1fARB, + InitMultiTexCoord1fvARB, + InitMultiTexCoord1iARB, + InitMultiTexCoord1ivARB, + InitMultiTexCoord1sARB, + InitMultiTexCoord1svARB, + InitMultiTexCoord2dARB, + InitMultiTexCoord2dvARB, + InitMultiTexCoord2fARB, + InitMultiTexCoord2fvARB, + InitMultiTexCoord2iARB, + InitMultiTexCoord2ivARB, + InitMultiTexCoord2sARB, + InitMultiTexCoord2svARB, + InitMultiTexCoord3dARB, + InitMultiTexCoord3dvARB, + InitMultiTexCoord3fARB, + InitMultiTexCoord3fvARB, + InitMultiTexCoord3iARB, + InitMultiTexCoord3ivARB, + InitMultiTexCoord3sARB, + InitMultiTexCoord3svARB, + InitMultiTexCoord4dARB, + InitMultiTexCoord4dvARB, + InitMultiTexCoord4fARB, + InitMultiTexCoord4fvARB, + InitMultiTexCoord4iARB, + InitMultiTexCoord4ivARB, + InitMultiTexCoord4sARB, + InitMultiTexCoord4svARB, + InitLoadTransposeMatrixfARB, + InitLoadTransposeMatrixdARB, + InitMultTransposeMatrixfARB, + InitMultTransposeMatrixdARB, + InitSampleCoverageARB, + InitCompressedTexImage3DARB, + InitCompressedTexImage2DARB, + InitCompressedTexImage1DARB, + InitCompressedTexSubImage3DARB, + InitCompressedTexSubImage2DARB, + InitCompressedTexSubImage1DARB, + InitGetCompressedTexImageARB, + InitPointParameterfARB, + InitPointParameterfvARB, + InitWeightbvARB, + InitWeightsvARB, + InitWeightivARB, + InitWeightfvARB, + InitWeightdvARB, + InitWeightubvARB, + InitWeightusvARB, + InitWeightuivARB, + InitWeightPointerARB, + InitVertexBlendARB, + InitCurrentPaletteMatrixARB, + InitMatrixIndexubvARB, + InitMatrixIndexusvARB, + InitMatrixIndexuivARB, + InitMatrixIndexPointerARB, + InitWindowPos2dARB, + InitWindowPos2dvARB, + InitWindowPos2fARB, + InitWindowPos2fvARB, + InitWindowPos2iARB, + InitWindowPos2ivARB, + InitWindowPos2sARB, + InitWindowPos2svARB, + InitWindowPos3dARB, + InitWindowPos3dvARB, + InitWindowPos3fARB, + InitWindowPos3fvARB, + InitWindowPos3iARB, + InitWindowPos3ivARB, + InitWindowPos3sARB, + InitWindowPos3svARB, + InitVertexAttrib1dARB, + InitVertexAttrib1dvARB, + InitVertexAttrib1fARB, + InitVertexAttrib1fvARB, + InitVertexAttrib1sARB, + InitVertexAttrib1svARB, + InitVertexAttrib2dARB, + InitVertexAttrib2dvARB, + InitVertexAttrib2fARB, + InitVertexAttrib2fvARB, + InitVertexAttrib2sARB, + InitVertexAttrib2svARB, + InitVertexAttrib3dARB, + InitVertexAttrib3dvARB, + InitVertexAttrib3fARB, + InitVertexAttrib3fvARB, + InitVertexAttrib3sARB, + InitVertexAttrib3svARB, + InitVertexAttrib4NbvARB, + InitVertexAttrib4NivARB, + InitVertexAttrib4NsvARB, + InitVertexAttrib4NubARB, + InitVertexAttrib4NubvARB, + InitVertexAttrib4NuivARB, + InitVertexAttrib4NusvARB, + InitVertexAttrib4bvARB, + InitVertexAttrib4dARB, + InitVertexAttrib4dvARB, + InitVertexAttrib4fARB, + InitVertexAttrib4fvARB, + InitVertexAttrib4ivARB, + InitVertexAttrib4sARB, + InitVertexAttrib4svARB, + InitVertexAttrib4ubvARB, + InitVertexAttrib4uivARB, + InitVertexAttrib4usvARB, + InitVertexAttribPointerARB, + InitEnableVertexAttribArrayARB, + InitDisableVertexAttribArrayARB, + InitProgramStringARB, + InitBindProgramARB, + InitDeleteProgramsARB, + InitGenProgramsARB, + InitProgramEnvParameter4dARB, + InitProgramEnvParameter4dvARB, + InitProgramEnvParameter4fARB, + InitProgramEnvParameter4fvARB, + InitProgramLocalParameter4dARB, + InitProgramLocalParameter4dvARB, + InitProgramLocalParameter4fARB, + InitProgramLocalParameter4fvARB, + InitGetProgramEnvParameterdvARB, + InitGetProgramEnvParameterfvARB, + InitGetProgramLocalParameterdvARB, + InitGetProgramLocalParameterfvARB, + InitGetProgramivARB, + InitGetProgramStringARB, + InitGetVertexAttribdvARB, + InitGetVertexAttribfvARB, + InitGetVertexAttribivARB, + InitGetVertexAttribPointervARB, + InitIsProgramARB, + InitBindBufferARB, + InitDeleteBuffersARB, + InitGenBuffersARB, + InitIsBufferARB, + InitBufferDataARB, + InitBufferSubDataARB, + InitGetBufferSubDataARB, + InitMapBufferARB, + InitUnmapBufferARB, + InitGetBufferParameterivARB, + InitGetBufferPointervARB, + InitGenQueriesARB, + InitDeleteQueriesARB, + InitIsQueryARB, + InitBeginQueryARB, + InitEndQueryARB, + InitGetQueryivARB, + InitGetQueryObjectivARB, + InitGetQueryObjectuivARB, + InitDeleteObjectARB, + InitGetHandleARB, + InitDetachObjectARB, + InitCreateShaderObjectARB, + InitShaderSourceARB, + InitCompileShaderARB, + InitCreateProgramObjectARB, + InitAttachObjectARB, + InitLinkProgramARB, + InitUseProgramObjectARB, + InitValidateProgramARB, + InitUniform1fARB, + InitUniform2fARB, + InitUniform3fARB, + InitUniform4fARB, + InitUniform1iARB, + InitUniform2iARB, + InitUniform3iARB, + InitUniform4iARB, + InitUniform1fvARB, + InitUniform2fvARB, + InitUniform3fvARB, + InitUniform4fvARB, + InitUniform1ivARB, + InitUniform2ivARB, + InitUniform3ivARB, + InitUniform4ivARB, + InitUniformMatrix2fvARB, + InitUniformMatrix3fvARB, + InitUniformMatrix4fvARB, + InitGetObjectParameterfvARB, + InitGetObjectParameterivARB, + InitGetInfoLogARB, + InitGetAttachedObjectsARB, + InitGetUniformLocationARB, + InitGetActiveUniformARB, + InitGetUniformfvARB, + InitGetUniformivARB, + InitGetShaderSourceARB, + InitBindAttribLocationARB, + InitGetActiveAttribARB, + InitGetAttribLocationARB, + InitBlendColorEXT, + InitPolygonOffsetEXT, + InitTexImage3DEXT, + InitTexSubImage3DEXT, + InitGetTexFilterFuncSGIS, + InitTexFilterFuncSGIS, + InitTexSubImage1DEXT, + InitTexSubImage2DEXT, + InitCopyTexImage1DEXT, + InitCopyTexImage2DEXT, + InitCopyTexSubImage1DEXT, + InitCopyTexSubImage2DEXT, + InitCopyTexSubImage3DEXT, + InitGetHistogramEXT, + InitGetHistogramParameterfvEXT, + InitGetHistogramParameterivEXT, + InitGetMinmaxEXT, + InitGetMinmaxParameterfvEXT, + InitGetMinmaxParameterivEXT, + InitHistogramEXT, + InitMinmaxEXT, + InitResetHistogramEXT, + InitResetMinmaxEXT, + InitConvolutionFilter1DEXT, + InitConvolutionFilter2DEXT, + InitConvolutionParameterfEXT, + InitConvolutionParameterfvEXT, + InitConvolutionParameteriEXT, + InitConvolutionParameterivEXT, + InitCopyConvolutionFilter1DEXT, + InitCopyConvolutionFilter2DEXT, + InitGetConvolutionFilterEXT, + InitGetConvolutionParameterfvEXT, + InitGetConvolutionParameterivEXT, + InitGetSeparableFilterEXT, + InitSeparableFilter2DEXT, + InitColorTableSGI, + InitColorTableParameterfvSGI, + InitColorTableParameterivSGI, + InitCopyColorTableSGI, + InitGetColorTableSGI, + InitGetColorTableParameterfvSGI, + InitGetColorTableParameterivSGI, + InitPixelTexGenSGIX, + InitPixelTexGenParameteriSGIS, + InitPixelTexGenParameterivSGIS, + InitPixelTexGenParameterfSGIS, + InitPixelTexGenParameterfvSGIS, + InitGetPixelTexGenParameterivSGIS, + InitGetPixelTexGenParameterfvSGIS, + InitTexImage4DSGIS, + InitTexSubImage4DSGIS, + InitAreTexturesResidentEXT, + InitBindTextureEXT, + InitDeleteTexturesEXT, + InitGenTexturesEXT, + InitIsTextureEXT, + InitPrioritizeTexturesEXT, + InitDetailTexFuncSGIS, + InitGetDetailTexFuncSGIS, + InitSharpenTexFuncSGIS, + InitGetSharpenTexFuncSGIS, + InitSampleMaskSGIS, + InitSamplePatternSGIS, + InitArrayElementEXT, + InitColorPointerEXT, + InitDrawArraysEXT, + InitEdgeFlagPointerEXT, + InitGetPointervEXT, + InitIndexPointerEXT, + InitNormalPointerEXT, + InitTexCoordPointerEXT, + InitVertexPointerEXT, + InitBlendEquationEXT, + InitSpriteParameterfSGIX, + InitSpriteParameterfvSGIX, + InitSpriteParameteriSGIX, + InitSpriteParameterivSGIX, + InitPointParameterfEXT, + InitPointParameterfvEXT, + InitPointParameterfSGIS, + InitPointParameterfvSGIS, + InitGetInstrumentsSGIX, + InitInstrumentsBufferSGIX, + InitPollInstrumentsSGIX, + InitReadInstrumentsSGIX, + InitStartInstrumentsSGIX, + InitStopInstrumentsSGIX, + InitFrameZoomSGIX, + InitTagSampleBufferSGIX, + InitDeformationMap3dSGIX, + InitDeformationMap3fSGIX, + InitDeformSGIX, + InitLoadIdentityDeformationMapSGIX, + InitReferencePlaneSGIX, + InitFlushRasterSGIX, + InitFogFuncSGIS, + InitGetFogFuncSGIS, + InitImageTransformParameteriHP, + InitImageTransformParameterfHP, + InitImageTransformParameterivHP, + InitImageTransformParameterfvHP, + InitGetImageTransformParameterivHP, + InitGetImageTransformParameterfvHP, + InitColorSubTableEXT, + InitCopyColorSubTableEXT, + InitHintPGI, + InitColorTableEXT, + InitGetColorTableEXT, + InitGetColorTableParameterivEXT, + InitGetColorTableParameterfvEXT, + InitGetListParameterfvSGIX, + InitGetListParameterivSGIX, + InitListParameterfSGIX, + InitListParameterfvSGIX, + InitListParameteriSGIX, + InitListParameterivSGIX, + InitIndexMaterialEXT, + InitIndexFuncEXT, + InitLockArraysEXT, + InitUnlockArraysEXT, + InitCullParameterdvEXT, + InitCullParameterfvEXT, + InitFragmentColorMaterialSGIX, + InitFragmentLightfSGIX, + InitFragmentLightfvSGIX, + InitFragmentLightiSGIX, + InitFragmentLightivSGIX, + InitFragmentLightModelfSGIX, + InitFragmentLightModelfvSGIX, + InitFragmentLightModeliSGIX, + InitFragmentLightModelivSGIX, + InitFragmentMaterialfSGIX, + InitFragmentMaterialfvSGIX, + InitFragmentMaterialiSGIX, + InitFragmentMaterialivSGIX, + InitGetFragmentLightfvSGIX, + InitGetFragmentLightivSGIX, + InitGetFragmentMaterialfvSGIX, + InitGetFragmentMaterialivSGIX, + InitLightEnviSGIX, + InitDrawRangeElementsEXT, + InitApplyTextureEXT, + InitTextureLightEXT, + InitTextureMaterialEXT, + InitAsyncMarkerSGIX, + InitFinishAsyncSGIX, + InitPollAsyncSGIX, + InitGenAsyncMarkersSGIX, + InitDeleteAsyncMarkersSGIX, + InitIsAsyncMarkerSGIX, + InitVertexPointervINTEL, + InitNormalPointervINTEL, + InitColorPointervINTEL, + InitTexCoordPointervINTEL, + InitPixelTransformParameteriEXT, + InitPixelTransformParameterfEXT, + InitPixelTransformParameterivEXT, + InitPixelTransformParameterfvEXT, + InitSecondaryColor3bEXT, + InitSecondaryColor3bvEXT, + InitSecondaryColor3dEXT, + InitSecondaryColor3dvEXT, + InitSecondaryColor3fEXT, + InitSecondaryColor3fvEXT, + InitSecondaryColor3iEXT, + InitSecondaryColor3ivEXT, + InitSecondaryColor3sEXT, + InitSecondaryColor3svEXT, + InitSecondaryColor3ubEXT, + InitSecondaryColor3ubvEXT, + InitSecondaryColor3uiEXT, + InitSecondaryColor3uivEXT, + InitSecondaryColor3usEXT, + InitSecondaryColor3usvEXT, + InitSecondaryColorPointerEXT, + InitTextureNormalEXT, + InitMultiDrawArraysEXT, + InitMultiDrawElementsEXT, + InitFogCoordfEXT, + InitFogCoordfvEXT, + InitFogCoorddEXT, + InitFogCoorddvEXT, + InitFogCoordPointerEXT, + InitTangent3bEXT, + InitTangent3bvEXT, + InitTangent3dEXT, + InitTangent3dvEXT, + InitTangent3fEXT, + InitTangent3fvEXT, + InitTangent3iEXT, + InitTangent3ivEXT, + InitTangent3sEXT, + InitTangent3svEXT, + InitBinormal3bEXT, + InitBinormal3bvEXT, + InitBinormal3dEXT, + InitBinormal3dvEXT, + InitBinormal3fEXT, + InitBinormal3fvEXT, + InitBinormal3iEXT, + InitBinormal3ivEXT, + InitBinormal3sEXT, + InitBinormal3svEXT, + InitTangentPointerEXT, + InitBinormalPointerEXT, + InitFinishTextureSUNX, + InitGlobalAlphaFactorbSUN, + InitGlobalAlphaFactorsSUN, + InitGlobalAlphaFactoriSUN, + InitGlobalAlphaFactorfSUN, + InitGlobalAlphaFactordSUN, + InitGlobalAlphaFactorubSUN, + InitGlobalAlphaFactorusSUN, + InitGlobalAlphaFactoruiSUN, + InitReplacementCodeuiSUN, + InitReplacementCodeusSUN, + InitReplacementCodeubSUN, + InitReplacementCodeuivSUN, + InitReplacementCodeusvSUN, + InitReplacementCodeubvSUN, + InitReplacementCodePointerSUN, + InitColor4ubVertex2fSUN, + InitColor4ubVertex2fvSUN, + InitColor4ubVertex3fSUN, + InitColor4ubVertex3fvSUN, + InitColor3fVertex3fSUN, + InitColor3fVertex3fvSUN, + InitNormal3fVertex3fSUN, + InitNormal3fVertex3fvSUN, + InitColor4fNormal3fVertex3fSUN, + InitColor4fNormal3fVertex3fvSUN, + InitTexCoord2fVertex3fSUN, + InitTexCoord2fVertex3fvSUN, + InitTexCoord4fVertex4fSUN, + InitTexCoord4fVertex4fvSUN, + InitTexCoord2fColor4ubVertex3fSUN, + InitTexCoord2fColor4ubVertex3fvSUN, + InitTexCoord2fColor3fVertex3fSUN, + InitTexCoord2fColor3fVertex3fvSUN, + InitTexCoord2fNormal3fVertex3fSUN, + InitTexCoord2fNormal3fVertex3fvSUN, + InitTexCoord2fColor4fNormal3fVertex3fSUN, + InitTexCoord2fColor4fNormal3fVertex3fvSUN, + InitTexCoord4fColor4fNormal3fVertex4fSUN, + InitTexCoord4fColor4fNormal3fVertex4fvSUN, + InitReplacementCodeuiVertex3fSUN, + InitReplacementCodeuiVertex3fvSUN, + InitReplacementCodeuiColor4ubVertex3fSUN, + InitReplacementCodeuiColor4ubVertex3fvSUN, + InitReplacementCodeuiColor3fVertex3fSUN, + InitReplacementCodeuiColor3fVertex3fvSUN, + InitReplacementCodeuiNormal3fVertex3fSUN, + InitReplacementCodeuiNormal3fVertex3fvSUN, + InitReplacementCodeuiColor4fNormal3fVertex3fSUN, + InitReplacementCodeuiColor4fNormal3fVertex3fvSUN, + InitReplacementCodeuiTexCoord2fVertex3fSUN, + InitReplacementCodeuiTexCoord2fVertex3fvSUN, + InitReplacementCodeuiTexCoord2fNormal3fVertex3fSUN, + InitReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN, + InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN, + InitReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN, + InitBlendFuncSeparateEXT, + InitBlendFuncSeparateINGR, + InitVertexWeightfEXT, + InitVertexWeightfvEXT, + InitVertexWeightPointerEXT, + InitFlushVertexArrayRangeNV, + InitVertexArrayRangeNV, + InitCombinerParameterfvNV, + InitCombinerParameterfNV, + InitCombinerParameterivNV, + InitCombinerParameteriNV, + InitCombinerInputNV, + InitCombinerOutputNV, + InitFinalCombinerInputNV, + InitGetCombinerInputParameterfvNV, + InitGetCombinerInputParameterivNV, + InitGetCombinerOutputParameterfvNV, + InitGetCombinerOutputParameterivNV, + InitGetFinalCombinerInputParameterfvNV, + InitGetFinalCombinerInputParameterivNV, + InitResizeBuffersMESA, + InitWindowPos2dMESA, + InitWindowPos2dvMESA, + InitWindowPos2fMESA, + InitWindowPos2fvMESA, + InitWindowPos2iMESA, + InitWindowPos2ivMESA, + InitWindowPos2sMESA, + InitWindowPos2svMESA, + InitWindowPos3dMESA, + InitWindowPos3dvMESA, + InitWindowPos3fMESA, + InitWindowPos3fvMESA, + InitWindowPos3iMESA, + InitWindowPos3ivMESA, + InitWindowPos3sMESA, + InitWindowPos3svMESA, + InitWindowPos4dMESA, + InitWindowPos4dvMESA, + InitWindowPos4fMESA, + InitWindowPos4fvMESA, + InitWindowPos4iMESA, + InitWindowPos4ivMESA, + InitWindowPos4sMESA, + InitWindowPos4svMESA, + InitMultiModeDrawArraysIBM, + InitMultiModeDrawElementsIBM, + InitColorPointerListIBM, + InitSecondaryColorPointerListIBM, + InitEdgeFlagPointerListIBM, + InitFogCoordPointerListIBM, + InitIndexPointerListIBM, + InitNormalPointerListIBM, + InitTexCoordPointerListIBM, + InitVertexPointerListIBM, + InitTbufferMask3DFX, + InitSampleMaskEXT, + InitSamplePatternEXT, + InitTextureColorMaskSGIS, + InitIglooInterfaceSGIX, + InitDeleteFencesNV, + InitGenFencesNV, + InitIsFenceNV, + InitTestFenceNV, + InitGetFenceivNV, + InitFinishFenceNV, + InitSetFenceNV, + InitMapControlPointsNV, + InitMapParameterivNV, + InitMapParameterfvNV, + InitGetMapControlPointsNV, + InitGetMapParameterivNV, + InitGetMapParameterfvNV, + InitGetMapAttribParameterivNV, + InitGetMapAttribParameterfvNV, + InitEvalMapsNV, + InitCombinerStageParameterfvNV, + InitGetCombinerStageParameterfvNV, + InitAreProgramsResidentNV, + InitBindProgramNV, + InitDeleteProgramsNV, + InitExecuteProgramNV, + InitGenProgramsNV, + InitGetProgramParameterdvNV, + InitGetProgramParameterfvNV, + InitGetProgramivNV, + InitGetProgramStringNV, + InitGetTrackMatrixivNV, + InitGetVertexAttribdvNV, + InitGetVertexAttribfvNV, + InitGetVertexAttribivNV, + InitGetVertexAttribPointervNV, + InitIsProgramNV, + InitLoadProgramNV, + InitProgramParameter4dNV, + InitProgramParameter4dvNV, + InitProgramParameter4fNV, + InitProgramParameter4fvNV, + InitProgramParameters4dvNV, + InitProgramParameters4fvNV, + InitRequestResidentProgramsNV, + InitTrackMatrixNV, + InitVertexAttribPointerNV, + InitVertexAttrib1dNV, + InitVertexAttrib1dvNV, + InitVertexAttrib1fNV, + InitVertexAttrib1fvNV, + InitVertexAttrib1sNV, + InitVertexAttrib1svNV, + InitVertexAttrib2dNV, + InitVertexAttrib2dvNV, + InitVertexAttrib2fNV, + InitVertexAttrib2fvNV, + InitVertexAttrib2sNV, + InitVertexAttrib2svNV, + InitVertexAttrib3dNV, + InitVertexAttrib3dvNV, + InitVertexAttrib3fNV, + InitVertexAttrib3fvNV, + InitVertexAttrib3sNV, + InitVertexAttrib3svNV, + InitVertexAttrib4dNV, + InitVertexAttrib4dvNV, + InitVertexAttrib4fNV, + InitVertexAttrib4fvNV, + InitVertexAttrib4sNV, + InitVertexAttrib4svNV, + InitVertexAttrib4ubNV, + InitVertexAttrib4ubvNV, + InitVertexAttribs1dvNV, + InitVertexAttribs1fvNV, + InitVertexAttribs1svNV, + InitVertexAttribs2dvNV, + InitVertexAttribs2fvNV, + InitVertexAttribs2svNV, + InitVertexAttribs3dvNV, + InitVertexAttribs3fvNV, + InitVertexAttribs3svNV, + InitVertexAttribs4dvNV, + InitVertexAttribs4fvNV, + InitVertexAttribs4svNV, + InitVertexAttribs4ubvNV, + InitTexBumpParameterivATI, + InitTexBumpParameterfvATI, + InitGetTexBumpParameterivATI, + InitGetTexBumpParameterfvATI, + InitGenFragmentShadersATI, + InitBindFragmentShaderATI, + InitDeleteFragmentShaderATI, + InitBeginFragmentShaderATI, + InitEndFragmentShaderATI, + InitPassTexCoordATI, + InitSampleMapATI, + InitColorFragmentOp1ATI, + InitColorFragmentOp2ATI, + InitColorFragmentOp3ATI, + InitAlphaFragmentOp1ATI, + InitAlphaFragmentOp2ATI, + InitAlphaFragmentOp3ATI, + InitSetFragmentShaderConstantATI, + InitPNTrianglesiATI, + InitPNTrianglesfATI, + InitNewObjectBufferATI, + InitIsObjectBufferATI, + InitUpdateObjectBufferATI, + InitGetObjectBufferfvATI, + InitGetObjectBufferivATI, + InitFreeObjectBufferATI, + InitArrayObjectATI, + InitGetArrayObjectfvATI, + InitGetArrayObjectivATI, + InitVariantArrayObjectATI, + InitGetVariantArrayObjectfvATI, + InitGetVariantArrayObjectivATI, + InitBeginVertexShaderEXT, + InitEndVertexShaderEXT, + InitBindVertexShaderEXT, + InitGenVertexShadersEXT, + InitDeleteVertexShaderEXT, + InitShaderOp1EXT, + InitShaderOp2EXT, + InitShaderOp3EXT, + InitSwizzleEXT, + InitWriteMaskEXT, + InitInsertComponentEXT, + InitExtractComponentEXT, + InitGenSymbolsEXT, + InitSetInvariantEXT, + InitSetLocalConstantEXT, + InitVariantbvEXT, + InitVariantsvEXT, + InitVariantivEXT, + InitVariantfvEXT, + InitVariantdvEXT, + InitVariantubvEXT, + InitVariantusvEXT, + InitVariantuivEXT, + InitVariantPointerEXT, + InitEnableVariantClientStateEXT, + InitDisableVariantClientStateEXT, + InitBindLightParameterEXT, + InitBindMaterialParameterEXT, + InitBindTexGenParameterEXT, + InitBindTextureUnitParameterEXT, + InitBindParameterEXT, + InitIsVariantEnabledEXT, + InitGetVariantBooleanvEXT, + InitGetVariantIntegervEXT, + InitGetVariantFloatvEXT, + InitGetVariantPointervEXT, + InitGetInvariantBooleanvEXT, + InitGetInvariantIntegervEXT, + InitGetInvariantFloatvEXT, + InitGetLocalConstantBooleanvEXT, + InitGetLocalConstantIntegervEXT, + InitGetLocalConstantFloatvEXT, + InitVertexStream1sATI, + InitVertexStream1svATI, + InitVertexStream1iATI, + InitVertexStream1ivATI, + InitVertexStream1fATI, + InitVertexStream1fvATI, + InitVertexStream1dATI, + InitVertexStream1dvATI, + InitVertexStream2sATI, + InitVertexStream2svATI, + InitVertexStream2iATI, + InitVertexStream2ivATI, + InitVertexStream2fATI, + InitVertexStream2fvATI, + InitVertexStream2dATI, + InitVertexStream2dvATI, + InitVertexStream3sATI, + InitVertexStream3svATI, + InitVertexStream3iATI, + InitVertexStream3ivATI, + InitVertexStream3fATI, + InitVertexStream3fvATI, + InitVertexStream3dATI, + InitVertexStream3dvATI, + InitVertexStream4sATI, + InitVertexStream4svATI, + InitVertexStream4iATI, + InitVertexStream4ivATI, + InitVertexStream4fATI, + InitVertexStream4fvATI, + InitVertexStream4dATI, + InitVertexStream4dvATI, + InitNormalStream3bATI, + InitNormalStream3bvATI, + InitNormalStream3sATI, + InitNormalStream3svATI, + InitNormalStream3iATI, + InitNormalStream3ivATI, + InitNormalStream3fATI, + InitNormalStream3fvATI, + InitNormalStream3dATI, + InitNormalStream3dvATI, + InitClientActiveVertexStreamATI, + InitVertexBlendEnviATI, + InitVertexBlendEnvfATI, + InitElementPointerATI, + InitDrawElementArrayATI, + InitDrawRangeElementArrayATI, + InitDrawMeshArraysSUN, + InitGenOcclusionQueriesNV, + InitDeleteOcclusionQueriesNV, + InitIsOcclusionQueryNV, + InitBeginOcclusionQueryNV, + InitEndOcclusionQueryNV, + InitGetOcclusionQueryivNV, + InitGetOcclusionQueryuivNV, + InitPointParameteriNV, + InitPointParameterivNV, + InitActiveStencilFaceEXT, + InitElementPointerAPPLE, + InitDrawElementArrayAPPLE, + InitDrawRangeElementArrayAPPLE, + InitMultiDrawElementArrayAPPLE, + InitMultiDrawRangeElementArrayAPPLE, + InitGenFencesAPPLE, + InitDeleteFencesAPPLE, + InitSetFenceAPPLE, + InitIsFenceAPPLE, + InitTestFenceAPPLE, + InitFinishFenceAPPLE, + InitTestObjectAPPLE, + InitFinishObjectAPPLE, + InitBindVertexArrayAPPLE, + InitDeleteVertexArraysAPPLE, + InitGenVertexArraysAPPLE, + InitIsVertexArrayAPPLE, + InitVertexArrayRangeAPPLE, + InitFlushVertexArrayRangeAPPLE, + InitVertexArrayParameteriAPPLE, + InitDrawBuffersATI, + InitProgramNamedParameter4fNV, + InitProgramNamedParameter4dNV, + InitProgramNamedParameter4fvNV, + InitProgramNamedParameter4dvNV, + InitGetProgramNamedParameterfvNV, + InitGetProgramNamedParameterdvNV, + InitVertex2hNV, + InitVertex2hvNV, + InitVertex3hNV, + InitVertex3hvNV, + InitVertex4hNV, + InitVertex4hvNV, + InitNormal3hNV, + InitNormal3hvNV, + InitColor3hNV, + InitColor3hvNV, + InitColor4hNV, + InitColor4hvNV, + InitTexCoord1hNV, + InitTexCoord1hvNV, + InitTexCoord2hNV, + InitTexCoord2hvNV, + InitTexCoord3hNV, + InitTexCoord3hvNV, + InitTexCoord4hNV, + InitTexCoord4hvNV, + InitMultiTexCoord1hNV, + InitMultiTexCoord1hvNV, + InitMultiTexCoord2hNV, + InitMultiTexCoord2hvNV, + InitMultiTexCoord3hNV, + InitMultiTexCoord3hvNV, + InitMultiTexCoord4hNV, + InitMultiTexCoord4hvNV, + InitFogCoordhNV, + InitFogCoordhvNV, + InitSecondaryColor3hNV, + InitSecondaryColor3hvNV, + InitVertexWeighthNV, + InitVertexWeighthvNV, + InitVertexAttrib1hNV, + InitVertexAttrib1hvNV, + InitVertexAttrib2hNV, + InitVertexAttrib2hvNV, + InitVertexAttrib3hNV, + InitVertexAttrib3hvNV, + InitVertexAttrib4hNV, + InitVertexAttrib4hvNV, + InitVertexAttribs1hvNV, + InitVertexAttribs2hvNV, + InitVertexAttribs3hvNV, + InitVertexAttribs4hvNV, + InitPixelDataRangeNV, + InitFlushPixelDataRangeNV, + InitPrimitiveRestartNV, + InitPrimitiveRestartIndexNV, + InitMapObjectBufferATI, + InitUnmapObjectBufferATI, + InitStencilOpSeparateATI, + InitStencilFuncSeparateATI, + InitVertexAttribArrayObjectATI, + InitGetVertexAttribArrayObjectfvATI, + InitGetVertexAttribArrayObjectivATI, + InitDepthBoundsEXT, + InitBlendEquationSeparateEXT, + InitAddSwapHintRectWIN, +#ifdef _WIN32 + InitCreateBufferRegionARB, + InitDeleteBufferRegionARB, + InitSaveBufferRegionARB, + InitRestoreBufferRegionARB, + InitGetExtensionsStringARB, + InitGetPixelFormatAttribivARB, + InitGetPixelFormatAttribfvARB, + InitChoosePixelFormatARB, + InitMakeContextCurrentARB, + InitGetCurrentReadDCARB, + InitCreatePbufferARB, + InitGetPbufferDCARB, + InitReleasePbufferDCARB, + InitDestroyPbufferARB, + InitQueryPbufferARB, + InitBindTexImageARB, + InitReleaseTexImageARB, + InitSetPbufferAttribARB, + InitCreateDisplayColorTableEXT, + InitLoadDisplayColorTableEXT, + InitBindDisplayColorTableEXT, + InitDestroyDisplayColorTableEXT, + InitGetExtensionsStringEXT, + InitMakeContextCurrentEXT, + InitGetCurrentReadDCEXT, + InitCreatePbufferEXT, + InitGetPbufferDCEXT, + InitReleasePbufferDCEXT, + InitDestroyPbufferEXT, + InitQueryPbufferEXT, + InitGetPixelFormatAttribivEXT, + InitGetPixelFormatAttribfvEXT, + InitChoosePixelFormatEXT, + InitSwapIntervalEXT, + InitGetSwapIntervalEXT, + InitAllocateMemoryNV, + InitFreeMemoryNV, + InitGetSyncValuesOML, + InitGetMscRateOML, + InitSwapBuffersMscOML, + InitSwapLayerBuffersMscOML, + InitWaitForMscOML, + InitWaitForSbcOML, + InitGetDigitalVideoParametersI3D, + InitSetDigitalVideoParametersI3D, + InitGetGammaTableParametersI3D, + InitSetGammaTableParametersI3D, + InitGetGammaTableI3D, + InitSetGammaTableI3D, + InitEnableGenlockI3D, + InitDisableGenlockI3D, + InitIsEnabledGenlockI3D, + InitGenlockSourceI3D, + InitGetGenlockSourceI3D, + InitGenlockSourceEdgeI3D, + InitGetGenlockSourceEdgeI3D, + InitGenlockSampleRateI3D, + InitGetGenlockSampleRateI3D, + InitGenlockSourceDelayI3D, + InitGetGenlockSourceDelayI3D, + InitQueryGenlockMaxSourceDelayI3D, + InitCreateImageBufferI3D, + InitDestroyImageBufferI3D, + InitAssociateImageBufferEventsI3D, + InitReleaseImageBufferEventsI3D, + InitEnableFrameLockI3D, + InitDisableFrameLockI3D, + InitIsEnabledFrameLockI3D, + InitQueryFrameLockMasterI3D, + InitGetFrameUsageI3D, + InitBeginFrameTrackingI3D, + InitEndFrameTrackingI3D, + InitQueryFrameTrackingI3D, +#endif /* _WIN32 */ +}; diff --git a/plugins/zerogs/opengl/glprocs.h b/plugins/zerogs/opengl/glprocs.h new file mode 100644 index 0000000000..c40e5bdc0f --- /dev/null +++ b/plugins/zerogs/opengl/glprocs.h @@ -0,0 +1,2213 @@ +#ifndef _GLPROCS_H_ +#define _GLPROCS_H_ + +/* +** GLprocs utility for getting function addresses for OpenGL(R) 1.2, +** OpenGL 1.3, OpenGL 1.4, OpenGL 1.5 and OpenGL extension functions. +** +** Version: 1.1 +** +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.1 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: This software was created using the +** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has +** not been independently verified as being compliant with the OpenGL(R) +** version 1.2.1 Specification. +** +** Initial version of glprocs.{c,h} contributed by Intel(R) Corporation. +*/ + +#ifdef _WIN32 + #include + #include +#else + #include +#endif + +#ifndef _WIN32 /* non-Windows environment */ + #ifndef APIENTRY + #define APIENTRY + #endif + #ifdef __GNUC__ + #define _inline __inline__ + #else + #define _inline + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure of all OpenGL {1.2, 1.3, 1.4, 1.5}, GL extension procs.*/ + +typedef struct { + void (APIENTRY *BlendColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY *BlendEquation) (GLenum mode); + void (APIENTRY *DrawRangeElements) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); + void (APIENTRY *ColorTable) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); + void (APIENTRY *ColorTableParameterfv) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ColorTableParameteriv) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyColorTable) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *GetColorTable) (GLenum target, GLenum format, GLenum type, GLvoid *table); + void (APIENTRY *GetColorTableParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetColorTableParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *ColorSubTable) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); + void (APIENTRY *CopyColorSubTable) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); + void (APIENTRY *ConvolutionFilter1D) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionFilter2D) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionParameterf) (GLenum target, GLenum pname, GLfloat params); + void (APIENTRY *ConvolutionParameterfv) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ConvolutionParameteri) (GLenum target, GLenum pname, GLint params); + void (APIENTRY *ConvolutionParameteriv) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyConvolutionFilter1D) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *CopyConvolutionFilter2D) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *GetConvolutionFilter) (GLenum target, GLenum format, GLenum type, GLvoid *image); + void (APIENTRY *GetConvolutionParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetConvolutionParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetSeparableFilter) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); + void (APIENTRY *SeparableFilter2D) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); + void (APIENTRY *GetHistogram) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetHistogramParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetHistogramParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetMinmax) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetMinmaxParameterfv) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetMinmaxParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *Histogram) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); + void (APIENTRY *Minmax) (GLenum target, GLenum internalformat, GLboolean sink); + void (APIENTRY *ResetHistogram) (GLenum target); + void (APIENTRY *ResetMinmax) (GLenum target); + void (APIENTRY *TexImage3D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *CopyTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *ActiveTexture) (GLenum texture); + void (APIENTRY *ClientActiveTexture) (GLenum texture); + void (APIENTRY *MultiTexCoord1d) (GLenum target, GLdouble s); + void (APIENTRY *MultiTexCoord1dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord1f) (GLenum target, GLfloat s); + void (APIENTRY *MultiTexCoord1fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord1i) (GLenum target, GLint s); + void (APIENTRY *MultiTexCoord1iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord1s) (GLenum target, GLshort s); + void (APIENTRY *MultiTexCoord1sv) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord2d) (GLenum target, GLdouble s, GLdouble t); + void (APIENTRY *MultiTexCoord2dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord2f) (GLenum target, GLfloat s, GLfloat t); + void (APIENTRY *MultiTexCoord2fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord2i) (GLenum target, GLint s, GLint t); + void (APIENTRY *MultiTexCoord2iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord2s) (GLenum target, GLshort s, GLshort t); + void (APIENTRY *MultiTexCoord2sv) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord3d) (GLenum target, GLdouble s, GLdouble t, GLdouble r); + void (APIENTRY *MultiTexCoord3dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord3f) (GLenum target, GLfloat s, GLfloat t, GLfloat r); + void (APIENTRY *MultiTexCoord3fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord3i) (GLenum target, GLint s, GLint t, GLint r); + void (APIENTRY *MultiTexCoord3iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord3s) (GLenum target, GLshort s, GLshort t, GLshort r); + void (APIENTRY *MultiTexCoord3sv) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord4d) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); + void (APIENTRY *MultiTexCoord4dv) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord4f) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); + void (APIENTRY *MultiTexCoord4fv) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord4i) (GLenum target, GLint s, GLint t, GLint r, GLint q); + void (APIENTRY *MultiTexCoord4iv) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord4s) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); + void (APIENTRY *MultiTexCoord4sv) (GLenum target, const GLshort *v); + void (APIENTRY *LoadTransposeMatrixf) (const GLfloat *m); + void (APIENTRY *LoadTransposeMatrixd) (const GLdouble *m); + void (APIENTRY *MultTransposeMatrixf) (const GLfloat *m); + void (APIENTRY *MultTransposeMatrixd) (const GLdouble *m); + void (APIENTRY *SampleCoverage) (GLclampf value, GLboolean invert); + void (APIENTRY *CompressedTexImage3D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage1D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage3D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *GetCompressedTexImage) (GLenum target, GLint level, GLvoid *img); + void (APIENTRY *BlendFuncSeparate) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); + void (APIENTRY *FogCoordf) (GLfloat coord); + void (APIENTRY *FogCoordfv) (const GLfloat *coord); + void (APIENTRY *FogCoordd) (GLdouble coord); + void (APIENTRY *FogCoorddv) (const GLdouble *coord); + void (APIENTRY *FogCoordPointer) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *MultiDrawArrays) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); + void (APIENTRY *MultiDrawElements) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); + void (APIENTRY *PointParameterf) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfv) (GLenum pname, const GLfloat *params); + void (APIENTRY *PointParameteri) (GLenum pname, GLint param); + void (APIENTRY *PointParameteriv) (GLenum pname, const GLint *params); + void (APIENTRY *SecondaryColor3b) (GLbyte red, GLbyte green, GLbyte blue); + void (APIENTRY *SecondaryColor3bv) (const GLbyte *v); + void (APIENTRY *SecondaryColor3d) (GLdouble red, GLdouble green, GLdouble blue); + void (APIENTRY *SecondaryColor3dv) (const GLdouble *v); + void (APIENTRY *SecondaryColor3f) (GLfloat red, GLfloat green, GLfloat blue); + void (APIENTRY *SecondaryColor3fv) (const GLfloat *v); + void (APIENTRY *SecondaryColor3i) (GLint red, GLint green, GLint blue); + void (APIENTRY *SecondaryColor3iv) (const GLint *v); + void (APIENTRY *SecondaryColor3s) (GLshort red, GLshort green, GLshort blue); + void (APIENTRY *SecondaryColor3sv) (const GLshort *v); + void (APIENTRY *SecondaryColor3ub) (GLubyte red, GLubyte green, GLubyte blue); + void (APIENTRY *SecondaryColor3ubv) (const GLubyte *v); + void (APIENTRY *SecondaryColor3ui) (GLuint red, GLuint green, GLuint blue); + void (APIENTRY *SecondaryColor3uiv) (const GLuint *v); + void (APIENTRY *SecondaryColor3us) (GLushort red, GLushort green, GLushort blue); + void (APIENTRY *SecondaryColor3usv) (const GLushort *v); + void (APIENTRY *SecondaryColorPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *WindowPos2d) (GLdouble x, GLdouble y); + void (APIENTRY *WindowPos2dv) (const GLdouble *v); + void (APIENTRY *WindowPos2f) (GLfloat x, GLfloat y); + void (APIENTRY *WindowPos2fv) (const GLfloat *v); + void (APIENTRY *WindowPos2i) (GLint x, GLint y); + void (APIENTRY *WindowPos2iv) (const GLint *v); + void (APIENTRY *WindowPos2s) (GLshort x, GLshort y); + void (APIENTRY *WindowPos2sv) (const GLshort *v); + void (APIENTRY *WindowPos3d) (GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *WindowPos3dv) (const GLdouble *v); + void (APIENTRY *WindowPos3f) (GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *WindowPos3fv) (const GLfloat *v); + void (APIENTRY *WindowPos3i) (GLint x, GLint y, GLint z); + void (APIENTRY *WindowPos3iv) (const GLint *v); + void (APIENTRY *WindowPos3s) (GLshort x, GLshort y, GLshort z); + void (APIENTRY *WindowPos3sv) (const GLshort *v); + void (APIENTRY *GenQueries) (GLsizei n, GLuint *ids); + void (APIENTRY *DeleteQueries) (GLsizei n, const GLuint *ids); + GLboolean (APIENTRY *IsQuery) (GLuint id); + void (APIENTRY *BeginQuery) (GLenum target, GLuint id); + void (APIENTRY *EndQuery) (GLenum target); + void (APIENTRY *GetQueryiv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectiv) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectuiv) (GLuint id, GLenum pname, GLuint *params); + void (APIENTRY *BindBuffer) (GLenum target, GLuint buffer); + void (APIENTRY *DeleteBuffers) (GLsizei n, const GLuint *buffers); + void (APIENTRY *GenBuffers) (GLsizei n, GLuint *buffers); + GLboolean (APIENTRY *IsBuffer) (GLuint buffer); + void (APIENTRY *BufferData) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); + void (APIENTRY *BufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); + void (APIENTRY *GetBufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); + GLvoid* (APIENTRY *MapBuffer) (GLenum target, GLenum access); + GLboolean (APIENTRY *UnmapBuffer) (GLenum target); + void (APIENTRY *GetBufferParameteriv) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetBufferPointerv) (GLenum target, GLenum pname, GLvoid* *params); + void (APIENTRY *ActiveTextureARB) (GLenum texture); + void (APIENTRY *ClientActiveTextureARB) (GLenum texture); + void (APIENTRY *MultiTexCoord1dARB) (GLenum target, GLdouble s); + void (APIENTRY *MultiTexCoord1dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord1fARB) (GLenum target, GLfloat s); + void (APIENTRY *MultiTexCoord1fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord1iARB) (GLenum target, GLint s); + void (APIENTRY *MultiTexCoord1ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord1sARB) (GLenum target, GLshort s); + void (APIENTRY *MultiTexCoord1svARB) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord2dARB) (GLenum target, GLdouble s, GLdouble t); + void (APIENTRY *MultiTexCoord2dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t); + void (APIENTRY *MultiTexCoord2fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord2iARB) (GLenum target, GLint s, GLint t); + void (APIENTRY *MultiTexCoord2ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord2sARB) (GLenum target, GLshort s, GLshort t); + void (APIENTRY *MultiTexCoord2svARB) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord3dARB) (GLenum target, GLdouble s, GLdouble t, GLdouble r); + void (APIENTRY *MultiTexCoord3dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord3fARB) (GLenum target, GLfloat s, GLfloat t, GLfloat r); + void (APIENTRY *MultiTexCoord3fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord3iARB) (GLenum target, GLint s, GLint t, GLint r); + void (APIENTRY *MultiTexCoord3ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord3sARB) (GLenum target, GLshort s, GLshort t, GLshort r); + void (APIENTRY *MultiTexCoord3svARB) (GLenum target, const GLshort *v); + void (APIENTRY *MultiTexCoord4dARB) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); + void (APIENTRY *MultiTexCoord4dvARB) (GLenum target, const GLdouble *v); + void (APIENTRY *MultiTexCoord4fARB) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); + void (APIENTRY *MultiTexCoord4fvARB) (GLenum target, const GLfloat *v); + void (APIENTRY *MultiTexCoord4iARB) (GLenum target, GLint s, GLint t, GLint r, GLint q); + void (APIENTRY *MultiTexCoord4ivARB) (GLenum target, const GLint *v); + void (APIENTRY *MultiTexCoord4sARB) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); + void (APIENTRY *MultiTexCoord4svARB) (GLenum target, const GLshort *v); + void (APIENTRY *LoadTransposeMatrixfARB) (const GLfloat *m); + void (APIENTRY *LoadTransposeMatrixdARB) (const GLdouble *m); + void (APIENTRY *MultTransposeMatrixfARB) (const GLfloat *m); + void (APIENTRY *MultTransposeMatrixdARB) (const GLdouble *m); + void (APIENTRY *SampleCoverageARB) (GLclampf value, GLboolean invert); + void (APIENTRY *CompressedTexImage3DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage2DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexImage1DARB) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage3DARB) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage2DARB) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *CompressedTexSubImage1DARB) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); + void (APIENTRY *GetCompressedTexImageARB) (GLenum target, GLint level, GLvoid *img); + void (APIENTRY *PointParameterfARB) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfvARB) (GLenum pname, const GLfloat *params); + void (APIENTRY *WeightbvARB) (GLint size, const GLbyte *weights); + void (APIENTRY *WeightsvARB) (GLint size, const GLshort *weights); + void (APIENTRY *WeightivARB) (GLint size, const GLint *weights); + void (APIENTRY *WeightfvARB) (GLint size, const GLfloat *weights); + void (APIENTRY *WeightdvARB) (GLint size, const GLdouble *weights); + void (APIENTRY *WeightubvARB) (GLint size, const GLubyte *weights); + void (APIENTRY *WeightusvARB) (GLint size, const GLushort *weights); + void (APIENTRY *WeightuivARB) (GLint size, const GLuint *weights); + void (APIENTRY *WeightPointerARB) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *VertexBlendARB) (GLint count); + void (APIENTRY *CurrentPaletteMatrixARB) (GLint index); + void (APIENTRY *MatrixIndexubvARB) (GLint size, const GLubyte *indices); + void (APIENTRY *MatrixIndexusvARB) (GLint size, const GLushort *indices); + void (APIENTRY *MatrixIndexuivARB) (GLint size, const GLuint *indices); + void (APIENTRY *MatrixIndexPointerARB) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *WindowPos2dARB) (GLdouble x, GLdouble y); + void (APIENTRY *WindowPos2dvARB) (const GLdouble *v); + void (APIENTRY *WindowPos2fARB) (GLfloat x, GLfloat y); + void (APIENTRY *WindowPos2fvARB) (const GLfloat *v); + void (APIENTRY *WindowPos2iARB) (GLint x, GLint y); + void (APIENTRY *WindowPos2ivARB) (const GLint *v); + void (APIENTRY *WindowPos2sARB) (GLshort x, GLshort y); + void (APIENTRY *WindowPos2svARB) (const GLshort *v); + void (APIENTRY *WindowPos3dARB) (GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *WindowPos3dvARB) (const GLdouble *v); + void (APIENTRY *WindowPos3fARB) (GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *WindowPos3fvARB) (const GLfloat *v); + void (APIENTRY *WindowPos3iARB) (GLint x, GLint y, GLint z); + void (APIENTRY *WindowPos3ivARB) (const GLint *v); + void (APIENTRY *WindowPos3sARB) (GLshort x, GLshort y, GLshort z); + void (APIENTRY *WindowPos3svARB) (const GLshort *v); + void (APIENTRY *VertexAttrib1dARB) (GLuint index, GLdouble x); + void (APIENTRY *VertexAttrib1dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib1fARB) (GLuint index, GLfloat x); + void (APIENTRY *VertexAttrib1fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib1sARB) (GLuint index, GLshort x); + void (APIENTRY *VertexAttrib1svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib2dARB) (GLuint index, GLdouble x, GLdouble y); + void (APIENTRY *VertexAttrib2dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib2fARB) (GLuint index, GLfloat x, GLfloat y); + void (APIENTRY *VertexAttrib2fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib2sARB) (GLuint index, GLshort x, GLshort y); + void (APIENTRY *VertexAttrib2svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib3dARB) (GLuint index, GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *VertexAttrib3dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib3fARB) (GLuint index, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *VertexAttrib3fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib3sARB) (GLuint index, GLshort x, GLshort y, GLshort z); + void (APIENTRY *VertexAttrib3svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4NbvARB) (GLuint index, const GLbyte *v); + void (APIENTRY *VertexAttrib4NivARB) (GLuint index, const GLint *v); + void (APIENTRY *VertexAttrib4NsvARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4NubARB) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); + void (APIENTRY *VertexAttrib4NubvARB) (GLuint index, const GLubyte *v); + void (APIENTRY *VertexAttrib4NuivARB) (GLuint index, const GLuint *v); + void (APIENTRY *VertexAttrib4NusvARB) (GLuint index, const GLushort *v); + void (APIENTRY *VertexAttrib4bvARB) (GLuint index, const GLbyte *v); + void (APIENTRY *VertexAttrib4dARB) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *VertexAttrib4dvARB) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib4fARB) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *VertexAttrib4fvARB) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib4ivARB) (GLuint index, const GLint *v); + void (APIENTRY *VertexAttrib4sARB) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *VertexAttrib4svARB) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4ubvARB) (GLuint index, const GLubyte *v); + void (APIENTRY *VertexAttrib4uivARB) (GLuint index, const GLuint *v); + void (APIENTRY *VertexAttrib4usvARB) (GLuint index, const GLushort *v); + void (APIENTRY *VertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *EnableVertexAttribArrayARB) (GLuint index); + void (APIENTRY *DisableVertexAttribArrayARB) (GLuint index); + void (APIENTRY *ProgramStringARB) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); + void (APIENTRY *BindProgramARB) (GLenum target, GLuint program); + void (APIENTRY *DeleteProgramsARB) (GLsizei n, const GLuint *programs); + void (APIENTRY *GenProgramsARB) (GLsizei n, GLuint *programs); + void (APIENTRY *ProgramEnvParameter4dARB) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramEnvParameter4dvARB) (GLenum target, GLuint index, const GLdouble *params); + void (APIENTRY *ProgramEnvParameter4fARB) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramEnvParameter4fvARB) (GLenum target, GLuint index, const GLfloat *params); + void (APIENTRY *ProgramLocalParameter4dARB) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramLocalParameter4dvARB) (GLenum target, GLuint index, const GLdouble *params); + void (APIENTRY *ProgramLocalParameter4fARB) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramLocalParameter4fvARB) (GLenum target, GLuint index, const GLfloat *params); + void (APIENTRY *GetProgramEnvParameterdvARB) (GLenum target, GLuint index, GLdouble *params); + void (APIENTRY *GetProgramEnvParameterfvARB) (GLenum target, GLuint index, GLfloat *params); + void (APIENTRY *GetProgramLocalParameterdvARB) (GLenum target, GLuint index, GLdouble *params); + void (APIENTRY *GetProgramLocalParameterfvARB) (GLenum target, GLuint index, GLfloat *params); + void (APIENTRY *GetProgramivARB) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetProgramStringARB) (GLenum target, GLenum pname, GLvoid *string); + void (APIENTRY *GetVertexAttribdvARB) (GLuint index, GLenum pname, GLdouble *params); + void (APIENTRY *GetVertexAttribfvARB) (GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetVertexAttribivARB) (GLuint index, GLenum pname, GLint *params); + void (APIENTRY *GetVertexAttribPointervARB) (GLuint index, GLenum pname, GLvoid* *pointer); + GLboolean (APIENTRY *IsProgramARB) (GLuint program); + void (APIENTRY *BindBufferARB) (GLenum target, GLuint buffer); + void (APIENTRY *DeleteBuffersARB) (GLsizei n, const GLuint *buffers); + void (APIENTRY *GenBuffersARB) (GLsizei n, GLuint *buffers); + GLboolean (APIENTRY *IsBufferARB) (GLuint buffer); + void (APIENTRY *BufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); + void (APIENTRY *BufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); + void (APIENTRY *GetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); + GLvoid* (APIENTRY *MapBufferARB) (GLenum target, GLenum access); + GLboolean (APIENTRY *UnmapBufferARB) (GLenum target); + void (APIENTRY *GetBufferParameterivARB) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetBufferPointervARB) (GLenum target, GLenum pname, GLvoid* *params); + void (APIENTRY *GenQueriesARB) (GLsizei n, GLuint *ids); + void (APIENTRY *DeleteQueriesARB) (GLsizei n, const GLuint *ids); + GLboolean (APIENTRY *IsQueryARB) (GLuint id); + void (APIENTRY *BeginQueryARB) (GLenum target, GLuint id); + void (APIENTRY *EndQueryARB) (GLenum target); + void (APIENTRY *GetQueryivARB) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectivARB) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetQueryObjectuivARB) (GLuint id, GLenum pname, GLuint *params); + void (APIENTRY *DeleteObjectARB) (GLhandleARB obj); + GLhandleARB (APIENTRY *GetHandleARB) (GLenum pname); + void (APIENTRY *DetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj); + GLhandleARB (APIENTRY *CreateShaderObjectARB) (GLenum shaderType); + void (APIENTRY *ShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); + void (APIENTRY *CompileShaderARB) (GLhandleARB shaderObj); + GLhandleARB (APIENTRY *CreateProgramObjectARB) (void); + void (APIENTRY *AttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj); + void (APIENTRY *LinkProgramARB) (GLhandleARB programObj); + void (APIENTRY *UseProgramObjectARB) (GLhandleARB programObj); + void (APIENTRY *ValidateProgramARB) (GLhandleARB programObj); + void (APIENTRY *Uniform1fARB) (GLint location, GLfloat v0); + void (APIENTRY *Uniform2fARB) (GLint location, GLfloat v0, GLfloat v1); + void (APIENTRY *Uniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); + void (APIENTRY *Uniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); + void (APIENTRY *Uniform1iARB) (GLint location, GLint v0); + void (APIENTRY *Uniform2iARB) (GLint location, GLint v0, GLint v1); + void (APIENTRY *Uniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2); + void (APIENTRY *Uniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); + void (APIENTRY *Uniform1fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform2fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform3fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform4fvARB) (GLint location, GLsizei count, const GLfloat *value); + void (APIENTRY *Uniform1ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *Uniform2ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *Uniform3ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *Uniform4ivARB) (GLint location, GLsizei count, const GLint *value); + void (APIENTRY *UniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void (APIENTRY *UniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void (APIENTRY *UniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void (APIENTRY *GetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat *params); + void (APIENTRY *GetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint *params); + void (APIENTRY *GetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); + void (APIENTRY *GetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); + GLint (APIENTRY *GetUniformLocationARB) (GLhandleARB programObj, const GLcharARB *name); + void (APIENTRY *GetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); + void (APIENTRY *GetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat *params); + void (APIENTRY *GetUniformivARB) (GLhandleARB programObj, GLint location, GLint *params); + void (APIENTRY *GetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); + void (APIENTRY *BindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB *name); + void (APIENTRY *GetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); + GLint (APIENTRY *GetAttribLocationARB) (GLhandleARB programObj, const GLcharARB *name); + void (APIENTRY *BlendColorEXT) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY *PolygonOffsetEXT) (GLfloat factor, GLfloat bias); + void (APIENTRY *TexImage3DEXT) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage3DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *GetTexFilterFuncSGIS) (GLenum target, GLenum filter, GLfloat *weights); + void (APIENTRY *TexFilterFuncSGIS) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); + void (APIENTRY *TexSubImage1DEXT) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage2DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *CopyTexImage1DEXT) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); + void (APIENTRY *CopyTexImage2DEXT) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); + void (APIENTRY *CopyTexSubImage1DEXT) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); + void (APIENTRY *CopyTexSubImage2DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *CopyTexSubImage3DEXT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *GetHistogramEXT) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetHistogramParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetHistogramParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetMinmaxEXT) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); + void (APIENTRY *GetMinmaxParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetMinmaxParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *HistogramEXT) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); + void (APIENTRY *MinmaxEXT) (GLenum target, GLenum internalformat, GLboolean sink); + void (APIENTRY *ResetHistogramEXT) (GLenum target); + void (APIENTRY *ResetMinmaxEXT) (GLenum target); + void (APIENTRY *ConvolutionFilter1DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionFilter2DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); + void (APIENTRY *ConvolutionParameterfEXT) (GLenum target, GLenum pname, GLfloat params); + void (APIENTRY *ConvolutionParameterfvEXT) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ConvolutionParameteriEXT) (GLenum target, GLenum pname, GLint params); + void (APIENTRY *ConvolutionParameterivEXT) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyConvolutionFilter1DEXT) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *CopyConvolutionFilter2DEXT) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY *GetConvolutionFilterEXT) (GLenum target, GLenum format, GLenum type, GLvoid *image); + void (APIENTRY *GetConvolutionParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetConvolutionParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetSeparableFilterEXT) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); + void (APIENTRY *SeparableFilter2DEXT) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); + void (APIENTRY *ColorTableSGI) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); + void (APIENTRY *ColorTableParameterfvSGI) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *ColorTableParameterivSGI) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *CopyColorTableSGI) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); + void (APIENTRY *GetColorTableSGI) (GLenum target, GLenum format, GLenum type, GLvoid *table); + void (APIENTRY *GetColorTableParameterfvSGI) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetColorTableParameterivSGI) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *PixelTexGenSGIX) (GLenum mode); + void (APIENTRY *PixelTexGenParameteriSGIS) (GLenum pname, GLint param); + void (APIENTRY *PixelTexGenParameterivSGIS) (GLenum pname, const GLint *params); + void (APIENTRY *PixelTexGenParameterfSGIS) (GLenum pname, GLfloat param); + void (APIENTRY *PixelTexGenParameterfvSGIS) (GLenum pname, const GLfloat *params); + void (APIENTRY *GetPixelTexGenParameterivSGIS) (GLenum pname, GLint *params); + void (APIENTRY *GetPixelTexGenParameterfvSGIS) (GLenum pname, GLfloat *params); + void (APIENTRY *TexImage4DSGIS) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY *TexSubImage4DSGIS) (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 GLvoid *pixels); + GLboolean (APIENTRY *AreTexturesResidentEXT) (GLsizei n, const GLuint *textures, GLboolean *residences); + void (APIENTRY *BindTextureEXT) (GLenum target, GLuint texture); + void (APIENTRY *DeleteTexturesEXT) (GLsizei n, const GLuint *textures); + void (APIENTRY *GenTexturesEXT) (GLsizei n, GLuint *textures); + GLboolean (APIENTRY *IsTextureEXT) (GLuint texture); + void (APIENTRY *PrioritizeTexturesEXT) (GLsizei n, const GLuint *textures, const GLclampf *priorities); + void (APIENTRY *DetailTexFuncSGIS) (GLenum target, GLsizei n, const GLfloat *points); + void (APIENTRY *GetDetailTexFuncSGIS) (GLenum target, GLfloat *points); + void (APIENTRY *SharpenTexFuncSGIS) (GLenum target, GLsizei n, const GLfloat *points); + void (APIENTRY *GetSharpenTexFuncSGIS) (GLenum target, GLfloat *points); + void (APIENTRY *SampleMaskSGIS) (GLclampf value, GLboolean invert); + void (APIENTRY *SamplePatternSGIS) (GLenum pattern); + void (APIENTRY *ArrayElementEXT) (GLint i); + void (APIENTRY *ColorPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *DrawArraysEXT) (GLenum mode, GLint first, GLsizei count); + void (APIENTRY *EdgeFlagPointerEXT) (GLsizei stride, GLsizei count, const GLboolean *pointer); + void (APIENTRY *GetPointervEXT) (GLenum pname, GLvoid* *params); + void (APIENTRY *IndexPointerEXT) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *NormalPointerEXT) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *TexCoordPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *VertexPointerEXT) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + void (APIENTRY *BlendEquationEXT) (GLenum mode); + void (APIENTRY *SpriteParameterfSGIX) (GLenum pname, GLfloat param); + void (APIENTRY *SpriteParameterfvSGIX) (GLenum pname, const GLfloat *params); + void (APIENTRY *SpriteParameteriSGIX) (GLenum pname, GLint param); + void (APIENTRY *SpriteParameterivSGIX) (GLenum pname, const GLint *params); + void (APIENTRY *PointParameterfEXT) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfvEXT) (GLenum pname, const GLfloat *params); + void (APIENTRY *PointParameterfSGIS) (GLenum pname, GLfloat param); + void (APIENTRY *PointParameterfvSGIS) (GLenum pname, const GLfloat *params); + GLint (APIENTRY *GetInstrumentsSGIX) (void); + void (APIENTRY *InstrumentsBufferSGIX) (GLsizei size, GLint *buffer); + GLint (APIENTRY *PollInstrumentsSGIX) (GLint *marker_p); + void (APIENTRY *ReadInstrumentsSGIX) (GLint marker); + void (APIENTRY *StartInstrumentsSGIX) (void); + void (APIENTRY *StopInstrumentsSGIX) (GLint marker); + void (APIENTRY *FrameZoomSGIX) (GLint factor); + void (APIENTRY *TagSampleBufferSGIX) (void); + void (APIENTRY *DeformationMap3dSGIX) (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); + void (APIENTRY *DeformationMap3fSGIX) (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); + void (APIENTRY *DeformSGIX) (GLbitfield mask); + void (APIENTRY *LoadIdentityDeformationMapSGIX) (GLbitfield mask); + void (APIENTRY *ReferencePlaneSGIX) (const GLdouble *equation); + void (APIENTRY *FlushRasterSGIX) (void); + void (APIENTRY *FogFuncSGIS) (GLsizei n, const GLfloat *points); + void (APIENTRY *GetFogFuncSGIS) (GLfloat *points); + void (APIENTRY *ImageTransformParameteriHP) (GLenum target, GLenum pname, GLint param); + void (APIENTRY *ImageTransformParameterfHP) (GLenum target, GLenum pname, GLfloat param); + void (APIENTRY *ImageTransformParameterivHP) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *ImageTransformParameterfvHP) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *GetImageTransformParameterivHP) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetImageTransformParameterfvHP) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *ColorSubTableEXT) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); + void (APIENTRY *CopyColorSubTableEXT) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); + void (APIENTRY *HintPGI) (GLenum target, GLint mode); + void (APIENTRY *ColorTableEXT) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); + void (APIENTRY *GetColorTableEXT) (GLenum target, GLenum format, GLenum type, GLvoid *data); + void (APIENTRY *GetColorTableParameterivEXT) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetColorTableParameterfvEXT) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetListParameterfvSGIX) (GLuint list, GLenum pname, GLfloat *params); + void (APIENTRY *GetListParameterivSGIX) (GLuint list, GLenum pname, GLint *params); + void (APIENTRY *ListParameterfSGIX) (GLuint list, GLenum pname, GLfloat param); + void (APIENTRY *ListParameterfvSGIX) (GLuint list, GLenum pname, const GLfloat *params); + void (APIENTRY *ListParameteriSGIX) (GLuint list, GLenum pname, GLint param); + void (APIENTRY *ListParameterivSGIX) (GLuint list, GLenum pname, const GLint *params); + void (APIENTRY *IndexMaterialEXT) (GLenum face, GLenum mode); + void (APIENTRY *IndexFuncEXT) (GLenum func, GLclampf ref); + void (APIENTRY *LockArraysEXT) (GLint first, GLsizei count); + void (APIENTRY *UnlockArraysEXT) (void); + void (APIENTRY *CullParameterdvEXT) (GLenum pname, GLdouble *params); + void (APIENTRY *CullParameterfvEXT) (GLenum pname, GLfloat *params); + void (APIENTRY *FragmentColorMaterialSGIX) (GLenum face, GLenum mode); + void (APIENTRY *FragmentLightfSGIX) (GLenum light, GLenum pname, GLfloat param); + void (APIENTRY *FragmentLightfvSGIX) (GLenum light, GLenum pname, const GLfloat *params); + void (APIENTRY *FragmentLightiSGIX) (GLenum light, GLenum pname, GLint param); + void (APIENTRY *FragmentLightivSGIX) (GLenum light, GLenum pname, const GLint *params); + void (APIENTRY *FragmentLightModelfSGIX) (GLenum pname, GLfloat param); + void (APIENTRY *FragmentLightModelfvSGIX) (GLenum pname, const GLfloat *params); + void (APIENTRY *FragmentLightModeliSGIX) (GLenum pname, GLint param); + void (APIENTRY *FragmentLightModelivSGIX) (GLenum pname, const GLint *params); + void (APIENTRY *FragmentMaterialfSGIX) (GLenum face, GLenum pname, GLfloat param); + void (APIENTRY *FragmentMaterialfvSGIX) (GLenum face, GLenum pname, const GLfloat *params); + void (APIENTRY *FragmentMaterialiSGIX) (GLenum face, GLenum pname, GLint param); + void (APIENTRY *FragmentMaterialivSGIX) (GLenum face, GLenum pname, const GLint *params); + void (APIENTRY *GetFragmentLightfvSGIX) (GLenum light, GLenum pname, GLfloat *params); + void (APIENTRY *GetFragmentLightivSGIX) (GLenum light, GLenum pname, GLint *params); + void (APIENTRY *GetFragmentMaterialfvSGIX) (GLenum face, GLenum pname, GLfloat *params); + void (APIENTRY *GetFragmentMaterialivSGIX) (GLenum face, GLenum pname, GLint *params); + void (APIENTRY *LightEnviSGIX) (GLenum pname, GLint param); + void (APIENTRY *DrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); + void (APIENTRY *ApplyTextureEXT) (GLenum mode); + void (APIENTRY *TextureLightEXT) (GLenum pname); + void (APIENTRY *TextureMaterialEXT) (GLenum face, GLenum mode); + void (APIENTRY *AsyncMarkerSGIX) (GLuint marker); + GLint (APIENTRY *FinishAsyncSGIX) (GLuint *markerp); + GLint (APIENTRY *PollAsyncSGIX) (GLuint *markerp); + GLuint (APIENTRY *GenAsyncMarkersSGIX) (GLsizei range); + void (APIENTRY *DeleteAsyncMarkersSGIX) (GLuint marker, GLsizei range); + GLboolean (APIENTRY *IsAsyncMarkerSGIX) (GLuint marker); + void (APIENTRY *VertexPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); + void (APIENTRY *NormalPointervINTEL) (GLenum type, const GLvoid* *pointer); + void (APIENTRY *ColorPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); + void (APIENTRY *TexCoordPointervINTEL) (GLint size, GLenum type, const GLvoid* *pointer); + void (APIENTRY *PixelTransformParameteriEXT) (GLenum target, GLenum pname, GLint param); + void (APIENTRY *PixelTransformParameterfEXT) (GLenum target, GLenum pname, GLfloat param); + void (APIENTRY *PixelTransformParameterivEXT) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *PixelTransformParameterfvEXT) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *SecondaryColor3bEXT) (GLbyte red, GLbyte green, GLbyte blue); + void (APIENTRY *SecondaryColor3bvEXT) (const GLbyte *v); + void (APIENTRY *SecondaryColor3dEXT) (GLdouble red, GLdouble green, GLdouble blue); + void (APIENTRY *SecondaryColor3dvEXT) (const GLdouble *v); + void (APIENTRY *SecondaryColor3fEXT) (GLfloat red, GLfloat green, GLfloat blue); + void (APIENTRY *SecondaryColor3fvEXT) (const GLfloat *v); + void (APIENTRY *SecondaryColor3iEXT) (GLint red, GLint green, GLint blue); + void (APIENTRY *SecondaryColor3ivEXT) (const GLint *v); + void (APIENTRY *SecondaryColor3sEXT) (GLshort red, GLshort green, GLshort blue); + void (APIENTRY *SecondaryColor3svEXT) (const GLshort *v); + void (APIENTRY *SecondaryColor3ubEXT) (GLubyte red, GLubyte green, GLubyte blue); + void (APIENTRY *SecondaryColor3ubvEXT) (const GLubyte *v); + void (APIENTRY *SecondaryColor3uiEXT) (GLuint red, GLuint green, GLuint blue); + void (APIENTRY *SecondaryColor3uivEXT) (const GLuint *v); + void (APIENTRY *SecondaryColor3usEXT) (GLushort red, GLushort green, GLushort blue); + void (APIENTRY *SecondaryColor3usvEXT) (const GLushort *v); + void (APIENTRY *SecondaryColorPointerEXT) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *TextureNormalEXT) (GLenum mode); + void (APIENTRY *MultiDrawArraysEXT) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount); + void (APIENTRY *MultiDrawElementsEXT) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); + void (APIENTRY *FogCoordfEXT) (GLfloat coord); + void (APIENTRY *FogCoordfvEXT) (const GLfloat *coord); + void (APIENTRY *FogCoorddEXT) (GLdouble coord); + void (APIENTRY *FogCoorddvEXT) (const GLdouble *coord); + void (APIENTRY *FogCoordPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *Tangent3bEXT) (GLbyte tx, GLbyte ty, GLbyte tz); + void (APIENTRY *Tangent3bvEXT) (const GLbyte *v); + void (APIENTRY *Tangent3dEXT) (GLdouble tx, GLdouble ty, GLdouble tz); + void (APIENTRY *Tangent3dvEXT) (const GLdouble *v); + void (APIENTRY *Tangent3fEXT) (GLfloat tx, GLfloat ty, GLfloat tz); + void (APIENTRY *Tangent3fvEXT) (const GLfloat *v); + void (APIENTRY *Tangent3iEXT) (GLint tx, GLint ty, GLint tz); + void (APIENTRY *Tangent3ivEXT) (const GLint *v); + void (APIENTRY *Tangent3sEXT) (GLshort tx, GLshort ty, GLshort tz); + void (APIENTRY *Tangent3svEXT) (const GLshort *v); + void (APIENTRY *Binormal3bEXT) (GLbyte bx, GLbyte by, GLbyte bz); + void (APIENTRY *Binormal3bvEXT) (const GLbyte *v); + void (APIENTRY *Binormal3dEXT) (GLdouble bx, GLdouble by, GLdouble bz); + void (APIENTRY *Binormal3dvEXT) (const GLdouble *v); + void (APIENTRY *Binormal3fEXT) (GLfloat bx, GLfloat by, GLfloat bz); + void (APIENTRY *Binormal3fvEXT) (const GLfloat *v); + void (APIENTRY *Binormal3iEXT) (GLint bx, GLint by, GLint bz); + void (APIENTRY *Binormal3ivEXT) (const GLint *v); + void (APIENTRY *Binormal3sEXT) (GLshort bx, GLshort by, GLshort bz); + void (APIENTRY *Binormal3svEXT) (const GLshort *v); + void (APIENTRY *TangentPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *BinormalPointerEXT) (GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *FinishTextureSUNX) (void); + void (APIENTRY *GlobalAlphaFactorbSUN) (GLbyte factor); + void (APIENTRY *GlobalAlphaFactorsSUN) (GLshort factor); + void (APIENTRY *GlobalAlphaFactoriSUN) (GLint factor); + void (APIENTRY *GlobalAlphaFactorfSUN) (GLfloat factor); + void (APIENTRY *GlobalAlphaFactordSUN) (GLdouble factor); + void (APIENTRY *GlobalAlphaFactorubSUN) (GLubyte factor); + void (APIENTRY *GlobalAlphaFactorusSUN) (GLushort factor); + void (APIENTRY *GlobalAlphaFactoruiSUN) (GLuint factor); + void (APIENTRY *ReplacementCodeuiSUN) (GLuint code); + void (APIENTRY *ReplacementCodeusSUN) (GLushort code); + void (APIENTRY *ReplacementCodeubSUN) (GLubyte code); + void (APIENTRY *ReplacementCodeuivSUN) (const GLuint *code); + void (APIENTRY *ReplacementCodeusvSUN) (const GLushort *code); + void (APIENTRY *ReplacementCodeubvSUN) (const GLubyte *code); + void (APIENTRY *ReplacementCodePointerSUN) (GLenum type, GLsizei stride, const GLvoid* *pointer); + void (APIENTRY *Color4ubVertex2fSUN) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); + void (APIENTRY *Color4ubVertex2fvSUN) (const GLubyte *c, const GLfloat *v); + void (APIENTRY *Color4ubVertex3fSUN) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Color4ubVertex3fvSUN) (const GLubyte *c, const GLfloat *v); + void (APIENTRY *Color3fVertex3fSUN) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Color3fVertex3fvSUN) (const GLfloat *c, const GLfloat *v); + void (APIENTRY *Normal3fVertex3fSUN) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Normal3fVertex3fvSUN) (const GLfloat *n, const GLfloat *v); + void (APIENTRY *Color4fNormal3fVertex3fSUN) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *Color4fNormal3fVertex3fvSUN) (const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *TexCoord2fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fVertex3fvSUN) (const GLfloat *tc, const GLfloat *v); + void (APIENTRY *TexCoord4fVertex4fSUN) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *TexCoord4fVertex4fvSUN) (const GLfloat *tc, const GLfloat *v); + void (APIENTRY *TexCoord2fColor4ubVertex3fSUN) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fColor4ubVertex3fvSUN) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); + void (APIENTRY *TexCoord2fColor3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fColor3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); + void (APIENTRY *TexCoord2fNormal3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fNormal3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); + void (APIENTRY *TexCoord2fColor4fNormal3fVertex3fSUN) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *TexCoord2fColor4fNormal3fVertex3fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *TexCoord4fColor4fNormal3fVertex4fSUN) (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); + void (APIENTRY *TexCoord4fColor4fNormal3fVertex4fvSUN) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiVertex3fSUN) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiVertex3fvSUN) (const GLuint *rc, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiColor4ubVertex3fSUN) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiColor4ubVertex3fvSUN) (const GLuint *rc, const GLubyte *c, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiColor3fVertex3fSUN) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiColor3fVertex3fvSUN) (const GLuint *rc, const GLfloat *c, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiNormal3fVertex3fSUN) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiColor4fNormal3fVertex3fSUN) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiColor4fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiTexCoord2fVertex3fSUN) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiTexCoord2fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiTexCoord2fNormal3fVertex3fSUN) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *ReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); + void (APIENTRY *ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN) (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); + void (APIENTRY *ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); + void (APIENTRY *BlendFuncSeparateEXT) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); + void (APIENTRY *BlendFuncSeparateINGR) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); + void (APIENTRY *VertexWeightfEXT) (GLfloat weight); + void (APIENTRY *VertexWeightfvEXT) (const GLfloat *weight); + void (APIENTRY *VertexWeightPointerEXT) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *FlushVertexArrayRangeNV) (void); + void (APIENTRY *VertexArrayRangeNV) (GLsizei length, const GLvoid *pointer); + void (APIENTRY *CombinerParameterfvNV) (GLenum pname, const GLfloat *params); + void (APIENTRY *CombinerParameterfNV) (GLenum pname, GLfloat param); + void (APIENTRY *CombinerParameterivNV) (GLenum pname, const GLint *params); + void (APIENTRY *CombinerParameteriNV) (GLenum pname, GLint param); + void (APIENTRY *CombinerInputNV) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); + void (APIENTRY *CombinerOutputNV) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); + void (APIENTRY *FinalCombinerInputNV) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); + void (APIENTRY *GetCombinerInputParameterfvNV) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); + void (APIENTRY *GetCombinerInputParameterivNV) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); + void (APIENTRY *GetCombinerOutputParameterfvNV) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); + void (APIENTRY *GetCombinerOutputParameterivNV) (GLenum stage, GLenum portion, GLenum pname, GLint *params); + void (APIENTRY *GetFinalCombinerInputParameterfvNV) (GLenum variable, GLenum pname, GLfloat *params); + void (APIENTRY *GetFinalCombinerInputParameterivNV) (GLenum variable, GLenum pname, GLint *params); + void (APIENTRY *ResizeBuffersMESA) (void); + void (APIENTRY *WindowPos2dMESA) (GLdouble x, GLdouble y); + void (APIENTRY *WindowPos2dvMESA) (const GLdouble *v); + void (APIENTRY *WindowPos2fMESA) (GLfloat x, GLfloat y); + void (APIENTRY *WindowPos2fvMESA) (const GLfloat *v); + void (APIENTRY *WindowPos2iMESA) (GLint x, GLint y); + void (APIENTRY *WindowPos2ivMESA) (const GLint *v); + void (APIENTRY *WindowPos2sMESA) (GLshort x, GLshort y); + void (APIENTRY *WindowPos2svMESA) (const GLshort *v); + void (APIENTRY *WindowPos3dMESA) (GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *WindowPos3dvMESA) (const GLdouble *v); + void (APIENTRY *WindowPos3fMESA) (GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *WindowPos3fvMESA) (const GLfloat *v); + void (APIENTRY *WindowPos3iMESA) (GLint x, GLint y, GLint z); + void (APIENTRY *WindowPos3ivMESA) (const GLint *v); + void (APIENTRY *WindowPos3sMESA) (GLshort x, GLshort y, GLshort z); + void (APIENTRY *WindowPos3svMESA) (const GLshort *v); + void (APIENTRY *WindowPos4dMESA) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *WindowPos4dvMESA) (const GLdouble *v); + void (APIENTRY *WindowPos4fMESA) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *WindowPos4fvMESA) (const GLfloat *v); + void (APIENTRY *WindowPos4iMESA) (GLint x, GLint y, GLint z, GLint w); + void (APIENTRY *WindowPos4ivMESA) (const GLint *v); + void (APIENTRY *WindowPos4sMESA) (GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *WindowPos4svMESA) (const GLshort *v); + void (APIENTRY *MultiModeDrawArraysIBM) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); + void (APIENTRY *MultiModeDrawElementsIBM) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); + void (APIENTRY *ColorPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *SecondaryColorPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *EdgeFlagPointerListIBM) (GLint stride, const GLboolean* *pointer, GLint ptrstride); + void (APIENTRY *FogCoordPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *IndexPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *NormalPointerListIBM) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *TexCoordPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *VertexPointerListIBM) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); + void (APIENTRY *TbufferMask3DFX) (GLuint mask); + void (APIENTRY *SampleMaskEXT) (GLclampf value, GLboolean invert); + void (APIENTRY *SamplePatternEXT) (GLenum pattern); + void (APIENTRY *TextureColorMaskSGIS) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void (APIENTRY *IglooInterfaceSGIX) (GLenum pname, const GLvoid *params); + void (APIENTRY *DeleteFencesNV) (GLsizei n, const GLuint *fences); + void (APIENTRY *GenFencesNV) (GLsizei n, GLuint *fences); + GLboolean (APIENTRY *IsFenceNV) (GLuint fence); + GLboolean (APIENTRY *TestFenceNV) (GLuint fence); + void (APIENTRY *GetFenceivNV) (GLuint fence, GLenum pname, GLint *params); + void (APIENTRY *FinishFenceNV) (GLuint fence); + void (APIENTRY *SetFenceNV) (GLuint fence, GLenum condition); + void (APIENTRY *MapControlPointsNV) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); + void (APIENTRY *MapParameterivNV) (GLenum target, GLenum pname, const GLint *params); + void (APIENTRY *MapParameterfvNV) (GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY *GetMapControlPointsNV) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); + void (APIENTRY *GetMapParameterivNV) (GLenum target, GLenum pname, GLint *params); + void (APIENTRY *GetMapParameterfvNV) (GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY *GetMapAttribParameterivNV) (GLenum target, GLuint index, GLenum pname, GLint *params); + void (APIENTRY *GetMapAttribParameterfvNV) (GLenum target, GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *EvalMapsNV) (GLenum target, GLenum mode); + void (APIENTRY *CombinerStageParameterfvNV) (GLenum stage, GLenum pname, const GLfloat *params); + void (APIENTRY *GetCombinerStageParameterfvNV) (GLenum stage, GLenum pname, GLfloat *params); + GLboolean (APIENTRY *AreProgramsResidentNV) (GLsizei n, const GLuint *programs, GLboolean *residences); + void (APIENTRY *BindProgramNV) (GLenum target, GLuint id); + void (APIENTRY *DeleteProgramsNV) (GLsizei n, const GLuint *programs); + void (APIENTRY *ExecuteProgramNV) (GLenum target, GLuint id, const GLfloat *params); + void (APIENTRY *GenProgramsNV) (GLsizei n, GLuint *programs); + void (APIENTRY *GetProgramParameterdvNV) (GLenum target, GLuint index, GLenum pname, GLdouble *params); + void (APIENTRY *GetProgramParameterfvNV) (GLenum target, GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetProgramivNV) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetProgramStringNV) (GLuint id, GLenum pname, GLubyte *program); + void (APIENTRY *GetTrackMatrixivNV) (GLenum target, GLuint address, GLenum pname, GLint *params); + void (APIENTRY *GetVertexAttribdvNV) (GLuint index, GLenum pname, GLdouble *params); + void (APIENTRY *GetVertexAttribfvNV) (GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetVertexAttribivNV) (GLuint index, GLenum pname, GLint *params); + void (APIENTRY *GetVertexAttribPointervNV) (GLuint index, GLenum pname, GLvoid* *pointer); + GLboolean (APIENTRY *IsProgramNV) (GLuint id); + void (APIENTRY *LoadProgramNV) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); + void (APIENTRY *ProgramParameter4dNV) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramParameter4dvNV) (GLenum target, GLuint index, const GLdouble *v); + void (APIENTRY *ProgramParameter4fNV) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramParameter4fvNV) (GLenum target, GLuint index, const GLfloat *v); + void (APIENTRY *ProgramParameters4dvNV) (GLenum target, GLuint index, GLuint count, const GLdouble *v); + void (APIENTRY *ProgramParameters4fvNV) (GLenum target, GLuint index, GLuint count, const GLfloat *v); + void (APIENTRY *RequestResidentProgramsNV) (GLsizei n, const GLuint *programs); + void (APIENTRY *TrackMatrixNV) (GLenum target, GLuint address, GLenum matrix, GLenum transform); + void (APIENTRY *VertexAttribPointerNV) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY *VertexAttrib1dNV) (GLuint index, GLdouble x); + void (APIENTRY *VertexAttrib1dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib1fNV) (GLuint index, GLfloat x); + void (APIENTRY *VertexAttrib1fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib1sNV) (GLuint index, GLshort x); + void (APIENTRY *VertexAttrib1svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib2dNV) (GLuint index, GLdouble x, GLdouble y); + void (APIENTRY *VertexAttrib2dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib2fNV) (GLuint index, GLfloat x, GLfloat y); + void (APIENTRY *VertexAttrib2fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib2sNV) (GLuint index, GLshort x, GLshort y); + void (APIENTRY *VertexAttrib2svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib3dNV) (GLuint index, GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *VertexAttrib3dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib3fNV) (GLuint index, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *VertexAttrib3fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib3sNV) (GLuint index, GLshort x, GLshort y, GLshort z); + void (APIENTRY *VertexAttrib3svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4dNV) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *VertexAttrib4dvNV) (GLuint index, const GLdouble *v); + void (APIENTRY *VertexAttrib4fNV) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *VertexAttrib4fvNV) (GLuint index, const GLfloat *v); + void (APIENTRY *VertexAttrib4sNV) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *VertexAttrib4svNV) (GLuint index, const GLshort *v); + void (APIENTRY *VertexAttrib4ubNV) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); + void (APIENTRY *VertexAttrib4ubvNV) (GLuint index, const GLubyte *v); + void (APIENTRY *VertexAttribs1dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs1fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs1svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs2dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs2fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs2svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs3dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs3fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs3svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs4dvNV) (GLuint index, GLsizei count, const GLdouble *v); + void (APIENTRY *VertexAttribs4fvNV) (GLuint index, GLsizei count, const GLfloat *v); + void (APIENTRY *VertexAttribs4svNV) (GLuint index, GLsizei count, const GLshort *v); + void (APIENTRY *VertexAttribs4ubvNV) (GLuint index, GLsizei count, const GLubyte *v); + void (APIENTRY *TexBumpParameterivATI) (GLenum pname, const GLint *param); + void (APIENTRY *TexBumpParameterfvATI) (GLenum pname, const GLfloat *param); + void (APIENTRY *GetTexBumpParameterivATI) (GLenum pname, GLint *param); + void (APIENTRY *GetTexBumpParameterfvATI) (GLenum pname, GLfloat *param); + GLuint (APIENTRY *GenFragmentShadersATI) (GLuint range); + void (APIENTRY *BindFragmentShaderATI) (GLuint id); + void (APIENTRY *DeleteFragmentShaderATI) (GLuint id); + void (APIENTRY *BeginFragmentShaderATI) (void); + void (APIENTRY *EndFragmentShaderATI) (void); + void (APIENTRY *PassTexCoordATI) (GLuint dst, GLuint coord, GLenum swizzle); + void (APIENTRY *SampleMapATI) (GLuint dst, GLuint interp, GLenum swizzle); + void (APIENTRY *ColorFragmentOp1ATI) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); + void (APIENTRY *ColorFragmentOp2ATI) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); + void (APIENTRY *ColorFragmentOp3ATI) (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); + void (APIENTRY *AlphaFragmentOp1ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); + void (APIENTRY *AlphaFragmentOp2ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); + void (APIENTRY *AlphaFragmentOp3ATI) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); + void (APIENTRY *SetFragmentShaderConstantATI) (GLuint dst, const GLfloat *value); + void (APIENTRY *PNTrianglesiATI) (GLenum pname, GLint param); + void (APIENTRY *PNTrianglesfATI) (GLenum pname, GLfloat param); + GLuint (APIENTRY *NewObjectBufferATI) (GLsizei size, const GLvoid *pointer, GLenum usage); + GLboolean (APIENTRY *IsObjectBufferATI) (GLuint buffer); + void (APIENTRY *UpdateObjectBufferATI) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); + void (APIENTRY *GetObjectBufferfvATI) (GLuint buffer, GLenum pname, GLfloat *params); + void (APIENTRY *GetObjectBufferivATI) (GLuint buffer, GLenum pname, GLint *params); + void (APIENTRY *FreeObjectBufferATI) (GLuint buffer); + void (APIENTRY *ArrayObjectATI) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); + void (APIENTRY *GetArrayObjectfvATI) (GLenum array, GLenum pname, GLfloat *params); + void (APIENTRY *GetArrayObjectivATI) (GLenum array, GLenum pname, GLint *params); + void (APIENTRY *VariantArrayObjectATI) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); + void (APIENTRY *GetVariantArrayObjectfvATI) (GLuint id, GLenum pname, GLfloat *params); + void (APIENTRY *GetVariantArrayObjectivATI) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *BeginVertexShaderEXT) (void); + void (APIENTRY *EndVertexShaderEXT) (void); + void (APIENTRY *BindVertexShaderEXT) (GLuint id); + GLuint (APIENTRY *GenVertexShadersEXT) (GLuint range); + void (APIENTRY *DeleteVertexShaderEXT) (GLuint id); + void (APIENTRY *ShaderOp1EXT) (GLenum op, GLuint res, GLuint arg1); + void (APIENTRY *ShaderOp2EXT) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); + void (APIENTRY *ShaderOp3EXT) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); + void (APIENTRY *SwizzleEXT) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); + void (APIENTRY *WriteMaskEXT) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); + void (APIENTRY *InsertComponentEXT) (GLuint res, GLuint src, GLuint num); + void (APIENTRY *ExtractComponentEXT) (GLuint res, GLuint src, GLuint num); + GLuint (APIENTRY *GenSymbolsEXT) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); + void (APIENTRY *SetInvariantEXT) (GLuint id, GLenum type, const GLvoid *addr); + void (APIENTRY *SetLocalConstantEXT) (GLuint id, GLenum type, const GLvoid *addr); + void (APIENTRY *VariantbvEXT) (GLuint id, const GLbyte *addr); + void (APIENTRY *VariantsvEXT) (GLuint id, const GLshort *addr); + void (APIENTRY *VariantivEXT) (GLuint id, const GLint *addr); + void (APIENTRY *VariantfvEXT) (GLuint id, const GLfloat *addr); + void (APIENTRY *VariantdvEXT) (GLuint id, const GLdouble *addr); + void (APIENTRY *VariantubvEXT) (GLuint id, const GLubyte *addr); + void (APIENTRY *VariantusvEXT) (GLuint id, const GLushort *addr); + void (APIENTRY *VariantuivEXT) (GLuint id, const GLuint *addr); + void (APIENTRY *VariantPointerEXT) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); + void (APIENTRY *EnableVariantClientStateEXT) (GLuint id); + void (APIENTRY *DisableVariantClientStateEXT) (GLuint id); + GLuint (APIENTRY *BindLightParameterEXT) (GLenum light, GLenum value); + GLuint (APIENTRY *BindMaterialParameterEXT) (GLenum face, GLenum value); + GLuint (APIENTRY *BindTexGenParameterEXT) (GLenum unit, GLenum coord, GLenum value); + GLuint (APIENTRY *BindTextureUnitParameterEXT) (GLenum unit, GLenum value); + GLuint (APIENTRY *BindParameterEXT) (GLenum value); + GLboolean (APIENTRY *IsVariantEnabledEXT) (GLuint id, GLenum cap); + void (APIENTRY *GetVariantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); + void (APIENTRY *GetVariantIntegervEXT) (GLuint id, GLenum value, GLint *data); + void (APIENTRY *GetVariantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); + void (APIENTRY *GetVariantPointervEXT) (GLuint id, GLenum value, GLvoid* *data); + void (APIENTRY *GetInvariantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); + void (APIENTRY *GetInvariantIntegervEXT) (GLuint id, GLenum value, GLint *data); + void (APIENTRY *GetInvariantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); + void (APIENTRY *GetLocalConstantBooleanvEXT) (GLuint id, GLenum value, GLboolean *data); + void (APIENTRY *GetLocalConstantIntegervEXT) (GLuint id, GLenum value, GLint *data); + void (APIENTRY *GetLocalConstantFloatvEXT) (GLuint id, GLenum value, GLfloat *data); + void (APIENTRY *VertexStream1sATI) (GLenum stream, GLshort x); + void (APIENTRY *VertexStream1svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream1iATI) (GLenum stream, GLint x); + void (APIENTRY *VertexStream1ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream1fATI) (GLenum stream, GLfloat x); + void (APIENTRY *VertexStream1fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream1dATI) (GLenum stream, GLdouble x); + void (APIENTRY *VertexStream1dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *VertexStream2sATI) (GLenum stream, GLshort x, GLshort y); + void (APIENTRY *VertexStream2svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream2iATI) (GLenum stream, GLint x, GLint y); + void (APIENTRY *VertexStream2ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream2fATI) (GLenum stream, GLfloat x, GLfloat y); + void (APIENTRY *VertexStream2fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream2dATI) (GLenum stream, GLdouble x, GLdouble y); + void (APIENTRY *VertexStream2dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *VertexStream3sATI) (GLenum stream, GLshort x, GLshort y, GLshort z); + void (APIENTRY *VertexStream3svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream3iATI) (GLenum stream, GLint x, GLint y, GLint z); + void (APIENTRY *VertexStream3ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream3fATI) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY *VertexStream3fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream3dATI) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY *VertexStream3dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *VertexStream4sATI) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY *VertexStream4svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *VertexStream4iATI) (GLenum stream, GLint x, GLint y, GLint z, GLint w); + void (APIENTRY *VertexStream4ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *VertexStream4fATI) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *VertexStream4fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *VertexStream4dATI) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *VertexStream4dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *NormalStream3bATI) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); + void (APIENTRY *NormalStream3bvATI) (GLenum stream, const GLbyte *coords); + void (APIENTRY *NormalStream3sATI) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); + void (APIENTRY *NormalStream3svATI) (GLenum stream, const GLshort *coords); + void (APIENTRY *NormalStream3iATI) (GLenum stream, GLint nx, GLint ny, GLint nz); + void (APIENTRY *NormalStream3ivATI) (GLenum stream, const GLint *coords); + void (APIENTRY *NormalStream3fATI) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); + void (APIENTRY *NormalStream3fvATI) (GLenum stream, const GLfloat *coords); + void (APIENTRY *NormalStream3dATI) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); + void (APIENTRY *NormalStream3dvATI) (GLenum stream, const GLdouble *coords); + void (APIENTRY *ClientActiveVertexStreamATI) (GLenum stream); + void (APIENTRY *VertexBlendEnviATI) (GLenum pname, GLint param); + void (APIENTRY *VertexBlendEnvfATI) (GLenum pname, GLfloat param); + void (APIENTRY *ElementPointerATI) (GLenum type, const GLvoid *pointer); + void (APIENTRY *DrawElementArrayATI) (GLenum mode, GLsizei count); + void (APIENTRY *DrawRangeElementArrayATI) (GLenum mode, GLuint start, GLuint end, GLsizei count); + void (APIENTRY *DrawMeshArraysSUN) (GLenum mode, GLint first, GLsizei count, GLsizei width); + void (APIENTRY *GenOcclusionQueriesNV) (GLsizei n, GLuint *ids); + void (APIENTRY *DeleteOcclusionQueriesNV) (GLsizei n, const GLuint *ids); + GLboolean (APIENTRY *IsOcclusionQueryNV) (GLuint id); + void (APIENTRY *BeginOcclusionQueryNV) (GLuint id); + void (APIENTRY *EndOcclusionQueryNV) (void); + void (APIENTRY *GetOcclusionQueryivNV) (GLuint id, GLenum pname, GLint *params); + void (APIENTRY *GetOcclusionQueryuivNV) (GLuint id, GLenum pname, GLuint *params); + void (APIENTRY *PointParameteriNV) (GLenum pname, GLint param); + void (APIENTRY *PointParameterivNV) (GLenum pname, const GLint *params); + void (APIENTRY *ActiveStencilFaceEXT) (GLenum face); + void (APIENTRY *ElementPointerAPPLE) (GLenum type, const GLvoid *pointer); + void (APIENTRY *DrawElementArrayAPPLE) (GLenum mode, GLint first, GLsizei count); + void (APIENTRY *DrawRangeElementArrayAPPLE) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); + void (APIENTRY *MultiDrawElementArrayAPPLE) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); + void (APIENTRY *MultiDrawRangeElementArrayAPPLE) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); + void (APIENTRY *GenFencesAPPLE) (GLsizei n, GLuint *fences); + void (APIENTRY *DeleteFencesAPPLE) (GLsizei n, const GLuint *fences); + void (APIENTRY *SetFenceAPPLE) (GLuint fence); + GLboolean (APIENTRY *IsFenceAPPLE) (GLuint fence); + GLboolean (APIENTRY *TestFenceAPPLE) (GLuint fence); + void (APIENTRY *FinishFenceAPPLE) (GLuint fence); + GLboolean (APIENTRY *TestObjectAPPLE) (GLenum object, GLuint name); + void (APIENTRY *FinishObjectAPPLE) (GLenum object, GLint name); + void (APIENTRY *BindVertexArrayAPPLE) (GLuint array); + void (APIENTRY *DeleteVertexArraysAPPLE) (GLsizei n, const GLuint *arrays); + void (APIENTRY *GenVertexArraysAPPLE) (GLsizei n, const GLuint *arrays); + GLboolean (APIENTRY *IsVertexArrayAPPLE) (GLuint array); + void (APIENTRY *VertexArrayRangeAPPLE) (GLsizei length, GLvoid *pointer); + void (APIENTRY *FlushVertexArrayRangeAPPLE) (GLsizei length, GLvoid *pointer); + void (APIENTRY *VertexArrayParameteriAPPLE) (GLenum pname, GLint param); + void (APIENTRY *DrawBuffersATI) (GLsizei n, const GLenum *bufs); + void (APIENTRY *ProgramNamedParameter4fNV) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY *ProgramNamedParameter4dNV) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY *ProgramNamedParameter4fvNV) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); + void (APIENTRY *ProgramNamedParameter4dvNV) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); + void (APIENTRY *GetProgramNamedParameterfvNV) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); + void (APIENTRY *GetProgramNamedParameterdvNV) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); + void (APIENTRY *Vertex2hNV) (GLhalfNV x, GLhalfNV y); + void (APIENTRY *Vertex2hvNV) (const GLhalfNV *v); + void (APIENTRY *Vertex3hNV) (GLhalfNV x, GLhalfNV y, GLhalfNV z); + void (APIENTRY *Vertex3hvNV) (const GLhalfNV *v); + void (APIENTRY *Vertex4hNV) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); + void (APIENTRY *Vertex4hvNV) (const GLhalfNV *v); + void (APIENTRY *Normal3hNV) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); + void (APIENTRY *Normal3hvNV) (const GLhalfNV *v); + void (APIENTRY *Color3hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); + void (APIENTRY *Color3hvNV) (const GLhalfNV *v); + void (APIENTRY *Color4hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); + void (APIENTRY *Color4hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord1hNV) (GLhalfNV s); + void (APIENTRY *TexCoord1hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord2hNV) (GLhalfNV s, GLhalfNV t); + void (APIENTRY *TexCoord2hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord3hNV) (GLhalfNV s, GLhalfNV t, GLhalfNV r); + void (APIENTRY *TexCoord3hvNV) (const GLhalfNV *v); + void (APIENTRY *TexCoord4hNV) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); + void (APIENTRY *TexCoord4hvNV) (const GLhalfNV *v); + void (APIENTRY *MultiTexCoord1hNV) (GLenum target, GLhalfNV s); + void (APIENTRY *MultiTexCoord1hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *MultiTexCoord2hNV) (GLenum target, GLhalfNV s, GLhalfNV t); + void (APIENTRY *MultiTexCoord2hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *MultiTexCoord3hNV) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); + void (APIENTRY *MultiTexCoord3hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *MultiTexCoord4hNV) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); + void (APIENTRY *MultiTexCoord4hvNV) (GLenum target, const GLhalfNV *v); + void (APIENTRY *FogCoordhNV) (GLhalfNV fog); + void (APIENTRY *FogCoordhvNV) (const GLhalfNV *fog); + void (APIENTRY *SecondaryColor3hNV) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); + void (APIENTRY *SecondaryColor3hvNV) (const GLhalfNV *v); + void (APIENTRY *VertexWeighthNV) (GLhalfNV weight); + void (APIENTRY *VertexWeighthvNV) (const GLhalfNV *weight); + void (APIENTRY *VertexAttrib1hNV) (GLuint index, GLhalfNV x); + void (APIENTRY *VertexAttrib1hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttrib2hNV) (GLuint index, GLhalfNV x, GLhalfNV y); + void (APIENTRY *VertexAttrib2hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttrib3hNV) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); + void (APIENTRY *VertexAttrib3hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttrib4hNV) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); + void (APIENTRY *VertexAttrib4hvNV) (GLuint index, const GLhalfNV *v); + void (APIENTRY *VertexAttribs1hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *VertexAttribs2hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *VertexAttribs3hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *VertexAttribs4hvNV) (GLuint index, GLsizei n, const GLhalfNV *v); + void (APIENTRY *PixelDataRangeNV) (GLenum target, GLsizei length, GLvoid *pointer); + void (APIENTRY *FlushPixelDataRangeNV) (GLenum target); + void (APIENTRY *PrimitiveRestartNV) (void); + void (APIENTRY *PrimitiveRestartIndexNV) (GLuint index); + GLvoid* (APIENTRY *MapObjectBufferATI) (GLuint buffer); + void (APIENTRY *UnmapObjectBufferATI) (GLuint buffer); + void (APIENTRY *StencilOpSeparateATI) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); + void (APIENTRY *StencilFuncSeparateATI) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); + void (APIENTRY *VertexAttribArrayObjectATI) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); + void (APIENTRY *GetVertexAttribArrayObjectfvATI) (GLuint index, GLenum pname, GLfloat *params); + void (APIENTRY *GetVertexAttribArrayObjectivATI) (GLuint index, GLenum pname, GLint *params); + void (APIENTRY *DepthBoundsEXT) (GLclampd zmin, GLclampd zmax); + void (APIENTRY *BlendEquationSeparateEXT) (GLenum modeRGB, GLenum modeAlpha); + void (APIENTRY *AddSwapHintRectWIN) (GLint x, GLint y, GLsizei width, GLsizei height); +#ifdef _WIN32 + HANDLE (WINAPI *CreateBufferRegionARB) (HDC hDC, int iLayerPlane, UINT uType); + VOID (WINAPI *DeleteBufferRegionARB) (HANDLE hRegion); + BOOL (WINAPI *SaveBufferRegionARB) (HANDLE hRegion, int x, int y, int width, int height); + BOOL (WINAPI *RestoreBufferRegionARB) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); + const int (WINAPI *GetExtensionsStringARB) (HDC hdc); + BOOL (WINAPI *GetPixelFormatAttribivARB) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); + BOOL (WINAPI *GetPixelFormatAttribfvARB) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); + BOOL (WINAPI *ChoosePixelFormatARB) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + BOOL (WINAPI *MakeContextCurrentARB) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); + HDC (WINAPI *GetCurrentReadDCARB) (void); + HPBUFFERARB (WINAPI *CreatePbufferARB) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); + HDC (WINAPI *GetPbufferDCARB) (HPBUFFERARB hPbuffer); + int (WINAPI *ReleasePbufferDCARB) (HPBUFFERARB hPbuffer, HDC hDC); + BOOL (WINAPI *DestroyPbufferARB) (HPBUFFERARB hPbuffer); + BOOL (WINAPI *QueryPbufferARB) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); + BOOL (WINAPI *BindTexImageARB) (HPBUFFERARB hPbuffer, int iBuffer); + BOOL (WINAPI *ReleaseTexImageARB) (HPBUFFERARB hPbuffer, int iBuffer); + BOOL (WINAPI *SetPbufferAttribARB) (HPBUFFERARB hPbuffer, const int *piAttribList); + GLboolean (WINAPI *CreateDisplayColorTableEXT) (GLushort id); + GLboolean (WINAPI *LoadDisplayColorTableEXT) (const GLushort *table, GLuint length); + GLboolean (WINAPI *BindDisplayColorTableEXT) (GLushort id); + VOID (WINAPI *DestroyDisplayColorTableEXT) (GLushort id); + const int (WINAPI *GetExtensionsStringEXT) (void); + BOOL (WINAPI *MakeContextCurrentEXT) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); + HDC (WINAPI *GetCurrentReadDCEXT) (void); + HPBUFFEREXT (WINAPI *CreatePbufferEXT) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); + HDC (WINAPI *GetPbufferDCEXT) (HPBUFFEREXT hPbuffer); + int (WINAPI *ReleasePbufferDCEXT) (HPBUFFEREXT hPbuffer, HDC hDC); + BOOL (WINAPI *DestroyPbufferEXT) (HPBUFFEREXT hPbuffer); + BOOL (WINAPI *QueryPbufferEXT) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); + BOOL (WINAPI *GetPixelFormatAttribivEXT) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); + BOOL (WINAPI *GetPixelFormatAttribfvEXT) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); + BOOL (WINAPI *ChoosePixelFormatEXT) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + BOOL (WINAPI *SwapIntervalEXT) (int interval); + int (WINAPI *GetSwapIntervalEXT) (void); + void* (WINAPI *AllocateMemoryNV) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); + void (WINAPI *FreeMemoryNV) (void); + BOOL (WINAPI *GetSyncValuesOML) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); + BOOL (WINAPI *GetMscRateOML) (HDC hdc, INT32 *numerator, INT32 *denominator); + INT64 (WINAPI *SwapBuffersMscOML) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); + INT64 (WINAPI *SwapLayerBuffersMscOML) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); + BOOL (WINAPI *WaitForMscOML) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); + BOOL (WINAPI *WaitForSbcOML) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); + BOOL (WINAPI *GetDigitalVideoParametersI3D) (HDC hDC, int iAttribute, int *piValue); + BOOL (WINAPI *SetDigitalVideoParametersI3D) (HDC hDC, int iAttribute, const int *piValue); + BOOL (WINAPI *GetGammaTableParametersI3D) (HDC hDC, int iAttribute, int *piValue); + BOOL (WINAPI *SetGammaTableParametersI3D) (HDC hDC, int iAttribute, const int *piValue); + BOOL (WINAPI *GetGammaTableI3D) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); + BOOL (WINAPI *SetGammaTableI3D) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); + BOOL (WINAPI *EnableGenlockI3D) (HDC hDC); + BOOL (WINAPI *DisableGenlockI3D) (HDC hDC); + BOOL (WINAPI *IsEnabledGenlockI3D) (HDC hDC, BOOL *pFlag); + BOOL (WINAPI *GenlockSourceI3D) (HDC hDC, UINT uSource); + BOOL (WINAPI *GetGenlockSourceI3D) (HDC hDC, UINT *uSource); + BOOL (WINAPI *GenlockSourceEdgeI3D) (HDC hDC, UINT uEdge); + BOOL (WINAPI *GetGenlockSourceEdgeI3D) (HDC hDC, UINT *uEdge); + BOOL (WINAPI *GenlockSampleRateI3D) (HDC hDC, UINT uRate); + BOOL (WINAPI *GetGenlockSampleRateI3D) (HDC hDC, UINT *uRate); + BOOL (WINAPI *GenlockSourceDelayI3D) (HDC hDC, UINT uDelay); + BOOL (WINAPI *GetGenlockSourceDelayI3D) (HDC hDC, UINT *uDelay); + BOOL (WINAPI *QueryGenlockMaxSourceDelayI3D) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); + LPVOID (WINAPI *CreateImageBufferI3D) (HDC hDC, DWORD dwSize, UINT uFlags); + BOOL (WINAPI *DestroyImageBufferI3D) (HDC hDC, LPVOID pAddress); + BOOL (WINAPI *AssociateImageBufferEventsI3D) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); + BOOL (WINAPI *ReleaseImageBufferEventsI3D) (HDC hDC, const LPVOID *pAddress, UINT count); + BOOL (WINAPI *EnableFrameLockI3D) (void); + BOOL (WINAPI *DisableFrameLockI3D) (void); + BOOL (WINAPI *IsEnabledFrameLockI3D) (BOOL *pFlag); + BOOL (WINAPI *QueryFrameLockMasterI3D) (BOOL *pFlag); + BOOL (WINAPI *GetFrameUsageI3D) (float *pUsage); + BOOL (WINAPI *BeginFrameTrackingI3D) (void); + BOOL (WINAPI *EndFrameTrackingI3D) (void); + BOOL (WINAPI *QueryFrameTrackingI3D) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#endif /* _WIN32 */ +} _GLextensionProcs; + +#define glBlendColor (_GET_TLS_PROCTABLE()->BlendColor) +#define glBlendEquation (_GET_TLS_PROCTABLE()->BlendEquation) +#define glDrawRangeElements (_GET_TLS_PROCTABLE()->DrawRangeElements) +#define glColorTable (_GET_TLS_PROCTABLE()->ColorTable) +#define glColorTableParameterfv (_GET_TLS_PROCTABLE()->ColorTableParameterfv) +#define glColorTableParameteriv (_GET_TLS_PROCTABLE()->ColorTableParameteriv) +#define glCopyColorTable (_GET_TLS_PROCTABLE()->CopyColorTable) +#define glGetColorTable (_GET_TLS_PROCTABLE()->GetColorTable) +#define glGetColorTableParameterfv (_GET_TLS_PROCTABLE()->GetColorTableParameterfv) +#define glGetColorTableParameteriv (_GET_TLS_PROCTABLE()->GetColorTableParameteriv) +#define glColorSubTable (_GET_TLS_PROCTABLE()->ColorSubTable) +#define glCopyColorSubTable (_GET_TLS_PROCTABLE()->CopyColorSubTable) +#define glConvolutionFilter1D (_GET_TLS_PROCTABLE()->ConvolutionFilter1D) +#define glConvolutionFilter2D (_GET_TLS_PROCTABLE()->ConvolutionFilter2D) +#define glConvolutionParameterf (_GET_TLS_PROCTABLE()->ConvolutionParameterf) +#define glConvolutionParameterfv (_GET_TLS_PROCTABLE()->ConvolutionParameterfv) +#define glConvolutionParameteri (_GET_TLS_PROCTABLE()->ConvolutionParameteri) +#define glConvolutionParameteriv (_GET_TLS_PROCTABLE()->ConvolutionParameteriv) +#define glCopyConvolutionFilter1D (_GET_TLS_PROCTABLE()->CopyConvolutionFilter1D) +#define glCopyConvolutionFilter2D (_GET_TLS_PROCTABLE()->CopyConvolutionFilter2D) +#define glGetConvolutionFilter (_GET_TLS_PROCTABLE()->GetConvolutionFilter) +#define glGetConvolutionParameterfv (_GET_TLS_PROCTABLE()->GetConvolutionParameterfv) +#define glGetConvolutionParameteriv (_GET_TLS_PROCTABLE()->GetConvolutionParameteriv) +#define glGetSeparableFilter (_GET_TLS_PROCTABLE()->GetSeparableFilter) +#define glSeparableFilter2D (_GET_TLS_PROCTABLE()->SeparableFilter2D) +#define glGetHistogram (_GET_TLS_PROCTABLE()->GetHistogram) +#define glGetHistogramParameterfv (_GET_TLS_PROCTABLE()->GetHistogramParameterfv) +#define glGetHistogramParameteriv (_GET_TLS_PROCTABLE()->GetHistogramParameteriv) +#define glGetMinmax (_GET_TLS_PROCTABLE()->GetMinmax) +#define glGetMinmaxParameterfv (_GET_TLS_PROCTABLE()->GetMinmaxParameterfv) +#define glGetMinmaxParameteriv (_GET_TLS_PROCTABLE()->GetMinmaxParameteriv) +#define glHistogram (_GET_TLS_PROCTABLE()->Histogram) +#define glMinmax (_GET_TLS_PROCTABLE()->Minmax) +#define glResetHistogram (_GET_TLS_PROCTABLE()->ResetHistogram) +#define glResetMinmax (_GET_TLS_PROCTABLE()->ResetMinmax) +#define glTexImage3D (_GET_TLS_PROCTABLE()->TexImage3D) +#define glTexSubImage3D (_GET_TLS_PROCTABLE()->TexSubImage3D) +#define glCopyTexSubImage3D (_GET_TLS_PROCTABLE()->CopyTexSubImage3D) +#define glActiveTexture (_GET_TLS_PROCTABLE()->ActiveTexture) +#define glClientActiveTexture (_GET_TLS_PROCTABLE()->ClientActiveTexture) +#define glMultiTexCoord1d (_GET_TLS_PROCTABLE()->MultiTexCoord1d) +#define glMultiTexCoord1dv (_GET_TLS_PROCTABLE()->MultiTexCoord1dv) +#define glMultiTexCoord1f (_GET_TLS_PROCTABLE()->MultiTexCoord1f) +#define glMultiTexCoord1fv (_GET_TLS_PROCTABLE()->MultiTexCoord1fv) +#define glMultiTexCoord1i (_GET_TLS_PROCTABLE()->MultiTexCoord1i) +#define glMultiTexCoord1iv (_GET_TLS_PROCTABLE()->MultiTexCoord1iv) +#define glMultiTexCoord1s (_GET_TLS_PROCTABLE()->MultiTexCoord1s) +#define glMultiTexCoord1sv (_GET_TLS_PROCTABLE()->MultiTexCoord1sv) +#define glMultiTexCoord2d (_GET_TLS_PROCTABLE()->MultiTexCoord2d) +#define glMultiTexCoord2dv (_GET_TLS_PROCTABLE()->MultiTexCoord2dv) +#define glMultiTexCoord2f (_GET_TLS_PROCTABLE()->MultiTexCoord2f) +#define glMultiTexCoord2fv (_GET_TLS_PROCTABLE()->MultiTexCoord2fv) +#define glMultiTexCoord2i (_GET_TLS_PROCTABLE()->MultiTexCoord2i) +#define glMultiTexCoord2iv (_GET_TLS_PROCTABLE()->MultiTexCoord2iv) +#define glMultiTexCoord2s (_GET_TLS_PROCTABLE()->MultiTexCoord2s) +#define glMultiTexCoord2sv (_GET_TLS_PROCTABLE()->MultiTexCoord2sv) +#define glMultiTexCoord3d (_GET_TLS_PROCTABLE()->MultiTexCoord3d) +#define glMultiTexCoord3dv (_GET_TLS_PROCTABLE()->MultiTexCoord3dv) +#define glMultiTexCoord3f (_GET_TLS_PROCTABLE()->MultiTexCoord3f) +#define glMultiTexCoord3fv (_GET_TLS_PROCTABLE()->MultiTexCoord3fv) +#define glMultiTexCoord3i (_GET_TLS_PROCTABLE()->MultiTexCoord3i) +#define glMultiTexCoord3iv (_GET_TLS_PROCTABLE()->MultiTexCoord3iv) +#define glMultiTexCoord3s (_GET_TLS_PROCTABLE()->MultiTexCoord3s) +#define glMultiTexCoord3sv (_GET_TLS_PROCTABLE()->MultiTexCoord3sv) +#define glMultiTexCoord4d (_GET_TLS_PROCTABLE()->MultiTexCoord4d) +#define glMultiTexCoord4dv (_GET_TLS_PROCTABLE()->MultiTexCoord4dv) +#define glMultiTexCoord4f (_GET_TLS_PROCTABLE()->MultiTexCoord4f) +#define glMultiTexCoord4fv (_GET_TLS_PROCTABLE()->MultiTexCoord4fv) +#define glMultiTexCoord4i (_GET_TLS_PROCTABLE()->MultiTexCoord4i) +#define glMultiTexCoord4iv (_GET_TLS_PROCTABLE()->MultiTexCoord4iv) +#define glMultiTexCoord4s (_GET_TLS_PROCTABLE()->MultiTexCoord4s) +#define glMultiTexCoord4sv (_GET_TLS_PROCTABLE()->MultiTexCoord4sv) +#define glLoadTransposeMatrixf (_GET_TLS_PROCTABLE()->LoadTransposeMatrixf) +#define glLoadTransposeMatrixd (_GET_TLS_PROCTABLE()->LoadTransposeMatrixd) +#define glMultTransposeMatrixf (_GET_TLS_PROCTABLE()->MultTransposeMatrixf) +#define glMultTransposeMatrixd (_GET_TLS_PROCTABLE()->MultTransposeMatrixd) +#define glSampleCoverage (_GET_TLS_PROCTABLE()->SampleCoverage) +#define glCompressedTexImage3D (_GET_TLS_PROCTABLE()->CompressedTexImage3D) +#define glCompressedTexImage2D (_GET_TLS_PROCTABLE()->CompressedTexImage2D) +#define glCompressedTexImage1D (_GET_TLS_PROCTABLE()->CompressedTexImage1D) +#define glCompressedTexSubImage3D (_GET_TLS_PROCTABLE()->CompressedTexSubImage3D) +#define glCompressedTexSubImage2D (_GET_TLS_PROCTABLE()->CompressedTexSubImage2D) +#define glCompressedTexSubImage1D (_GET_TLS_PROCTABLE()->CompressedTexSubImage1D) +#define glGetCompressedTexImage (_GET_TLS_PROCTABLE()->GetCompressedTexImage) +#define glBlendFuncSeparate (_GET_TLS_PROCTABLE()->BlendFuncSeparate) +#define glFogCoordf (_GET_TLS_PROCTABLE()->FogCoordf) +#define glFogCoordfv (_GET_TLS_PROCTABLE()->FogCoordfv) +#define glFogCoordd (_GET_TLS_PROCTABLE()->FogCoordd) +#define glFogCoorddv (_GET_TLS_PROCTABLE()->FogCoorddv) +#define glFogCoordPointer (_GET_TLS_PROCTABLE()->FogCoordPointer) +#define glMultiDrawArrays (_GET_TLS_PROCTABLE()->MultiDrawArrays) +#define glMultiDrawElements (_GET_TLS_PROCTABLE()->MultiDrawElements) +#define glPointParameterf (_GET_TLS_PROCTABLE()->PointParameterf) +#define glPointParameterfv (_GET_TLS_PROCTABLE()->PointParameterfv) +#define glPointParameteri (_GET_TLS_PROCTABLE()->PointParameteri) +#define glPointParameteriv (_GET_TLS_PROCTABLE()->PointParameteriv) +#define glSecondaryColor3b (_GET_TLS_PROCTABLE()->SecondaryColor3b) +#define glSecondaryColor3bv (_GET_TLS_PROCTABLE()->SecondaryColor3bv) +#define glSecondaryColor3d (_GET_TLS_PROCTABLE()->SecondaryColor3d) +#define glSecondaryColor3dv (_GET_TLS_PROCTABLE()->SecondaryColor3dv) +#define glSecondaryColor3f (_GET_TLS_PROCTABLE()->SecondaryColor3f) +#define glSecondaryColor3fv (_GET_TLS_PROCTABLE()->SecondaryColor3fv) +#define glSecondaryColor3i (_GET_TLS_PROCTABLE()->SecondaryColor3i) +#define glSecondaryColor3iv (_GET_TLS_PROCTABLE()->SecondaryColor3iv) +#define glSecondaryColor3s (_GET_TLS_PROCTABLE()->SecondaryColor3s) +#define glSecondaryColor3sv (_GET_TLS_PROCTABLE()->SecondaryColor3sv) +#define glSecondaryColor3ub (_GET_TLS_PROCTABLE()->SecondaryColor3ub) +#define glSecondaryColor3ubv (_GET_TLS_PROCTABLE()->SecondaryColor3ubv) +#define glSecondaryColor3ui (_GET_TLS_PROCTABLE()->SecondaryColor3ui) +#define glSecondaryColor3uiv (_GET_TLS_PROCTABLE()->SecondaryColor3uiv) +#define glSecondaryColor3us (_GET_TLS_PROCTABLE()->SecondaryColor3us) +#define glSecondaryColor3usv (_GET_TLS_PROCTABLE()->SecondaryColor3usv) +#define glSecondaryColorPointer (_GET_TLS_PROCTABLE()->SecondaryColorPointer) +#define glWindowPos2d (_GET_TLS_PROCTABLE()->WindowPos2d) +#define glWindowPos2dv (_GET_TLS_PROCTABLE()->WindowPos2dv) +#define glWindowPos2f (_GET_TLS_PROCTABLE()->WindowPos2f) +#define glWindowPos2fv (_GET_TLS_PROCTABLE()->WindowPos2fv) +#define glWindowPos2i (_GET_TLS_PROCTABLE()->WindowPos2i) +#define glWindowPos2iv (_GET_TLS_PROCTABLE()->WindowPos2iv) +#define glWindowPos2s (_GET_TLS_PROCTABLE()->WindowPos2s) +#define glWindowPos2sv (_GET_TLS_PROCTABLE()->WindowPos2sv) +#define glWindowPos3d (_GET_TLS_PROCTABLE()->WindowPos3d) +#define glWindowPos3dv (_GET_TLS_PROCTABLE()->WindowPos3dv) +#define glWindowPos3f (_GET_TLS_PROCTABLE()->WindowPos3f) +#define glWindowPos3fv (_GET_TLS_PROCTABLE()->WindowPos3fv) +#define glWindowPos3i (_GET_TLS_PROCTABLE()->WindowPos3i) +#define glWindowPos3iv (_GET_TLS_PROCTABLE()->WindowPos3iv) +#define glWindowPos3s (_GET_TLS_PROCTABLE()->WindowPos3s) +#define glWindowPos3sv (_GET_TLS_PROCTABLE()->WindowPos3sv) +#define glGenQueries (_GET_TLS_PROCTABLE()->GenQueries) +#define glDeleteQueries (_GET_TLS_PROCTABLE()->DeleteQueries) +#define glIsQuery (_GET_TLS_PROCTABLE()->IsQuery) +#define glBeginQuery (_GET_TLS_PROCTABLE()->BeginQuery) +#define glEndQuery (_GET_TLS_PROCTABLE()->EndQuery) +#define glGetQueryiv (_GET_TLS_PROCTABLE()->GetQueryiv) +#define glGetQueryObjectiv (_GET_TLS_PROCTABLE()->GetQueryObjectiv) +#define glGetQueryObjectuiv (_GET_TLS_PROCTABLE()->GetQueryObjectuiv) +#define glBindBuffer (_GET_TLS_PROCTABLE()->BindBuffer) +#define glDeleteBuffers (_GET_TLS_PROCTABLE()->DeleteBuffers) +#define glGenBuffers (_GET_TLS_PROCTABLE()->GenBuffers) +#define glIsBuffer (_GET_TLS_PROCTABLE()->IsBuffer) +#define glBufferData (_GET_TLS_PROCTABLE()->BufferData) +#define glBufferSubData (_GET_TLS_PROCTABLE()->BufferSubData) +#define glGetBufferSubData (_GET_TLS_PROCTABLE()->GetBufferSubData) +#define glMapBuffer (_GET_TLS_PROCTABLE()->MapBuffer) +#define glUnmapBuffer (_GET_TLS_PROCTABLE()->UnmapBuffer) +#define glGetBufferParameteriv (_GET_TLS_PROCTABLE()->GetBufferParameteriv) +#define glGetBufferPointerv (_GET_TLS_PROCTABLE()->GetBufferPointerv) +#define glActiveTextureARB (_GET_TLS_PROCTABLE()->ActiveTextureARB) +#define glClientActiveTextureARB (_GET_TLS_PROCTABLE()->ClientActiveTextureARB) +#define glMultiTexCoord1dARB (_GET_TLS_PROCTABLE()->MultiTexCoord1dARB) +#define glMultiTexCoord1dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord1dvARB) +#define glMultiTexCoord1fARB (_GET_TLS_PROCTABLE()->MultiTexCoord1fARB) +#define glMultiTexCoord1fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord1fvARB) +#define glMultiTexCoord1iARB (_GET_TLS_PROCTABLE()->MultiTexCoord1iARB) +#define glMultiTexCoord1ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord1ivARB) +#define glMultiTexCoord1sARB (_GET_TLS_PROCTABLE()->MultiTexCoord1sARB) +#define glMultiTexCoord1svARB (_GET_TLS_PROCTABLE()->MultiTexCoord1svARB) +#define glMultiTexCoord2dARB (_GET_TLS_PROCTABLE()->MultiTexCoord2dARB) +#define glMultiTexCoord2dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord2dvARB) +#define glMultiTexCoord2fARB (_GET_TLS_PROCTABLE()->MultiTexCoord2fARB) +#define glMultiTexCoord2fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord2fvARB) +#define glMultiTexCoord2iARB (_GET_TLS_PROCTABLE()->MultiTexCoord2iARB) +#define glMultiTexCoord2ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord2ivARB) +#define glMultiTexCoord2sARB (_GET_TLS_PROCTABLE()->MultiTexCoord2sARB) +#define glMultiTexCoord2svARB (_GET_TLS_PROCTABLE()->MultiTexCoord2svARB) +#define glMultiTexCoord3dARB (_GET_TLS_PROCTABLE()->MultiTexCoord3dARB) +#define glMultiTexCoord3dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord3dvARB) +#define glMultiTexCoord3fARB (_GET_TLS_PROCTABLE()->MultiTexCoord3fARB) +#define glMultiTexCoord3fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord3fvARB) +#define glMultiTexCoord3iARB (_GET_TLS_PROCTABLE()->MultiTexCoord3iARB) +#define glMultiTexCoord3ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord3ivARB) +#define glMultiTexCoord3sARB (_GET_TLS_PROCTABLE()->MultiTexCoord3sARB) +#define glMultiTexCoord3svARB (_GET_TLS_PROCTABLE()->MultiTexCoord3svARB) +#define glMultiTexCoord4dARB (_GET_TLS_PROCTABLE()->MultiTexCoord4dARB) +#define glMultiTexCoord4dvARB (_GET_TLS_PROCTABLE()->MultiTexCoord4dvARB) +#define glMultiTexCoord4fARB (_GET_TLS_PROCTABLE()->MultiTexCoord4fARB) +#define glMultiTexCoord4fvARB (_GET_TLS_PROCTABLE()->MultiTexCoord4fvARB) +#define glMultiTexCoord4iARB (_GET_TLS_PROCTABLE()->MultiTexCoord4iARB) +#define glMultiTexCoord4ivARB (_GET_TLS_PROCTABLE()->MultiTexCoord4ivARB) +#define glMultiTexCoord4sARB (_GET_TLS_PROCTABLE()->MultiTexCoord4sARB) +#define glMultiTexCoord4svARB (_GET_TLS_PROCTABLE()->MultiTexCoord4svARB) +#define glLoadTransposeMatrixfARB (_GET_TLS_PROCTABLE()->LoadTransposeMatrixfARB) +#define glLoadTransposeMatrixdARB (_GET_TLS_PROCTABLE()->LoadTransposeMatrixdARB) +#define glMultTransposeMatrixfARB (_GET_TLS_PROCTABLE()->MultTransposeMatrixfARB) +#define glMultTransposeMatrixdARB (_GET_TLS_PROCTABLE()->MultTransposeMatrixdARB) +#define glSampleCoverageARB (_GET_TLS_PROCTABLE()->SampleCoverageARB) +#define glCompressedTexImage3DARB (_GET_TLS_PROCTABLE()->CompressedTexImage3DARB) +#define glCompressedTexImage2DARB (_GET_TLS_PROCTABLE()->CompressedTexImage2DARB) +#define glCompressedTexImage1DARB (_GET_TLS_PROCTABLE()->CompressedTexImage1DARB) +#define glCompressedTexSubImage3DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage3DARB) +#define glCompressedTexSubImage2DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage2DARB) +#define glCompressedTexSubImage1DARB (_GET_TLS_PROCTABLE()->CompressedTexSubImage1DARB) +#define glGetCompressedTexImageARB (_GET_TLS_PROCTABLE()->GetCompressedTexImageARB) +#define glPointParameterfARB (_GET_TLS_PROCTABLE()->PointParameterfARB) +#define glPointParameterfvARB (_GET_TLS_PROCTABLE()->PointParameterfvARB) +#define glWeightbvARB (_GET_TLS_PROCTABLE()->WeightbvARB) +#define glWeightsvARB (_GET_TLS_PROCTABLE()->WeightsvARB) +#define glWeightivARB (_GET_TLS_PROCTABLE()->WeightivARB) +#define glWeightfvARB (_GET_TLS_PROCTABLE()->WeightfvARB) +#define glWeightdvARB (_GET_TLS_PROCTABLE()->WeightdvARB) +#define glWeightubvARB (_GET_TLS_PROCTABLE()->WeightubvARB) +#define glWeightusvARB (_GET_TLS_PROCTABLE()->WeightusvARB) +#define glWeightuivARB (_GET_TLS_PROCTABLE()->WeightuivARB) +#define glWeightPointerARB (_GET_TLS_PROCTABLE()->WeightPointerARB) +#define glVertexBlendARB (_GET_TLS_PROCTABLE()->VertexBlendARB) +#define glCurrentPaletteMatrixARB (_GET_TLS_PROCTABLE()->CurrentPaletteMatrixARB) +#define glMatrixIndexubvARB (_GET_TLS_PROCTABLE()->MatrixIndexubvARB) +#define glMatrixIndexusvARB (_GET_TLS_PROCTABLE()->MatrixIndexusvARB) +#define glMatrixIndexuivARB (_GET_TLS_PROCTABLE()->MatrixIndexuivARB) +#define glMatrixIndexPointerARB (_GET_TLS_PROCTABLE()->MatrixIndexPointerARB) +#define glWindowPos2dARB (_GET_TLS_PROCTABLE()->WindowPos2dARB) +#define glWindowPos2dvARB (_GET_TLS_PROCTABLE()->WindowPos2dvARB) +#define glWindowPos2fARB (_GET_TLS_PROCTABLE()->WindowPos2fARB) +#define glWindowPos2fvARB (_GET_TLS_PROCTABLE()->WindowPos2fvARB) +#define glWindowPos2iARB (_GET_TLS_PROCTABLE()->WindowPos2iARB) +#define glWindowPos2ivARB (_GET_TLS_PROCTABLE()->WindowPos2ivARB) +#define glWindowPos2sARB (_GET_TLS_PROCTABLE()->WindowPos2sARB) +#define glWindowPos2svARB (_GET_TLS_PROCTABLE()->WindowPos2svARB) +#define glWindowPos3dARB (_GET_TLS_PROCTABLE()->WindowPos3dARB) +#define glWindowPos3dvARB (_GET_TLS_PROCTABLE()->WindowPos3dvARB) +#define glWindowPos3fARB (_GET_TLS_PROCTABLE()->WindowPos3fARB) +#define glWindowPos3fvARB (_GET_TLS_PROCTABLE()->WindowPos3fvARB) +#define glWindowPos3iARB (_GET_TLS_PROCTABLE()->WindowPos3iARB) +#define glWindowPos3ivARB (_GET_TLS_PROCTABLE()->WindowPos3ivARB) +#define glWindowPos3sARB (_GET_TLS_PROCTABLE()->WindowPos3sARB) +#define glWindowPos3svARB (_GET_TLS_PROCTABLE()->WindowPos3svARB) +#define glVertexAttrib1dARB (_GET_TLS_PROCTABLE()->VertexAttrib1dARB) +#define glVertexAttrib1dvARB (_GET_TLS_PROCTABLE()->VertexAttrib1dvARB) +#define glVertexAttrib1fARB (_GET_TLS_PROCTABLE()->VertexAttrib1fARB) +#define glVertexAttrib1fvARB (_GET_TLS_PROCTABLE()->VertexAttrib1fvARB) +#define glVertexAttrib1sARB (_GET_TLS_PROCTABLE()->VertexAttrib1sARB) +#define glVertexAttrib1svARB (_GET_TLS_PROCTABLE()->VertexAttrib1svARB) +#define glVertexAttrib2dARB (_GET_TLS_PROCTABLE()->VertexAttrib2dARB) +#define glVertexAttrib2dvARB (_GET_TLS_PROCTABLE()->VertexAttrib2dvARB) +#define glVertexAttrib2fARB (_GET_TLS_PROCTABLE()->VertexAttrib2fARB) +#define glVertexAttrib2fvARB (_GET_TLS_PROCTABLE()->VertexAttrib2fvARB) +#define glVertexAttrib2sARB (_GET_TLS_PROCTABLE()->VertexAttrib2sARB) +#define glVertexAttrib2svARB (_GET_TLS_PROCTABLE()->VertexAttrib2svARB) +#define glVertexAttrib3dARB (_GET_TLS_PROCTABLE()->VertexAttrib3dARB) +#define glVertexAttrib3dvARB (_GET_TLS_PROCTABLE()->VertexAttrib3dvARB) +#define glVertexAttrib3fARB (_GET_TLS_PROCTABLE()->VertexAttrib3fARB) +#define glVertexAttrib3fvARB (_GET_TLS_PROCTABLE()->VertexAttrib3fvARB) +#define glVertexAttrib3sARB (_GET_TLS_PROCTABLE()->VertexAttrib3sARB) +#define glVertexAttrib3svARB (_GET_TLS_PROCTABLE()->VertexAttrib3svARB) +#define glVertexAttrib4NbvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NbvARB) +#define glVertexAttrib4NivARB (_GET_TLS_PROCTABLE()->VertexAttrib4NivARB) +#define glVertexAttrib4NsvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NsvARB) +#define glVertexAttrib4NubARB (_GET_TLS_PROCTABLE()->VertexAttrib4NubARB) +#define glVertexAttrib4NubvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NubvARB) +#define glVertexAttrib4NuivARB (_GET_TLS_PROCTABLE()->VertexAttrib4NuivARB) +#define glVertexAttrib4NusvARB (_GET_TLS_PROCTABLE()->VertexAttrib4NusvARB) +#define glVertexAttrib4bvARB (_GET_TLS_PROCTABLE()->VertexAttrib4bvARB) +#define glVertexAttrib4dARB (_GET_TLS_PROCTABLE()->VertexAttrib4dARB) +#define glVertexAttrib4dvARB (_GET_TLS_PROCTABLE()->VertexAttrib4dvARB) +#define glVertexAttrib4fARB (_GET_TLS_PROCTABLE()->VertexAttrib4fARB) +#define glVertexAttrib4fvARB (_GET_TLS_PROCTABLE()->VertexAttrib4fvARB) +#define glVertexAttrib4ivARB (_GET_TLS_PROCTABLE()->VertexAttrib4ivARB) +#define glVertexAttrib4sARB (_GET_TLS_PROCTABLE()->VertexAttrib4sARB) +#define glVertexAttrib4svARB (_GET_TLS_PROCTABLE()->VertexAttrib4svARB) +#define glVertexAttrib4ubvARB (_GET_TLS_PROCTABLE()->VertexAttrib4ubvARB) +#define glVertexAttrib4uivARB (_GET_TLS_PROCTABLE()->VertexAttrib4uivARB) +#define glVertexAttrib4usvARB (_GET_TLS_PROCTABLE()->VertexAttrib4usvARB) +#define glVertexAttribPointerARB (_GET_TLS_PROCTABLE()->VertexAttribPointerARB) +#define glEnableVertexAttribArrayARB (_GET_TLS_PROCTABLE()->EnableVertexAttribArrayARB) +#define glDisableVertexAttribArrayARB (_GET_TLS_PROCTABLE()->DisableVertexAttribArrayARB) +#define glProgramStringARB (_GET_TLS_PROCTABLE()->ProgramStringARB) +#define glBindProgramARB (_GET_TLS_PROCTABLE()->BindProgramARB) +#define glDeleteProgramsARB (_GET_TLS_PROCTABLE()->DeleteProgramsARB) +#define glGenProgramsARB (_GET_TLS_PROCTABLE()->GenProgramsARB) +#define glProgramEnvParameter4dARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4dARB) +#define glProgramEnvParameter4dvARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4dvARB) +#define glProgramEnvParameter4fARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4fARB) +#define glProgramEnvParameter4fvARB (_GET_TLS_PROCTABLE()->ProgramEnvParameter4fvARB) +#define glProgramLocalParameter4dARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4dARB) +#define glProgramLocalParameter4dvARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4dvARB) +#define glProgramLocalParameter4fARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4fARB) +#define glProgramLocalParameter4fvARB (_GET_TLS_PROCTABLE()->ProgramLocalParameter4fvARB) +#define glGetProgramEnvParameterdvARB (_GET_TLS_PROCTABLE()->GetProgramEnvParameterdvARB) +#define glGetProgramEnvParameterfvARB (_GET_TLS_PROCTABLE()->GetProgramEnvParameterfvARB) +#define glGetProgramLocalParameterdvARB (_GET_TLS_PROCTABLE()->GetProgramLocalParameterdvARB) +#define glGetProgramLocalParameterfvARB (_GET_TLS_PROCTABLE()->GetProgramLocalParameterfvARB) +#define glGetProgramivARB (_GET_TLS_PROCTABLE()->GetProgramivARB) +#define glGetProgramStringARB (_GET_TLS_PROCTABLE()->GetProgramStringARB) +#define glGetVertexAttribdvARB (_GET_TLS_PROCTABLE()->GetVertexAttribdvARB) +#define glGetVertexAttribfvARB (_GET_TLS_PROCTABLE()->GetVertexAttribfvARB) +#define glGetVertexAttribivARB (_GET_TLS_PROCTABLE()->GetVertexAttribivARB) +#define glGetVertexAttribPointervARB (_GET_TLS_PROCTABLE()->GetVertexAttribPointervARB) +#define glIsProgramARB (_GET_TLS_PROCTABLE()->IsProgramARB) +#define glBindBufferARB (_GET_TLS_PROCTABLE()->BindBufferARB) +#define glDeleteBuffersARB (_GET_TLS_PROCTABLE()->DeleteBuffersARB) +#define glGenBuffersARB (_GET_TLS_PROCTABLE()->GenBuffersARB) +#define glIsBufferARB (_GET_TLS_PROCTABLE()->IsBufferARB) +#define glBufferDataARB (_GET_TLS_PROCTABLE()->BufferDataARB) +#define glBufferSubDataARB (_GET_TLS_PROCTABLE()->BufferSubDataARB) +#define glGetBufferSubDataARB (_GET_TLS_PROCTABLE()->GetBufferSubDataARB) +#define glMapBufferARB (_GET_TLS_PROCTABLE()->MapBufferARB) +#define glUnmapBufferARB (_GET_TLS_PROCTABLE()->UnmapBufferARB) +#define glGetBufferParameterivARB (_GET_TLS_PROCTABLE()->GetBufferParameterivARB) +#define glGetBufferPointervARB (_GET_TLS_PROCTABLE()->GetBufferPointervARB) +#define glGenQueriesARB (_GET_TLS_PROCTABLE()->GenQueriesARB) +#define glDeleteQueriesARB (_GET_TLS_PROCTABLE()->DeleteQueriesARB) +#define glIsQueryARB (_GET_TLS_PROCTABLE()->IsQueryARB) +#define glBeginQueryARB (_GET_TLS_PROCTABLE()->BeginQueryARB) +#define glEndQueryARB (_GET_TLS_PROCTABLE()->EndQueryARB) +#define glGetQueryivARB (_GET_TLS_PROCTABLE()->GetQueryivARB) +#define glGetQueryObjectivARB (_GET_TLS_PROCTABLE()->GetQueryObjectivARB) +#define glGetQueryObjectuivARB (_GET_TLS_PROCTABLE()->GetQueryObjectuivARB) +#define glDeleteObjectARB (_GET_TLS_PROCTABLE()->DeleteObjectARB) +#define glGetHandleARB (_GET_TLS_PROCTABLE()->GetHandleARB) +#define glDetachObjectARB (_GET_TLS_PROCTABLE()->DetachObjectARB) +#define glCreateShaderObjectARB (_GET_TLS_PROCTABLE()->CreateShaderObjectARB) +#define glShaderSourceARB (_GET_TLS_PROCTABLE()->ShaderSourceARB) +#define glCompileShaderARB (_GET_TLS_PROCTABLE()->CompileShaderARB) +#define glCreateProgramObjectARB (_GET_TLS_PROCTABLE()->CreateProgramObjectARB) +#define glAttachObjectARB (_GET_TLS_PROCTABLE()->AttachObjectARB) +#define glLinkProgramARB (_GET_TLS_PROCTABLE()->LinkProgramARB) +#define glUseProgramObjectARB (_GET_TLS_PROCTABLE()->UseProgramObjectARB) +#define glValidateProgramARB (_GET_TLS_PROCTABLE()->ValidateProgramARB) +#define glUniform1fARB (_GET_TLS_PROCTABLE()->Uniform1fARB) +#define glUniform2fARB (_GET_TLS_PROCTABLE()->Uniform2fARB) +#define glUniform3fARB (_GET_TLS_PROCTABLE()->Uniform3fARB) +#define glUniform4fARB (_GET_TLS_PROCTABLE()->Uniform4fARB) +#define glUniform1iARB (_GET_TLS_PROCTABLE()->Uniform1iARB) +#define glUniform2iARB (_GET_TLS_PROCTABLE()->Uniform2iARB) +#define glUniform3iARB (_GET_TLS_PROCTABLE()->Uniform3iARB) +#define glUniform4iARB (_GET_TLS_PROCTABLE()->Uniform4iARB) +#define glUniform1fvARB (_GET_TLS_PROCTABLE()->Uniform1fvARB) +#define glUniform2fvARB (_GET_TLS_PROCTABLE()->Uniform2fvARB) +#define glUniform3fvARB (_GET_TLS_PROCTABLE()->Uniform3fvARB) +#define glUniform4fvARB (_GET_TLS_PROCTABLE()->Uniform4fvARB) +#define glUniform1ivARB (_GET_TLS_PROCTABLE()->Uniform1ivARB) +#define glUniform2ivARB (_GET_TLS_PROCTABLE()->Uniform2ivARB) +#define glUniform3ivARB (_GET_TLS_PROCTABLE()->Uniform3ivARB) +#define glUniform4ivARB (_GET_TLS_PROCTABLE()->Uniform4ivARB) +#define glUniformMatrix2fvARB (_GET_TLS_PROCTABLE()->UniformMatrix2fvARB) +#define glUniformMatrix3fvARB (_GET_TLS_PROCTABLE()->UniformMatrix3fvARB) +#define glUniformMatrix4fvARB (_GET_TLS_PROCTABLE()->UniformMatrix4fvARB) +#define glGetObjectParameterfvARB (_GET_TLS_PROCTABLE()->GetObjectParameterfvARB) +#define glGetObjectParameterivARB (_GET_TLS_PROCTABLE()->GetObjectParameterivARB) +#define glGetInfoLogARB (_GET_TLS_PROCTABLE()->GetInfoLogARB) +#define glGetAttachedObjectsARB (_GET_TLS_PROCTABLE()->GetAttachedObjectsARB) +#define glGetUniformLocationARB (_GET_TLS_PROCTABLE()->GetUniformLocationARB) +#define glGetActiveUniformARB (_GET_TLS_PROCTABLE()->GetActiveUniformARB) +#define glGetUniformfvARB (_GET_TLS_PROCTABLE()->GetUniformfvARB) +#define glGetUniformivARB (_GET_TLS_PROCTABLE()->GetUniformivARB) +#define glGetShaderSourceARB (_GET_TLS_PROCTABLE()->GetShaderSourceARB) +#define glBindAttribLocationARB (_GET_TLS_PROCTABLE()->BindAttribLocationARB) +#define glGetActiveAttribARB (_GET_TLS_PROCTABLE()->GetActiveAttribARB) +#define glGetAttribLocationARB (_GET_TLS_PROCTABLE()->GetAttribLocationARB) +#define glBlendColorEXT (_GET_TLS_PROCTABLE()->BlendColorEXT) +#define glPolygonOffsetEXT (_GET_TLS_PROCTABLE()->PolygonOffsetEXT) +#define glTexImage3DEXT (_GET_TLS_PROCTABLE()->TexImage3DEXT) +#define glTexSubImage3DEXT (_GET_TLS_PROCTABLE()->TexSubImage3DEXT) +#define glGetTexFilterFuncSGIS (_GET_TLS_PROCTABLE()->GetTexFilterFuncSGIS) +#define glTexFilterFuncSGIS (_GET_TLS_PROCTABLE()->TexFilterFuncSGIS) +#define glTexSubImage1DEXT (_GET_TLS_PROCTABLE()->TexSubImage1DEXT) +#define glTexSubImage2DEXT (_GET_TLS_PROCTABLE()->TexSubImage2DEXT) +#define glCopyTexImage1DEXT (_GET_TLS_PROCTABLE()->CopyTexImage1DEXT) +#define glCopyTexImage2DEXT (_GET_TLS_PROCTABLE()->CopyTexImage2DEXT) +#define glCopyTexSubImage1DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage1DEXT) +#define glCopyTexSubImage2DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage2DEXT) +#define glCopyTexSubImage3DEXT (_GET_TLS_PROCTABLE()->CopyTexSubImage3DEXT) +#define glGetHistogramEXT (_GET_TLS_PROCTABLE()->GetHistogramEXT) +#define glGetHistogramParameterfvEXT (_GET_TLS_PROCTABLE()->GetHistogramParameterfvEXT) +#define glGetHistogramParameterivEXT (_GET_TLS_PROCTABLE()->GetHistogramParameterivEXT) +#define glGetMinmaxEXT (_GET_TLS_PROCTABLE()->GetMinmaxEXT) +#define glGetMinmaxParameterfvEXT (_GET_TLS_PROCTABLE()->GetMinmaxParameterfvEXT) +#define glGetMinmaxParameterivEXT (_GET_TLS_PROCTABLE()->GetMinmaxParameterivEXT) +#define glHistogramEXT (_GET_TLS_PROCTABLE()->HistogramEXT) +#define glMinmaxEXT (_GET_TLS_PROCTABLE()->MinmaxEXT) +#define glResetHistogramEXT (_GET_TLS_PROCTABLE()->ResetHistogramEXT) +#define glResetMinmaxEXT (_GET_TLS_PROCTABLE()->ResetMinmaxEXT) +#define glConvolutionFilter1DEXT (_GET_TLS_PROCTABLE()->ConvolutionFilter1DEXT) +#define glConvolutionFilter2DEXT (_GET_TLS_PROCTABLE()->ConvolutionFilter2DEXT) +#define glConvolutionParameterfEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterfEXT) +#define glConvolutionParameterfvEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterfvEXT) +#define glConvolutionParameteriEXT (_GET_TLS_PROCTABLE()->ConvolutionParameteriEXT) +#define glConvolutionParameterivEXT (_GET_TLS_PROCTABLE()->ConvolutionParameterivEXT) +#define glCopyConvolutionFilter1DEXT (_GET_TLS_PROCTABLE()->CopyConvolutionFilter1DEXT) +#define glCopyConvolutionFilter2DEXT (_GET_TLS_PROCTABLE()->CopyConvolutionFilter2DEXT) +#define glGetConvolutionFilterEXT (_GET_TLS_PROCTABLE()->GetConvolutionFilterEXT) +#define glGetConvolutionParameterfvEXT (_GET_TLS_PROCTABLE()->GetConvolutionParameterfvEXT) +#define glGetConvolutionParameterivEXT (_GET_TLS_PROCTABLE()->GetConvolutionParameterivEXT) +#define glGetSeparableFilterEXT (_GET_TLS_PROCTABLE()->GetSeparableFilterEXT) +#define glSeparableFilter2DEXT (_GET_TLS_PROCTABLE()->SeparableFilter2DEXT) +#define glColorTableSGI (_GET_TLS_PROCTABLE()->ColorTableSGI) +#define glColorTableParameterfvSGI (_GET_TLS_PROCTABLE()->ColorTableParameterfvSGI) +#define glColorTableParameterivSGI (_GET_TLS_PROCTABLE()->ColorTableParameterivSGI) +#define glCopyColorTableSGI (_GET_TLS_PROCTABLE()->CopyColorTableSGI) +#define glGetColorTableSGI (_GET_TLS_PROCTABLE()->GetColorTableSGI) +#define glGetColorTableParameterfvSGI (_GET_TLS_PROCTABLE()->GetColorTableParameterfvSGI) +#define glGetColorTableParameterivSGI (_GET_TLS_PROCTABLE()->GetColorTableParameterivSGI) +#define glPixelTexGenSGIX (_GET_TLS_PROCTABLE()->PixelTexGenSGIX) +#define glPixelTexGenParameteriSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameteriSGIS) +#define glPixelTexGenParameterivSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterivSGIS) +#define glPixelTexGenParameterfSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterfSGIS) +#define glPixelTexGenParameterfvSGIS (_GET_TLS_PROCTABLE()->PixelTexGenParameterfvSGIS) +#define glGetPixelTexGenParameterivSGIS (_GET_TLS_PROCTABLE()->GetPixelTexGenParameterivSGIS) +#define glGetPixelTexGenParameterfvSGIS (_GET_TLS_PROCTABLE()->GetPixelTexGenParameterfvSGIS) +#define glTexImage4DSGIS (_GET_TLS_PROCTABLE()->TexImage4DSGIS) +#define glTexSubImage4DSGIS (_GET_TLS_PROCTABLE()->TexSubImage4DSGIS) +#define glAreTexturesResidentEXT (_GET_TLS_PROCTABLE()->AreTexturesResidentEXT) +#define glBindTextureEXT (_GET_TLS_PROCTABLE()->BindTextureEXT) +#define glDeleteTexturesEXT (_GET_TLS_PROCTABLE()->DeleteTexturesEXT) +#define glGenTexturesEXT (_GET_TLS_PROCTABLE()->GenTexturesEXT) +#define glIsTextureEXT (_GET_TLS_PROCTABLE()->IsTextureEXT) +#define glPrioritizeTexturesEXT (_GET_TLS_PROCTABLE()->PrioritizeTexturesEXT) +#define glDetailTexFuncSGIS (_GET_TLS_PROCTABLE()->DetailTexFuncSGIS) +#define glGetDetailTexFuncSGIS (_GET_TLS_PROCTABLE()->GetDetailTexFuncSGIS) +#define glSharpenTexFuncSGIS (_GET_TLS_PROCTABLE()->SharpenTexFuncSGIS) +#define glGetSharpenTexFuncSGIS (_GET_TLS_PROCTABLE()->GetSharpenTexFuncSGIS) +#define glSampleMaskSGIS (_GET_TLS_PROCTABLE()->SampleMaskSGIS) +#define glSamplePatternSGIS (_GET_TLS_PROCTABLE()->SamplePatternSGIS) +#define glArrayElementEXT (_GET_TLS_PROCTABLE()->ArrayElementEXT) +#define glColorPointerEXT (_GET_TLS_PROCTABLE()->ColorPointerEXT) +#define glDrawArraysEXT (_GET_TLS_PROCTABLE()->DrawArraysEXT) +#define glEdgeFlagPointerEXT (_GET_TLS_PROCTABLE()->EdgeFlagPointerEXT) +#define glGetPointervEXT (_GET_TLS_PROCTABLE()->GetPointervEXT) +#define glIndexPointerEXT (_GET_TLS_PROCTABLE()->IndexPointerEXT) +#define glNormalPointerEXT (_GET_TLS_PROCTABLE()->NormalPointerEXT) +#define glTexCoordPointerEXT (_GET_TLS_PROCTABLE()->TexCoordPointerEXT) +#define glVertexPointerEXT (_GET_TLS_PROCTABLE()->VertexPointerEXT) +#define glBlendEquationEXT (_GET_TLS_PROCTABLE()->BlendEquationEXT) +#define glSpriteParameterfSGIX (_GET_TLS_PROCTABLE()->SpriteParameterfSGIX) +#define glSpriteParameterfvSGIX (_GET_TLS_PROCTABLE()->SpriteParameterfvSGIX) +#define glSpriteParameteriSGIX (_GET_TLS_PROCTABLE()->SpriteParameteriSGIX) +#define glSpriteParameterivSGIX (_GET_TLS_PROCTABLE()->SpriteParameterivSGIX) +#define glPointParameterfEXT (_GET_TLS_PROCTABLE()->PointParameterfEXT) +#define glPointParameterfvEXT (_GET_TLS_PROCTABLE()->PointParameterfvEXT) +#define glPointParameterfSGIS (_GET_TLS_PROCTABLE()->PointParameterfSGIS) +#define glPointParameterfvSGIS (_GET_TLS_PROCTABLE()->PointParameterfvSGIS) +#define glGetInstrumentsSGIX (_GET_TLS_PROCTABLE()->GetInstrumentsSGIX) +#define glInstrumentsBufferSGIX (_GET_TLS_PROCTABLE()->InstrumentsBufferSGIX) +#define glPollInstrumentsSGIX (_GET_TLS_PROCTABLE()->PollInstrumentsSGIX) +#define glReadInstrumentsSGIX (_GET_TLS_PROCTABLE()->ReadInstrumentsSGIX) +#define glStartInstrumentsSGIX (_GET_TLS_PROCTABLE()->StartInstrumentsSGIX) +#define glStopInstrumentsSGIX (_GET_TLS_PROCTABLE()->StopInstrumentsSGIX) +#define glFrameZoomSGIX (_GET_TLS_PROCTABLE()->FrameZoomSGIX) +#define glTagSampleBufferSGIX (_GET_TLS_PROCTABLE()->TagSampleBufferSGIX) +#define glDeformationMap3dSGIX (_GET_TLS_PROCTABLE()->DeformationMap3dSGIX) +#define glDeformationMap3fSGIX (_GET_TLS_PROCTABLE()->DeformationMap3fSGIX) +#define glDeformSGIX (_GET_TLS_PROCTABLE()->DeformSGIX) +#define glLoadIdentityDeformationMapSGIX (_GET_TLS_PROCTABLE()->LoadIdentityDeformationMapSGIX) +#define glReferencePlaneSGIX (_GET_TLS_PROCTABLE()->ReferencePlaneSGIX) +#define glFlushRasterSGIX (_GET_TLS_PROCTABLE()->FlushRasterSGIX) +#define glFogFuncSGIS (_GET_TLS_PROCTABLE()->FogFuncSGIS) +#define glGetFogFuncSGIS (_GET_TLS_PROCTABLE()->GetFogFuncSGIS) +#define glImageTransformParameteriHP (_GET_TLS_PROCTABLE()->ImageTransformParameteriHP) +#define glImageTransformParameterfHP (_GET_TLS_PROCTABLE()->ImageTransformParameterfHP) +#define glImageTransformParameterivHP (_GET_TLS_PROCTABLE()->ImageTransformParameterivHP) +#define glImageTransformParameterfvHP (_GET_TLS_PROCTABLE()->ImageTransformParameterfvHP) +#define glGetImageTransformParameterivHP (_GET_TLS_PROCTABLE()->GetImageTransformParameterivHP) +#define glGetImageTransformParameterfvHP (_GET_TLS_PROCTABLE()->GetImageTransformParameterfvHP) +#define glColorSubTableEXT (_GET_TLS_PROCTABLE()->ColorSubTableEXT) +#define glCopyColorSubTableEXT (_GET_TLS_PROCTABLE()->CopyColorSubTableEXT) +#define glHintPGI (_GET_TLS_PROCTABLE()->HintPGI) +#define glColorTableEXT (_GET_TLS_PROCTABLE()->ColorTableEXT) +#define glGetColorTableEXT (_GET_TLS_PROCTABLE()->GetColorTableEXT) +#define glGetColorTableParameterivEXT (_GET_TLS_PROCTABLE()->GetColorTableParameterivEXT) +#define glGetColorTableParameterfvEXT (_GET_TLS_PROCTABLE()->GetColorTableParameterfvEXT) +#define glGetListParameterfvSGIX (_GET_TLS_PROCTABLE()->GetListParameterfvSGIX) +#define glGetListParameterivSGIX (_GET_TLS_PROCTABLE()->GetListParameterivSGIX) +#define glListParameterfSGIX (_GET_TLS_PROCTABLE()->ListParameterfSGIX) +#define glListParameterfvSGIX (_GET_TLS_PROCTABLE()->ListParameterfvSGIX) +#define glListParameteriSGIX (_GET_TLS_PROCTABLE()->ListParameteriSGIX) +#define glListParameterivSGIX (_GET_TLS_PROCTABLE()->ListParameterivSGIX) +#define glIndexMaterialEXT (_GET_TLS_PROCTABLE()->IndexMaterialEXT) +#define glIndexFuncEXT (_GET_TLS_PROCTABLE()->IndexFuncEXT) +#define glLockArraysEXT (_GET_TLS_PROCTABLE()->LockArraysEXT) +#define glUnlockArraysEXT (_GET_TLS_PROCTABLE()->UnlockArraysEXT) +#define glCullParameterdvEXT (_GET_TLS_PROCTABLE()->CullParameterdvEXT) +#define glCullParameterfvEXT (_GET_TLS_PROCTABLE()->CullParameterfvEXT) +#define glFragmentColorMaterialSGIX (_GET_TLS_PROCTABLE()->FragmentColorMaterialSGIX) +#define glFragmentLightfSGIX (_GET_TLS_PROCTABLE()->FragmentLightfSGIX) +#define glFragmentLightfvSGIX (_GET_TLS_PROCTABLE()->FragmentLightfvSGIX) +#define glFragmentLightiSGIX (_GET_TLS_PROCTABLE()->FragmentLightiSGIX) +#define glFragmentLightivSGIX (_GET_TLS_PROCTABLE()->FragmentLightivSGIX) +#define glFragmentLightModelfSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelfSGIX) +#define glFragmentLightModelfvSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelfvSGIX) +#define glFragmentLightModeliSGIX (_GET_TLS_PROCTABLE()->FragmentLightModeliSGIX) +#define glFragmentLightModelivSGIX (_GET_TLS_PROCTABLE()->FragmentLightModelivSGIX) +#define glFragmentMaterialfSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialfSGIX) +#define glFragmentMaterialfvSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialfvSGIX) +#define glFragmentMaterialiSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialiSGIX) +#define glFragmentMaterialivSGIX (_GET_TLS_PROCTABLE()->FragmentMaterialivSGIX) +#define glGetFragmentLightfvSGIX (_GET_TLS_PROCTABLE()->GetFragmentLightfvSGIX) +#define glGetFragmentLightivSGIX (_GET_TLS_PROCTABLE()->GetFragmentLightivSGIX) +#define glGetFragmentMaterialfvSGIX (_GET_TLS_PROCTABLE()->GetFragmentMaterialfvSGIX) +#define glGetFragmentMaterialivSGIX (_GET_TLS_PROCTABLE()->GetFragmentMaterialivSGIX) +#define glLightEnviSGIX (_GET_TLS_PROCTABLE()->LightEnviSGIX) +#define glDrawRangeElementsEXT (_GET_TLS_PROCTABLE()->DrawRangeElementsEXT) +#define glApplyTextureEXT (_GET_TLS_PROCTABLE()->ApplyTextureEXT) +#define glTextureLightEXT (_GET_TLS_PROCTABLE()->TextureLightEXT) +#define glTextureMaterialEXT (_GET_TLS_PROCTABLE()->TextureMaterialEXT) +#define glAsyncMarkerSGIX (_GET_TLS_PROCTABLE()->AsyncMarkerSGIX) +#define glFinishAsyncSGIX (_GET_TLS_PROCTABLE()->FinishAsyncSGIX) +#define glPollAsyncSGIX (_GET_TLS_PROCTABLE()->PollAsyncSGIX) +#define glGenAsyncMarkersSGIX (_GET_TLS_PROCTABLE()->GenAsyncMarkersSGIX) +#define glDeleteAsyncMarkersSGIX (_GET_TLS_PROCTABLE()->DeleteAsyncMarkersSGIX) +#define glIsAsyncMarkerSGIX (_GET_TLS_PROCTABLE()->IsAsyncMarkerSGIX) +#define glVertexPointervINTEL (_GET_TLS_PROCTABLE()->VertexPointervINTEL) +#define glNormalPointervINTEL (_GET_TLS_PROCTABLE()->NormalPointervINTEL) +#define glColorPointervINTEL (_GET_TLS_PROCTABLE()->ColorPointervINTEL) +#define glTexCoordPointervINTEL (_GET_TLS_PROCTABLE()->TexCoordPointervINTEL) +#define glPixelTransformParameteriEXT (_GET_TLS_PROCTABLE()->PixelTransformParameteriEXT) +#define glPixelTransformParameterfEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterfEXT) +#define glPixelTransformParameterivEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterivEXT) +#define glPixelTransformParameterfvEXT (_GET_TLS_PROCTABLE()->PixelTransformParameterfvEXT) +#define glSecondaryColor3bEXT (_GET_TLS_PROCTABLE()->SecondaryColor3bEXT) +#define glSecondaryColor3bvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3bvEXT) +#define glSecondaryColor3dEXT (_GET_TLS_PROCTABLE()->SecondaryColor3dEXT) +#define glSecondaryColor3dvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3dvEXT) +#define glSecondaryColor3fEXT (_GET_TLS_PROCTABLE()->SecondaryColor3fEXT) +#define glSecondaryColor3fvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3fvEXT) +#define glSecondaryColor3iEXT (_GET_TLS_PROCTABLE()->SecondaryColor3iEXT) +#define glSecondaryColor3ivEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ivEXT) +#define glSecondaryColor3sEXT (_GET_TLS_PROCTABLE()->SecondaryColor3sEXT) +#define glSecondaryColor3svEXT (_GET_TLS_PROCTABLE()->SecondaryColor3svEXT) +#define glSecondaryColor3ubEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ubEXT) +#define glSecondaryColor3ubvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3ubvEXT) +#define glSecondaryColor3uiEXT (_GET_TLS_PROCTABLE()->SecondaryColor3uiEXT) +#define glSecondaryColor3uivEXT (_GET_TLS_PROCTABLE()->SecondaryColor3uivEXT) +#define glSecondaryColor3usEXT (_GET_TLS_PROCTABLE()->SecondaryColor3usEXT) +#define glSecondaryColor3usvEXT (_GET_TLS_PROCTABLE()->SecondaryColor3usvEXT) +#define glSecondaryColorPointerEXT (_GET_TLS_PROCTABLE()->SecondaryColorPointerEXT) +#define glTextureNormalEXT (_GET_TLS_PROCTABLE()->TextureNormalEXT) +#define glMultiDrawArraysEXT (_GET_TLS_PROCTABLE()->MultiDrawArraysEXT) +#define glMultiDrawElementsEXT (_GET_TLS_PROCTABLE()->MultiDrawElementsEXT) +#define glFogCoordfEXT (_GET_TLS_PROCTABLE()->FogCoordfEXT) +#define glFogCoordfvEXT (_GET_TLS_PROCTABLE()->FogCoordfvEXT) +#define glFogCoorddEXT (_GET_TLS_PROCTABLE()->FogCoorddEXT) +#define glFogCoorddvEXT (_GET_TLS_PROCTABLE()->FogCoorddvEXT) +#define glFogCoordPointerEXT (_GET_TLS_PROCTABLE()->FogCoordPointerEXT) +#define glTangent3bEXT (_GET_TLS_PROCTABLE()->Tangent3bEXT) +#define glTangent3bvEXT (_GET_TLS_PROCTABLE()->Tangent3bvEXT) +#define glTangent3dEXT (_GET_TLS_PROCTABLE()->Tangent3dEXT) +#define glTangent3dvEXT (_GET_TLS_PROCTABLE()->Tangent3dvEXT) +#define glTangent3fEXT (_GET_TLS_PROCTABLE()->Tangent3fEXT) +#define glTangent3fvEXT (_GET_TLS_PROCTABLE()->Tangent3fvEXT) +#define glTangent3iEXT (_GET_TLS_PROCTABLE()->Tangent3iEXT) +#define glTangent3ivEXT (_GET_TLS_PROCTABLE()->Tangent3ivEXT) +#define glTangent3sEXT (_GET_TLS_PROCTABLE()->Tangent3sEXT) +#define glTangent3svEXT (_GET_TLS_PROCTABLE()->Tangent3svEXT) +#define glBinormal3bEXT (_GET_TLS_PROCTABLE()->Binormal3bEXT) +#define glBinormal3bvEXT (_GET_TLS_PROCTABLE()->Binormal3bvEXT) +#define glBinormal3dEXT (_GET_TLS_PROCTABLE()->Binormal3dEXT) +#define glBinormal3dvEXT (_GET_TLS_PROCTABLE()->Binormal3dvEXT) +#define glBinormal3fEXT (_GET_TLS_PROCTABLE()->Binormal3fEXT) +#define glBinormal3fvEXT (_GET_TLS_PROCTABLE()->Binormal3fvEXT) +#define glBinormal3iEXT (_GET_TLS_PROCTABLE()->Binormal3iEXT) +#define glBinormal3ivEXT (_GET_TLS_PROCTABLE()->Binormal3ivEXT) +#define glBinormal3sEXT (_GET_TLS_PROCTABLE()->Binormal3sEXT) +#define glBinormal3svEXT (_GET_TLS_PROCTABLE()->Binormal3svEXT) +#define glTangentPointerEXT (_GET_TLS_PROCTABLE()->TangentPointerEXT) +#define glBinormalPointerEXT (_GET_TLS_PROCTABLE()->BinormalPointerEXT) +#define glFinishTextureSUNX (_GET_TLS_PROCTABLE()->FinishTextureSUNX) +#define glGlobalAlphaFactorbSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorbSUN) +#define glGlobalAlphaFactorsSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorsSUN) +#define glGlobalAlphaFactoriSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactoriSUN) +#define glGlobalAlphaFactorfSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorfSUN) +#define glGlobalAlphaFactordSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactordSUN) +#define glGlobalAlphaFactorubSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorubSUN) +#define glGlobalAlphaFactorusSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactorusSUN) +#define glGlobalAlphaFactoruiSUN (_GET_TLS_PROCTABLE()->GlobalAlphaFactoruiSUN) +#define glReplacementCodeuiSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiSUN) +#define glReplacementCodeusSUN (_GET_TLS_PROCTABLE()->ReplacementCodeusSUN) +#define glReplacementCodeubSUN (_GET_TLS_PROCTABLE()->ReplacementCodeubSUN) +#define glReplacementCodeuivSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuivSUN) +#define glReplacementCodeusvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeusvSUN) +#define glReplacementCodeubvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeubvSUN) +#define glReplacementCodePointerSUN (_GET_TLS_PROCTABLE()->ReplacementCodePointerSUN) +#define glColor4ubVertex2fSUN (_GET_TLS_PROCTABLE()->Color4ubVertex2fSUN) +#define glColor4ubVertex2fvSUN (_GET_TLS_PROCTABLE()->Color4ubVertex2fvSUN) +#define glColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->Color4ubVertex3fSUN) +#define glColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->Color4ubVertex3fvSUN) +#define glColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->Color3fVertex3fSUN) +#define glColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Color3fVertex3fvSUN) +#define glNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->Normal3fVertex3fSUN) +#define glNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Normal3fVertex3fvSUN) +#define glColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->Color4fNormal3fVertex3fSUN) +#define glColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->Color4fNormal3fVertex3fvSUN) +#define glTexCoord2fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fVertex3fSUN) +#define glTexCoord2fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fVertex3fvSUN) +#define glTexCoord4fVertex4fSUN (_GET_TLS_PROCTABLE()->TexCoord4fVertex4fSUN) +#define glTexCoord4fVertex4fvSUN (_GET_TLS_PROCTABLE()->TexCoord4fVertex4fvSUN) +#define glTexCoord2fColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4ubVertex3fSUN) +#define glTexCoord2fColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4ubVertex3fvSUN) +#define glTexCoord2fColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor3fVertex3fSUN) +#define glTexCoord2fColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor3fVertex3fvSUN) +#define glTexCoord2fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fNormal3fVertex3fSUN) +#define glTexCoord2fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fNormal3fVertex3fvSUN) +#define glTexCoord2fColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4fNormal3fVertex3fSUN) +#define glTexCoord2fColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->TexCoord2fColor4fNormal3fVertex3fvSUN) +#define glTexCoord4fColor4fNormal3fVertex4fSUN (_GET_TLS_PROCTABLE()->TexCoord4fColor4fNormal3fVertex4fSUN) +#define glTexCoord4fColor4fNormal3fVertex4fvSUN (_GET_TLS_PROCTABLE()->TexCoord4fColor4fNormal3fVertex4fvSUN) +#define glReplacementCodeuiVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiVertex3fSUN) +#define glReplacementCodeuiVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiVertex3fvSUN) +#define glReplacementCodeuiColor4ubVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4ubVertex3fSUN) +#define glReplacementCodeuiColor4ubVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4ubVertex3fvSUN) +#define glReplacementCodeuiColor3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor3fVertex3fSUN) +#define glReplacementCodeuiColor3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor3fVertex3fvSUN) +#define glReplacementCodeuiNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiNormal3fVertex3fSUN) +#define glReplacementCodeuiNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiNormal3fVertex3fvSUN) +#define glReplacementCodeuiColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4fNormal3fVertex3fSUN) +#define glReplacementCodeuiColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiColor4fNormal3fVertex3fvSUN) +#define glReplacementCodeuiTexCoord2fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fVertex3fSUN) +#define glReplacementCodeuiTexCoord2fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fVertex3fvSUN) +#define glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fNormal3fVertex3fSUN) +#define glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN) +#define glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN) +#define glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (_GET_TLS_PROCTABLE()->ReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN) +#define glBlendFuncSeparateEXT (_GET_TLS_PROCTABLE()->BlendFuncSeparateEXT) +#define glBlendFuncSeparateINGR (_GET_TLS_PROCTABLE()->BlendFuncSeparateINGR) +#define glVertexWeightfEXT (_GET_TLS_PROCTABLE()->VertexWeightfEXT) +#define glVertexWeightfvEXT (_GET_TLS_PROCTABLE()->VertexWeightfvEXT) +#define glVertexWeightPointerEXT (_GET_TLS_PROCTABLE()->VertexWeightPointerEXT) +#define glFlushVertexArrayRangeNV (_GET_TLS_PROCTABLE()->FlushVertexArrayRangeNV) +#define glVertexArrayRangeNV (_GET_TLS_PROCTABLE()->VertexArrayRangeNV) +#define glCombinerParameterfvNV (_GET_TLS_PROCTABLE()->CombinerParameterfvNV) +#define glCombinerParameterfNV (_GET_TLS_PROCTABLE()->CombinerParameterfNV) +#define glCombinerParameterivNV (_GET_TLS_PROCTABLE()->CombinerParameterivNV) +#define glCombinerParameteriNV (_GET_TLS_PROCTABLE()->CombinerParameteriNV) +#define glCombinerInputNV (_GET_TLS_PROCTABLE()->CombinerInputNV) +#define glCombinerOutputNV (_GET_TLS_PROCTABLE()->CombinerOutputNV) +#define glFinalCombinerInputNV (_GET_TLS_PROCTABLE()->FinalCombinerInputNV) +#define glGetCombinerInputParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerInputParameterfvNV) +#define glGetCombinerInputParameterivNV (_GET_TLS_PROCTABLE()->GetCombinerInputParameterivNV) +#define glGetCombinerOutputParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerOutputParameterfvNV) +#define glGetCombinerOutputParameterivNV (_GET_TLS_PROCTABLE()->GetCombinerOutputParameterivNV) +#define glGetFinalCombinerInputParameterfvNV (_GET_TLS_PROCTABLE()->GetFinalCombinerInputParameterfvNV) +#define glGetFinalCombinerInputParameterivNV (_GET_TLS_PROCTABLE()->GetFinalCombinerInputParameterivNV) +#define glResizeBuffersMESA (_GET_TLS_PROCTABLE()->ResizeBuffersMESA) +#define glWindowPos2dMESA (_GET_TLS_PROCTABLE()->WindowPos2dMESA) +#define glWindowPos2dvMESA (_GET_TLS_PROCTABLE()->WindowPos2dvMESA) +#define glWindowPos2fMESA (_GET_TLS_PROCTABLE()->WindowPos2fMESA) +#define glWindowPos2fvMESA (_GET_TLS_PROCTABLE()->WindowPos2fvMESA) +#define glWindowPos2iMESA (_GET_TLS_PROCTABLE()->WindowPos2iMESA) +#define glWindowPos2ivMESA (_GET_TLS_PROCTABLE()->WindowPos2ivMESA) +#define glWindowPos2sMESA (_GET_TLS_PROCTABLE()->WindowPos2sMESA) +#define glWindowPos2svMESA (_GET_TLS_PROCTABLE()->WindowPos2svMESA) +#define glWindowPos3dMESA (_GET_TLS_PROCTABLE()->WindowPos3dMESA) +#define glWindowPos3dvMESA (_GET_TLS_PROCTABLE()->WindowPos3dvMESA) +#define glWindowPos3fMESA (_GET_TLS_PROCTABLE()->WindowPos3fMESA) +#define glWindowPos3fvMESA (_GET_TLS_PROCTABLE()->WindowPos3fvMESA) +#define glWindowPos3iMESA (_GET_TLS_PROCTABLE()->WindowPos3iMESA) +#define glWindowPos3ivMESA (_GET_TLS_PROCTABLE()->WindowPos3ivMESA) +#define glWindowPos3sMESA (_GET_TLS_PROCTABLE()->WindowPos3sMESA) +#define glWindowPos3svMESA (_GET_TLS_PROCTABLE()->WindowPos3svMESA) +#define glWindowPos4dMESA (_GET_TLS_PROCTABLE()->WindowPos4dMESA) +#define glWindowPos4dvMESA (_GET_TLS_PROCTABLE()->WindowPos4dvMESA) +#define glWindowPos4fMESA (_GET_TLS_PROCTABLE()->WindowPos4fMESA) +#define glWindowPos4fvMESA (_GET_TLS_PROCTABLE()->WindowPos4fvMESA) +#define glWindowPos4iMESA (_GET_TLS_PROCTABLE()->WindowPos4iMESA) +#define glWindowPos4ivMESA (_GET_TLS_PROCTABLE()->WindowPos4ivMESA) +#define glWindowPos4sMESA (_GET_TLS_PROCTABLE()->WindowPos4sMESA) +#define glWindowPos4svMESA (_GET_TLS_PROCTABLE()->WindowPos4svMESA) +#define glMultiModeDrawArraysIBM (_GET_TLS_PROCTABLE()->MultiModeDrawArraysIBM) +#define glMultiModeDrawElementsIBM (_GET_TLS_PROCTABLE()->MultiModeDrawElementsIBM) +#define glColorPointerListIBM (_GET_TLS_PROCTABLE()->ColorPointerListIBM) +#define glSecondaryColorPointerListIBM (_GET_TLS_PROCTABLE()->SecondaryColorPointerListIBM) +#define glEdgeFlagPointerListIBM (_GET_TLS_PROCTABLE()->EdgeFlagPointerListIBM) +#define glFogCoordPointerListIBM (_GET_TLS_PROCTABLE()->FogCoordPointerListIBM) +#define glIndexPointerListIBM (_GET_TLS_PROCTABLE()->IndexPointerListIBM) +#define glNormalPointerListIBM (_GET_TLS_PROCTABLE()->NormalPointerListIBM) +#define glTexCoordPointerListIBM (_GET_TLS_PROCTABLE()->TexCoordPointerListIBM) +#define glVertexPointerListIBM (_GET_TLS_PROCTABLE()->VertexPointerListIBM) +#define glTbufferMask3DFX (_GET_TLS_PROCTABLE()->TbufferMask3DFX) +#define glSampleMaskEXT (_GET_TLS_PROCTABLE()->SampleMaskEXT) +#define glSamplePatternEXT (_GET_TLS_PROCTABLE()->SamplePatternEXT) +#define glTextureColorMaskSGIS (_GET_TLS_PROCTABLE()->TextureColorMaskSGIS) +#define glIglooInterfaceSGIX (_GET_TLS_PROCTABLE()->IglooInterfaceSGIX) +#define glDeleteFencesNV (_GET_TLS_PROCTABLE()->DeleteFencesNV) +#define glGenFencesNV (_GET_TLS_PROCTABLE()->GenFencesNV) +#define glIsFenceNV (_GET_TLS_PROCTABLE()->IsFenceNV) +#define glTestFenceNV (_GET_TLS_PROCTABLE()->TestFenceNV) +#define glGetFenceivNV (_GET_TLS_PROCTABLE()->GetFenceivNV) +#define glFinishFenceNV (_GET_TLS_PROCTABLE()->FinishFenceNV) +#define glSetFenceNV (_GET_TLS_PROCTABLE()->SetFenceNV) +#define glMapControlPointsNV (_GET_TLS_PROCTABLE()->MapControlPointsNV) +#define glMapParameterivNV (_GET_TLS_PROCTABLE()->MapParameterivNV) +#define glMapParameterfvNV (_GET_TLS_PROCTABLE()->MapParameterfvNV) +#define glGetMapControlPointsNV (_GET_TLS_PROCTABLE()->GetMapControlPointsNV) +#define glGetMapParameterivNV (_GET_TLS_PROCTABLE()->GetMapParameterivNV) +#define glGetMapParameterfvNV (_GET_TLS_PROCTABLE()->GetMapParameterfvNV) +#define glGetMapAttribParameterivNV (_GET_TLS_PROCTABLE()->GetMapAttribParameterivNV) +#define glGetMapAttribParameterfvNV (_GET_TLS_PROCTABLE()->GetMapAttribParameterfvNV) +#define glEvalMapsNV (_GET_TLS_PROCTABLE()->EvalMapsNV) +#define glCombinerStageParameterfvNV (_GET_TLS_PROCTABLE()->CombinerStageParameterfvNV) +#define glGetCombinerStageParameterfvNV (_GET_TLS_PROCTABLE()->GetCombinerStageParameterfvNV) +#define glAreProgramsResidentNV (_GET_TLS_PROCTABLE()->AreProgramsResidentNV) +#define glBindProgramNV (_GET_TLS_PROCTABLE()->BindProgramNV) +#define glDeleteProgramsNV (_GET_TLS_PROCTABLE()->DeleteProgramsNV) +#define glExecuteProgramNV (_GET_TLS_PROCTABLE()->ExecuteProgramNV) +#define glGenProgramsNV (_GET_TLS_PROCTABLE()->GenProgramsNV) +#define glGetProgramParameterdvNV (_GET_TLS_PROCTABLE()->GetProgramParameterdvNV) +#define glGetProgramParameterfvNV (_GET_TLS_PROCTABLE()->GetProgramParameterfvNV) +#define glGetProgramivNV (_GET_TLS_PROCTABLE()->GetProgramivNV) +#define glGetProgramStringNV (_GET_TLS_PROCTABLE()->GetProgramStringNV) +#define glGetTrackMatrixivNV (_GET_TLS_PROCTABLE()->GetTrackMatrixivNV) +#define glGetVertexAttribdvNV (_GET_TLS_PROCTABLE()->GetVertexAttribdvNV) +#define glGetVertexAttribfvNV (_GET_TLS_PROCTABLE()->GetVertexAttribfvNV) +#define glGetVertexAttribivNV (_GET_TLS_PROCTABLE()->GetVertexAttribivNV) +#define glGetVertexAttribPointervNV (_GET_TLS_PROCTABLE()->GetVertexAttribPointervNV) +#define glIsProgramNV (_GET_TLS_PROCTABLE()->IsProgramNV) +#define glLoadProgramNV (_GET_TLS_PROCTABLE()->LoadProgramNV) +#define glProgramParameter4dNV (_GET_TLS_PROCTABLE()->ProgramParameter4dNV) +#define glProgramParameter4dvNV (_GET_TLS_PROCTABLE()->ProgramParameter4dvNV) +#define glProgramParameter4fNV (_GET_TLS_PROCTABLE()->ProgramParameter4fNV) +#define glProgramParameter4fvNV (_GET_TLS_PROCTABLE()->ProgramParameter4fvNV) +#define glProgramParameters4dvNV (_GET_TLS_PROCTABLE()->ProgramParameters4dvNV) +#define glProgramParameters4fvNV (_GET_TLS_PROCTABLE()->ProgramParameters4fvNV) +#define glRequestResidentProgramsNV (_GET_TLS_PROCTABLE()->RequestResidentProgramsNV) +#define glTrackMatrixNV (_GET_TLS_PROCTABLE()->TrackMatrixNV) +#define glVertexAttribPointerNV (_GET_TLS_PROCTABLE()->VertexAttribPointerNV) +#define glVertexAttrib1dNV (_GET_TLS_PROCTABLE()->VertexAttrib1dNV) +#define glVertexAttrib1dvNV (_GET_TLS_PROCTABLE()->VertexAttrib1dvNV) +#define glVertexAttrib1fNV (_GET_TLS_PROCTABLE()->VertexAttrib1fNV) +#define glVertexAttrib1fvNV (_GET_TLS_PROCTABLE()->VertexAttrib1fvNV) +#define glVertexAttrib1sNV (_GET_TLS_PROCTABLE()->VertexAttrib1sNV) +#define glVertexAttrib1svNV (_GET_TLS_PROCTABLE()->VertexAttrib1svNV) +#define glVertexAttrib2dNV (_GET_TLS_PROCTABLE()->VertexAttrib2dNV) +#define glVertexAttrib2dvNV (_GET_TLS_PROCTABLE()->VertexAttrib2dvNV) +#define glVertexAttrib2fNV (_GET_TLS_PROCTABLE()->VertexAttrib2fNV) +#define glVertexAttrib2fvNV (_GET_TLS_PROCTABLE()->VertexAttrib2fvNV) +#define glVertexAttrib2sNV (_GET_TLS_PROCTABLE()->VertexAttrib2sNV) +#define glVertexAttrib2svNV (_GET_TLS_PROCTABLE()->VertexAttrib2svNV) +#define glVertexAttrib3dNV (_GET_TLS_PROCTABLE()->VertexAttrib3dNV) +#define glVertexAttrib3dvNV (_GET_TLS_PROCTABLE()->VertexAttrib3dvNV) +#define glVertexAttrib3fNV (_GET_TLS_PROCTABLE()->VertexAttrib3fNV) +#define glVertexAttrib3fvNV (_GET_TLS_PROCTABLE()->VertexAttrib3fvNV) +#define glVertexAttrib3sNV (_GET_TLS_PROCTABLE()->VertexAttrib3sNV) +#define glVertexAttrib3svNV (_GET_TLS_PROCTABLE()->VertexAttrib3svNV) +#define glVertexAttrib4dNV (_GET_TLS_PROCTABLE()->VertexAttrib4dNV) +#define glVertexAttrib4dvNV (_GET_TLS_PROCTABLE()->VertexAttrib4dvNV) +#define glVertexAttrib4fNV (_GET_TLS_PROCTABLE()->VertexAttrib4fNV) +#define glVertexAttrib4fvNV (_GET_TLS_PROCTABLE()->VertexAttrib4fvNV) +#define glVertexAttrib4sNV (_GET_TLS_PROCTABLE()->VertexAttrib4sNV) +#define glVertexAttrib4svNV (_GET_TLS_PROCTABLE()->VertexAttrib4svNV) +#define glVertexAttrib4ubNV (_GET_TLS_PROCTABLE()->VertexAttrib4ubNV) +#define glVertexAttrib4ubvNV (_GET_TLS_PROCTABLE()->VertexAttrib4ubvNV) +#define glVertexAttribs1dvNV (_GET_TLS_PROCTABLE()->VertexAttribs1dvNV) +#define glVertexAttribs1fvNV (_GET_TLS_PROCTABLE()->VertexAttribs1fvNV) +#define glVertexAttribs1svNV (_GET_TLS_PROCTABLE()->VertexAttribs1svNV) +#define glVertexAttribs2dvNV (_GET_TLS_PROCTABLE()->VertexAttribs2dvNV) +#define glVertexAttribs2fvNV (_GET_TLS_PROCTABLE()->VertexAttribs2fvNV) +#define glVertexAttribs2svNV (_GET_TLS_PROCTABLE()->VertexAttribs2svNV) +#define glVertexAttribs3dvNV (_GET_TLS_PROCTABLE()->VertexAttribs3dvNV) +#define glVertexAttribs3fvNV (_GET_TLS_PROCTABLE()->VertexAttribs3fvNV) +#define glVertexAttribs3svNV (_GET_TLS_PROCTABLE()->VertexAttribs3svNV) +#define glVertexAttribs4dvNV (_GET_TLS_PROCTABLE()->VertexAttribs4dvNV) +#define glVertexAttribs4fvNV (_GET_TLS_PROCTABLE()->VertexAttribs4fvNV) +#define glVertexAttribs4svNV (_GET_TLS_PROCTABLE()->VertexAttribs4svNV) +#define glVertexAttribs4ubvNV (_GET_TLS_PROCTABLE()->VertexAttribs4ubvNV) +#define glTexBumpParameterivATI (_GET_TLS_PROCTABLE()->TexBumpParameterivATI) +#define glTexBumpParameterfvATI (_GET_TLS_PROCTABLE()->TexBumpParameterfvATI) +#define glGetTexBumpParameterivATI (_GET_TLS_PROCTABLE()->GetTexBumpParameterivATI) +#define glGetTexBumpParameterfvATI (_GET_TLS_PROCTABLE()->GetTexBumpParameterfvATI) +#define glGenFragmentShadersATI (_GET_TLS_PROCTABLE()->GenFragmentShadersATI) +#define glBindFragmentShaderATI (_GET_TLS_PROCTABLE()->BindFragmentShaderATI) +#define glDeleteFragmentShaderATI (_GET_TLS_PROCTABLE()->DeleteFragmentShaderATI) +#define glBeginFragmentShaderATI (_GET_TLS_PROCTABLE()->BeginFragmentShaderATI) +#define glEndFragmentShaderATI (_GET_TLS_PROCTABLE()->EndFragmentShaderATI) +#define glPassTexCoordATI (_GET_TLS_PROCTABLE()->PassTexCoordATI) +#define glSampleMapATI (_GET_TLS_PROCTABLE()->SampleMapATI) +#define glColorFragmentOp1ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp1ATI) +#define glColorFragmentOp2ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp2ATI) +#define glColorFragmentOp3ATI (_GET_TLS_PROCTABLE()->ColorFragmentOp3ATI) +#define glAlphaFragmentOp1ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp1ATI) +#define glAlphaFragmentOp2ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp2ATI) +#define glAlphaFragmentOp3ATI (_GET_TLS_PROCTABLE()->AlphaFragmentOp3ATI) +#define glSetFragmentShaderConstantATI (_GET_TLS_PROCTABLE()->SetFragmentShaderConstantATI) +#define glPNTrianglesiATI (_GET_TLS_PROCTABLE()->PNTrianglesiATI) +#define glPNTrianglesfATI (_GET_TLS_PROCTABLE()->PNTrianglesfATI) +#define glNewObjectBufferATI (_GET_TLS_PROCTABLE()->NewObjectBufferATI) +#define glIsObjectBufferATI (_GET_TLS_PROCTABLE()->IsObjectBufferATI) +#define glUpdateObjectBufferATI (_GET_TLS_PROCTABLE()->UpdateObjectBufferATI) +#define glGetObjectBufferfvATI (_GET_TLS_PROCTABLE()->GetObjectBufferfvATI) +#define glGetObjectBufferivATI (_GET_TLS_PROCTABLE()->GetObjectBufferivATI) +#define glFreeObjectBufferATI (_GET_TLS_PROCTABLE()->FreeObjectBufferATI) +#define glArrayObjectATI (_GET_TLS_PROCTABLE()->ArrayObjectATI) +#define glGetArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetArrayObjectfvATI) +#define glGetArrayObjectivATI (_GET_TLS_PROCTABLE()->GetArrayObjectivATI) +#define glVariantArrayObjectATI (_GET_TLS_PROCTABLE()->VariantArrayObjectATI) +#define glGetVariantArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetVariantArrayObjectfvATI) +#define glGetVariantArrayObjectivATI (_GET_TLS_PROCTABLE()->GetVariantArrayObjectivATI) +#define glBeginVertexShaderEXT (_GET_TLS_PROCTABLE()->BeginVertexShaderEXT) +#define glEndVertexShaderEXT (_GET_TLS_PROCTABLE()->EndVertexShaderEXT) +#define glBindVertexShaderEXT (_GET_TLS_PROCTABLE()->BindVertexShaderEXT) +#define glGenVertexShadersEXT (_GET_TLS_PROCTABLE()->GenVertexShadersEXT) +#define glDeleteVertexShaderEXT (_GET_TLS_PROCTABLE()->DeleteVertexShaderEXT) +#define glShaderOp1EXT (_GET_TLS_PROCTABLE()->ShaderOp1EXT) +#define glShaderOp2EXT (_GET_TLS_PROCTABLE()->ShaderOp2EXT) +#define glShaderOp3EXT (_GET_TLS_PROCTABLE()->ShaderOp3EXT) +#define glSwizzleEXT (_GET_TLS_PROCTABLE()->SwizzleEXT) +#define glWriteMaskEXT (_GET_TLS_PROCTABLE()->WriteMaskEXT) +#define glInsertComponentEXT (_GET_TLS_PROCTABLE()->InsertComponentEXT) +#define glExtractComponentEXT (_GET_TLS_PROCTABLE()->ExtractComponentEXT) +#define glGenSymbolsEXT (_GET_TLS_PROCTABLE()->GenSymbolsEXT) +#define glSetInvariantEXT (_GET_TLS_PROCTABLE()->SetInvariantEXT) +#define glSetLocalConstantEXT (_GET_TLS_PROCTABLE()->SetLocalConstantEXT) +#define glVariantbvEXT (_GET_TLS_PROCTABLE()->VariantbvEXT) +#define glVariantsvEXT (_GET_TLS_PROCTABLE()->VariantsvEXT) +#define glVariantivEXT (_GET_TLS_PROCTABLE()->VariantivEXT) +#define glVariantfvEXT (_GET_TLS_PROCTABLE()->VariantfvEXT) +#define glVariantdvEXT (_GET_TLS_PROCTABLE()->VariantdvEXT) +#define glVariantubvEXT (_GET_TLS_PROCTABLE()->VariantubvEXT) +#define glVariantusvEXT (_GET_TLS_PROCTABLE()->VariantusvEXT) +#define glVariantuivEXT (_GET_TLS_PROCTABLE()->VariantuivEXT) +#define glVariantPointerEXT (_GET_TLS_PROCTABLE()->VariantPointerEXT) +#define glEnableVariantClientStateEXT (_GET_TLS_PROCTABLE()->EnableVariantClientStateEXT) +#define glDisableVariantClientStateEXT (_GET_TLS_PROCTABLE()->DisableVariantClientStateEXT) +#define glBindLightParameterEXT (_GET_TLS_PROCTABLE()->BindLightParameterEXT) +#define glBindMaterialParameterEXT (_GET_TLS_PROCTABLE()->BindMaterialParameterEXT) +#define glBindTexGenParameterEXT (_GET_TLS_PROCTABLE()->BindTexGenParameterEXT) +#define glBindTextureUnitParameterEXT (_GET_TLS_PROCTABLE()->BindTextureUnitParameterEXT) +#define glBindParameterEXT (_GET_TLS_PROCTABLE()->BindParameterEXT) +#define glIsVariantEnabledEXT (_GET_TLS_PROCTABLE()->IsVariantEnabledEXT) +#define glGetVariantBooleanvEXT (_GET_TLS_PROCTABLE()->GetVariantBooleanvEXT) +#define glGetVariantIntegervEXT (_GET_TLS_PROCTABLE()->GetVariantIntegervEXT) +#define glGetVariantFloatvEXT (_GET_TLS_PROCTABLE()->GetVariantFloatvEXT) +#define glGetVariantPointervEXT (_GET_TLS_PROCTABLE()->GetVariantPointervEXT) +#define glGetInvariantBooleanvEXT (_GET_TLS_PROCTABLE()->GetInvariantBooleanvEXT) +#define glGetInvariantIntegervEXT (_GET_TLS_PROCTABLE()->GetInvariantIntegervEXT) +#define glGetInvariantFloatvEXT (_GET_TLS_PROCTABLE()->GetInvariantFloatvEXT) +#define glGetLocalConstantBooleanvEXT (_GET_TLS_PROCTABLE()->GetLocalConstantBooleanvEXT) +#define glGetLocalConstantIntegervEXT (_GET_TLS_PROCTABLE()->GetLocalConstantIntegervEXT) +#define glGetLocalConstantFloatvEXT (_GET_TLS_PROCTABLE()->GetLocalConstantFloatvEXT) +#define glVertexStream1sATI (_GET_TLS_PROCTABLE()->VertexStream1sATI) +#define glVertexStream1svATI (_GET_TLS_PROCTABLE()->VertexStream1svATI) +#define glVertexStream1iATI (_GET_TLS_PROCTABLE()->VertexStream1iATI) +#define glVertexStream1ivATI (_GET_TLS_PROCTABLE()->VertexStream1ivATI) +#define glVertexStream1fATI (_GET_TLS_PROCTABLE()->VertexStream1fATI) +#define glVertexStream1fvATI (_GET_TLS_PROCTABLE()->VertexStream1fvATI) +#define glVertexStream1dATI (_GET_TLS_PROCTABLE()->VertexStream1dATI) +#define glVertexStream1dvATI (_GET_TLS_PROCTABLE()->VertexStream1dvATI) +#define glVertexStream2sATI (_GET_TLS_PROCTABLE()->VertexStream2sATI) +#define glVertexStream2svATI (_GET_TLS_PROCTABLE()->VertexStream2svATI) +#define glVertexStream2iATI (_GET_TLS_PROCTABLE()->VertexStream2iATI) +#define glVertexStream2ivATI (_GET_TLS_PROCTABLE()->VertexStream2ivATI) +#define glVertexStream2fATI (_GET_TLS_PROCTABLE()->VertexStream2fATI) +#define glVertexStream2fvATI (_GET_TLS_PROCTABLE()->VertexStream2fvATI) +#define glVertexStream2dATI (_GET_TLS_PROCTABLE()->VertexStream2dATI) +#define glVertexStream2dvATI (_GET_TLS_PROCTABLE()->VertexStream2dvATI) +#define glVertexStream3sATI (_GET_TLS_PROCTABLE()->VertexStream3sATI) +#define glVertexStream3svATI (_GET_TLS_PROCTABLE()->VertexStream3svATI) +#define glVertexStream3iATI (_GET_TLS_PROCTABLE()->VertexStream3iATI) +#define glVertexStream3ivATI (_GET_TLS_PROCTABLE()->VertexStream3ivATI) +#define glVertexStream3fATI (_GET_TLS_PROCTABLE()->VertexStream3fATI) +#define glVertexStream3fvATI (_GET_TLS_PROCTABLE()->VertexStream3fvATI) +#define glVertexStream3dATI (_GET_TLS_PROCTABLE()->VertexStream3dATI) +#define glVertexStream3dvATI (_GET_TLS_PROCTABLE()->VertexStream3dvATI) +#define glVertexStream4sATI (_GET_TLS_PROCTABLE()->VertexStream4sATI) +#define glVertexStream4svATI (_GET_TLS_PROCTABLE()->VertexStream4svATI) +#define glVertexStream4iATI (_GET_TLS_PROCTABLE()->VertexStream4iATI) +#define glVertexStream4ivATI (_GET_TLS_PROCTABLE()->VertexStream4ivATI) +#define glVertexStream4fATI (_GET_TLS_PROCTABLE()->VertexStream4fATI) +#define glVertexStream4fvATI (_GET_TLS_PROCTABLE()->VertexStream4fvATI) +#define glVertexStream4dATI (_GET_TLS_PROCTABLE()->VertexStream4dATI) +#define glVertexStream4dvATI (_GET_TLS_PROCTABLE()->VertexStream4dvATI) +#define glNormalStream3bATI (_GET_TLS_PROCTABLE()->NormalStream3bATI) +#define glNormalStream3bvATI (_GET_TLS_PROCTABLE()->NormalStream3bvATI) +#define glNormalStream3sATI (_GET_TLS_PROCTABLE()->NormalStream3sATI) +#define glNormalStream3svATI (_GET_TLS_PROCTABLE()->NormalStream3svATI) +#define glNormalStream3iATI (_GET_TLS_PROCTABLE()->NormalStream3iATI) +#define glNormalStream3ivATI (_GET_TLS_PROCTABLE()->NormalStream3ivATI) +#define glNormalStream3fATI (_GET_TLS_PROCTABLE()->NormalStream3fATI) +#define glNormalStream3fvATI (_GET_TLS_PROCTABLE()->NormalStream3fvATI) +#define glNormalStream3dATI (_GET_TLS_PROCTABLE()->NormalStream3dATI) +#define glNormalStream3dvATI (_GET_TLS_PROCTABLE()->NormalStream3dvATI) +#define glClientActiveVertexStreamATI (_GET_TLS_PROCTABLE()->ClientActiveVertexStreamATI) +#define glVertexBlendEnviATI (_GET_TLS_PROCTABLE()->VertexBlendEnviATI) +#define glVertexBlendEnvfATI (_GET_TLS_PROCTABLE()->VertexBlendEnvfATI) +#define glElementPointerATI (_GET_TLS_PROCTABLE()->ElementPointerATI) +#define glDrawElementArrayATI (_GET_TLS_PROCTABLE()->DrawElementArrayATI) +#define glDrawRangeElementArrayATI (_GET_TLS_PROCTABLE()->DrawRangeElementArrayATI) +#define glDrawMeshArraysSUN (_GET_TLS_PROCTABLE()->DrawMeshArraysSUN) +#define glGenOcclusionQueriesNV (_GET_TLS_PROCTABLE()->GenOcclusionQueriesNV) +#define glDeleteOcclusionQueriesNV (_GET_TLS_PROCTABLE()->DeleteOcclusionQueriesNV) +#define glIsOcclusionQueryNV (_GET_TLS_PROCTABLE()->IsOcclusionQueryNV) +#define glBeginOcclusionQueryNV (_GET_TLS_PROCTABLE()->BeginOcclusionQueryNV) +#define glEndOcclusionQueryNV (_GET_TLS_PROCTABLE()->EndOcclusionQueryNV) +#define glGetOcclusionQueryivNV (_GET_TLS_PROCTABLE()->GetOcclusionQueryivNV) +#define glGetOcclusionQueryuivNV (_GET_TLS_PROCTABLE()->GetOcclusionQueryuivNV) +#define glPointParameteriNV (_GET_TLS_PROCTABLE()->PointParameteriNV) +#define glPointParameterivNV (_GET_TLS_PROCTABLE()->PointParameterivNV) +#define glActiveStencilFaceEXT (_GET_TLS_PROCTABLE()->ActiveStencilFaceEXT) +#define glElementPointerAPPLE (_GET_TLS_PROCTABLE()->ElementPointerAPPLE) +#define glDrawElementArrayAPPLE (_GET_TLS_PROCTABLE()->DrawElementArrayAPPLE) +#define glDrawRangeElementArrayAPPLE (_GET_TLS_PROCTABLE()->DrawRangeElementArrayAPPLE) +#define glMultiDrawElementArrayAPPLE (_GET_TLS_PROCTABLE()->MultiDrawElementArrayAPPLE) +#define glMultiDrawRangeElementArrayAPPLE (_GET_TLS_PROCTABLE()->MultiDrawRangeElementArrayAPPLE) +#define glGenFencesAPPLE (_GET_TLS_PROCTABLE()->GenFencesAPPLE) +#define glDeleteFencesAPPLE (_GET_TLS_PROCTABLE()->DeleteFencesAPPLE) +#define glSetFenceAPPLE (_GET_TLS_PROCTABLE()->SetFenceAPPLE) +#define glIsFenceAPPLE (_GET_TLS_PROCTABLE()->IsFenceAPPLE) +#define glTestFenceAPPLE (_GET_TLS_PROCTABLE()->TestFenceAPPLE) +#define glFinishFenceAPPLE (_GET_TLS_PROCTABLE()->FinishFenceAPPLE) +#define glTestObjectAPPLE (_GET_TLS_PROCTABLE()->TestObjectAPPLE) +#define glFinishObjectAPPLE (_GET_TLS_PROCTABLE()->FinishObjectAPPLE) +#define glBindVertexArrayAPPLE (_GET_TLS_PROCTABLE()->BindVertexArrayAPPLE) +#define glDeleteVertexArraysAPPLE (_GET_TLS_PROCTABLE()->DeleteVertexArraysAPPLE) +#define glGenVertexArraysAPPLE (_GET_TLS_PROCTABLE()->GenVertexArraysAPPLE) +#define glIsVertexArrayAPPLE (_GET_TLS_PROCTABLE()->IsVertexArrayAPPLE) +#define glVertexArrayRangeAPPLE (_GET_TLS_PROCTABLE()->VertexArrayRangeAPPLE) +#define glFlushVertexArrayRangeAPPLE (_GET_TLS_PROCTABLE()->FlushVertexArrayRangeAPPLE) +#define glVertexArrayParameteriAPPLE (_GET_TLS_PROCTABLE()->VertexArrayParameteriAPPLE) +#define glDrawBuffersATI (_GET_TLS_PROCTABLE()->DrawBuffersATI) +#define glProgramNamedParameter4fNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4fNV) +#define glProgramNamedParameter4dNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4dNV) +#define glProgramNamedParameter4fvNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4fvNV) +#define glProgramNamedParameter4dvNV (_GET_TLS_PROCTABLE()->ProgramNamedParameter4dvNV) +#define glGetProgramNamedParameterfvNV (_GET_TLS_PROCTABLE()->GetProgramNamedParameterfvNV) +#define glGetProgramNamedParameterdvNV (_GET_TLS_PROCTABLE()->GetProgramNamedParameterdvNV) +#define glVertex2hNV (_GET_TLS_PROCTABLE()->Vertex2hNV) +#define glVertex2hvNV (_GET_TLS_PROCTABLE()->Vertex2hvNV) +#define glVertex3hNV (_GET_TLS_PROCTABLE()->Vertex3hNV) +#define glVertex3hvNV (_GET_TLS_PROCTABLE()->Vertex3hvNV) +#define glVertex4hNV (_GET_TLS_PROCTABLE()->Vertex4hNV) +#define glVertex4hvNV (_GET_TLS_PROCTABLE()->Vertex4hvNV) +#define glNormal3hNV (_GET_TLS_PROCTABLE()->Normal3hNV) +#define glNormal3hvNV (_GET_TLS_PROCTABLE()->Normal3hvNV) +#define glColor3hNV (_GET_TLS_PROCTABLE()->Color3hNV) +#define glColor3hvNV (_GET_TLS_PROCTABLE()->Color3hvNV) +#define glColor4hNV (_GET_TLS_PROCTABLE()->Color4hNV) +#define glColor4hvNV (_GET_TLS_PROCTABLE()->Color4hvNV) +#define glTexCoord1hNV (_GET_TLS_PROCTABLE()->TexCoord1hNV) +#define glTexCoord1hvNV (_GET_TLS_PROCTABLE()->TexCoord1hvNV) +#define glTexCoord2hNV (_GET_TLS_PROCTABLE()->TexCoord2hNV) +#define glTexCoord2hvNV (_GET_TLS_PROCTABLE()->TexCoord2hvNV) +#define glTexCoord3hNV (_GET_TLS_PROCTABLE()->TexCoord3hNV) +#define glTexCoord3hvNV (_GET_TLS_PROCTABLE()->TexCoord3hvNV) +#define glTexCoord4hNV (_GET_TLS_PROCTABLE()->TexCoord4hNV) +#define glTexCoord4hvNV (_GET_TLS_PROCTABLE()->TexCoord4hvNV) +#define glMultiTexCoord1hNV (_GET_TLS_PROCTABLE()->MultiTexCoord1hNV) +#define glMultiTexCoord1hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord1hvNV) +#define glMultiTexCoord2hNV (_GET_TLS_PROCTABLE()->MultiTexCoord2hNV) +#define glMultiTexCoord2hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord2hvNV) +#define glMultiTexCoord3hNV (_GET_TLS_PROCTABLE()->MultiTexCoord3hNV) +#define glMultiTexCoord3hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord3hvNV) +#define glMultiTexCoord4hNV (_GET_TLS_PROCTABLE()->MultiTexCoord4hNV) +#define glMultiTexCoord4hvNV (_GET_TLS_PROCTABLE()->MultiTexCoord4hvNV) +#define glFogCoordhNV (_GET_TLS_PROCTABLE()->FogCoordhNV) +#define glFogCoordhvNV (_GET_TLS_PROCTABLE()->FogCoordhvNV) +#define glSecondaryColor3hNV (_GET_TLS_PROCTABLE()->SecondaryColor3hNV) +#define glSecondaryColor3hvNV (_GET_TLS_PROCTABLE()->SecondaryColor3hvNV) +#define glVertexWeighthNV (_GET_TLS_PROCTABLE()->VertexWeighthNV) +#define glVertexWeighthvNV (_GET_TLS_PROCTABLE()->VertexWeighthvNV) +#define glVertexAttrib1hNV (_GET_TLS_PROCTABLE()->VertexAttrib1hNV) +#define glVertexAttrib1hvNV (_GET_TLS_PROCTABLE()->VertexAttrib1hvNV) +#define glVertexAttrib2hNV (_GET_TLS_PROCTABLE()->VertexAttrib2hNV) +#define glVertexAttrib2hvNV (_GET_TLS_PROCTABLE()->VertexAttrib2hvNV) +#define glVertexAttrib3hNV (_GET_TLS_PROCTABLE()->VertexAttrib3hNV) +#define glVertexAttrib3hvNV (_GET_TLS_PROCTABLE()->VertexAttrib3hvNV) +#define glVertexAttrib4hNV (_GET_TLS_PROCTABLE()->VertexAttrib4hNV) +#define glVertexAttrib4hvNV (_GET_TLS_PROCTABLE()->VertexAttrib4hvNV) +#define glVertexAttribs1hvNV (_GET_TLS_PROCTABLE()->VertexAttribs1hvNV) +#define glVertexAttribs2hvNV (_GET_TLS_PROCTABLE()->VertexAttribs2hvNV) +#define glVertexAttribs3hvNV (_GET_TLS_PROCTABLE()->VertexAttribs3hvNV) +#define glVertexAttribs4hvNV (_GET_TLS_PROCTABLE()->VertexAttribs4hvNV) +#define glPixelDataRangeNV (_GET_TLS_PROCTABLE()->PixelDataRangeNV) +#define glFlushPixelDataRangeNV (_GET_TLS_PROCTABLE()->FlushPixelDataRangeNV) +#define glPrimitiveRestartNV (_GET_TLS_PROCTABLE()->PrimitiveRestartNV) +#define glPrimitiveRestartIndexNV (_GET_TLS_PROCTABLE()->PrimitiveRestartIndexNV) +#define glMapObjectBufferATI (_GET_TLS_PROCTABLE()->MapObjectBufferATI) +#define glUnmapObjectBufferATI (_GET_TLS_PROCTABLE()->UnmapObjectBufferATI) +#define glStencilOpSeparateATI (_GET_TLS_PROCTABLE()->StencilOpSeparateATI) +#define glStencilFuncSeparateATI (_GET_TLS_PROCTABLE()->StencilFuncSeparateATI) +#define glVertexAttribArrayObjectATI (_GET_TLS_PROCTABLE()->VertexAttribArrayObjectATI) +#define glGetVertexAttribArrayObjectfvATI (_GET_TLS_PROCTABLE()->GetVertexAttribArrayObjectfvATI) +#define glGetVertexAttribArrayObjectivATI (_GET_TLS_PROCTABLE()->GetVertexAttribArrayObjectivATI) +#define glDepthBoundsEXT (_GET_TLS_PROCTABLE()->DepthBoundsEXT) +#define glBlendEquationSeparateEXT (_GET_TLS_PROCTABLE()->BlendEquationSeparateEXT) +#define glAddSwapHintRectWIN (_GET_TLS_PROCTABLE()->AddSwapHintRectWIN) +#ifdef _WIN32 +#define wglCreateBufferRegionARB (_GET_TLS_PROCTABLE()->CreateBufferRegionARB) +#define wglDeleteBufferRegionARB (_GET_TLS_PROCTABLE()->DeleteBufferRegionARB) +#define wglSaveBufferRegionARB (_GET_TLS_PROCTABLE()->SaveBufferRegionARB) +#define wglRestoreBufferRegionARB (_GET_TLS_PROCTABLE()->RestoreBufferRegionARB) +#define wglGetExtensionsStringARB (_GET_TLS_PROCTABLE()->GetExtensionsStringARB) +#define wglGetPixelFormatAttribivARB (_GET_TLS_PROCTABLE()->GetPixelFormatAttribivARB) +#define wglGetPixelFormatAttribfvARB (_GET_TLS_PROCTABLE()->GetPixelFormatAttribfvARB) +#define wglChoosePixelFormatARB (_GET_TLS_PROCTABLE()->ChoosePixelFormatARB) +#define wglMakeContextCurrentARB (_GET_TLS_PROCTABLE()->MakeContextCurrentARB) +#define wglGetCurrentReadDCARB (_GET_TLS_PROCTABLE()->GetCurrentReadDCARB) +#define wglCreatePbufferARB (_GET_TLS_PROCTABLE()->CreatePbufferARB) +#define wglGetPbufferDCARB (_GET_TLS_PROCTABLE()->GetPbufferDCARB) +#define wglReleasePbufferDCARB (_GET_TLS_PROCTABLE()->ReleasePbufferDCARB) +#define wglDestroyPbufferARB (_GET_TLS_PROCTABLE()->DestroyPbufferARB) +#define wglQueryPbufferARB (_GET_TLS_PROCTABLE()->QueryPbufferARB) +#define wglBindTexImageARB (_GET_TLS_PROCTABLE()->BindTexImageARB) +#define wglReleaseTexImageARB (_GET_TLS_PROCTABLE()->ReleaseTexImageARB) +#define wglSetPbufferAttribARB (_GET_TLS_PROCTABLE()->SetPbufferAttribARB) +#define wglCreateDisplayColorTableEXT (_GET_TLS_PROCTABLE()->CreateDisplayColorTableEXT) +#define wglLoadDisplayColorTableEXT (_GET_TLS_PROCTABLE()->LoadDisplayColorTableEXT) +#define wglBindDisplayColorTableEXT (_GET_TLS_PROCTABLE()->BindDisplayColorTableEXT) +#define wglDestroyDisplayColorTableEXT (_GET_TLS_PROCTABLE()->DestroyDisplayColorTableEXT) +#define wglGetExtensionsStringEXT (_GET_TLS_PROCTABLE()->GetExtensionsStringEXT) +#define wglMakeContextCurrentEXT (_GET_TLS_PROCTABLE()->MakeContextCurrentEXT) +#define wglGetCurrentReadDCEXT (_GET_TLS_PROCTABLE()->GetCurrentReadDCEXT) +#define wglCreatePbufferEXT (_GET_TLS_PROCTABLE()->CreatePbufferEXT) +#define wglGetPbufferDCEXT (_GET_TLS_PROCTABLE()->GetPbufferDCEXT) +#define wglReleasePbufferDCEXT (_GET_TLS_PROCTABLE()->ReleasePbufferDCEXT) +#define wglDestroyPbufferEXT (_GET_TLS_PROCTABLE()->DestroyPbufferEXT) +#define wglQueryPbufferEXT (_GET_TLS_PROCTABLE()->QueryPbufferEXT) +#define wglGetPixelFormatAttribivEXT (_GET_TLS_PROCTABLE()->GetPixelFormatAttribivEXT) +#define wglGetPixelFormatAttribfvEXT (_GET_TLS_PROCTABLE()->GetPixelFormatAttribfvEXT) +#define wglChoosePixelFormatEXT (_GET_TLS_PROCTABLE()->ChoosePixelFormatEXT) +#define wglSwapIntervalEXT (_GET_TLS_PROCTABLE()->SwapIntervalEXT) +#define wglGetSwapIntervalEXT (_GET_TLS_PROCTABLE()->GetSwapIntervalEXT) +#define wglAllocateMemoryNV (_GET_TLS_PROCTABLE()->AllocateMemoryNV) +#define wglFreeMemoryNV (_GET_TLS_PROCTABLE()->FreeMemoryNV) +#define wglGetSyncValuesOML (_GET_TLS_PROCTABLE()->GetSyncValuesOML) +#define wglGetMscRateOML (_GET_TLS_PROCTABLE()->GetMscRateOML) +#define wglSwapBuffersMscOML (_GET_TLS_PROCTABLE()->SwapBuffersMscOML) +#define wglSwapLayerBuffersMscOML (_GET_TLS_PROCTABLE()->SwapLayerBuffersMscOML) +#define wglWaitForMscOML (_GET_TLS_PROCTABLE()->WaitForMscOML) +#define wglWaitForSbcOML (_GET_TLS_PROCTABLE()->WaitForSbcOML) +#define wglGetDigitalVideoParametersI3D (_GET_TLS_PROCTABLE()->GetDigitalVideoParametersI3D) +#define wglSetDigitalVideoParametersI3D (_GET_TLS_PROCTABLE()->SetDigitalVideoParametersI3D) +#define wglGetGammaTableParametersI3D (_GET_TLS_PROCTABLE()->GetGammaTableParametersI3D) +#define wglSetGammaTableParametersI3D (_GET_TLS_PROCTABLE()->SetGammaTableParametersI3D) +#define wglGetGammaTableI3D (_GET_TLS_PROCTABLE()->GetGammaTableI3D) +#define wglSetGammaTableI3D (_GET_TLS_PROCTABLE()->SetGammaTableI3D) +#define wglEnableGenlockI3D (_GET_TLS_PROCTABLE()->EnableGenlockI3D) +#define wglDisableGenlockI3D (_GET_TLS_PROCTABLE()->DisableGenlockI3D) +#define wglIsEnabledGenlockI3D (_GET_TLS_PROCTABLE()->IsEnabledGenlockI3D) +#define wglGenlockSourceI3D (_GET_TLS_PROCTABLE()->GenlockSourceI3D) +#define wglGetGenlockSourceI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceI3D) +#define wglGenlockSourceEdgeI3D (_GET_TLS_PROCTABLE()->GenlockSourceEdgeI3D) +#define wglGetGenlockSourceEdgeI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceEdgeI3D) +#define wglGenlockSampleRateI3D (_GET_TLS_PROCTABLE()->GenlockSampleRateI3D) +#define wglGetGenlockSampleRateI3D (_GET_TLS_PROCTABLE()->GetGenlockSampleRateI3D) +#define wglGenlockSourceDelayI3D (_GET_TLS_PROCTABLE()->GenlockSourceDelayI3D) +#define wglGetGenlockSourceDelayI3D (_GET_TLS_PROCTABLE()->GetGenlockSourceDelayI3D) +#define wglQueryGenlockMaxSourceDelayI3D (_GET_TLS_PROCTABLE()->QueryGenlockMaxSourceDelayI3D) +#define wglCreateImageBufferI3D (_GET_TLS_PROCTABLE()->CreateImageBufferI3D) +#define wglDestroyImageBufferI3D (_GET_TLS_PROCTABLE()->DestroyImageBufferI3D) +#define wglAssociateImageBufferEventsI3D (_GET_TLS_PROCTABLE()->AssociateImageBufferEventsI3D) +#define wglReleaseImageBufferEventsI3D (_GET_TLS_PROCTABLE()->ReleaseImageBufferEventsI3D) +#define wglEnableFrameLockI3D (_GET_TLS_PROCTABLE()->EnableFrameLockI3D) +#define wglDisableFrameLockI3D (_GET_TLS_PROCTABLE()->DisableFrameLockI3D) +#define wglIsEnabledFrameLockI3D (_GET_TLS_PROCTABLE()->IsEnabledFrameLockI3D) +#define wglQueryFrameLockMasterI3D (_GET_TLS_PROCTABLE()->QueryFrameLockMasterI3D) +#define wglGetFrameUsageI3D (_GET_TLS_PROCTABLE()->GetFrameUsageI3D) +#define wglBeginFrameTrackingI3D (_GET_TLS_PROCTABLE()->BeginFrameTrackingI3D) +#define wglEndFrameTrackingI3D (_GET_TLS_PROCTABLE()->EndFrameTrackingI3D) +#define wglQueryFrameTrackingI3D (_GET_TLS_PROCTABLE()->QueryFrameTrackingI3D) +#endif /* _WIN32 */ + +#ifndef _APP_PROCTABLE + +/* + * Applications can replace the following function with its own function + * for accessing thread local proc/context dependent proc table. + * The following default function works for most applications which + * are using the same device for all their contexts - even if + * the contexts are on different threads. + */ + +static _inline _GLextensionProcs *_GET_TLS_PROCTABLE(void) + +{ + extern _GLextensionProcs _extensionProcs; + + return (&_extensionProcs); +} + +#else + +/* + * Application should replace this compiled function with + * an inlined function for maximum performance. + */ + +extern _GLextensionProcs *_GET_TLS_PROCTABLE(void); + +#endif + +/* + * Provide an initialization function for the application + * to initialize its own proc tables in case the application + * needs to use multiple proc tables. + */ + +static _inline void _InitExtensionProcs(_GLextensionProcs *appProcs) +{ + extern _GLextensionProcs _extensionProcs; + + *appProcs = _extensionProcs; +} + +#ifdef __cplusplus +} +#endif + + +#endif /* _GLPROCS_H_ */ diff --git a/plugins/zerogs/opengl/install-sh b/plugins/zerogs/opengl/install-sh new file mode 100644 index 0000000000..4d4a9519ea --- /dev/null +++ b/plugins/zerogs/opengl/install-sh @@ -0,0 +1,323 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2005-05-14.22 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# 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 Software. +# +# THE SOFTWARE IS 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 +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +chmodcmd="$chmodprog 0755" +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit $?;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit $?;; + + *) # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + test -n "$dir_arg$dstarg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + src= + + if test -d "$dst"; then + mkdircmd=: + chmodcmd= + else + mkdircmd=$mkdirprog + fi + else + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dst=$dst/`basename "$src"` + fi + fi + + # This sed command emulates the dirname command. + dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` + + # Make sure that the destination directory exists. + + # Skip lots of stat calls in the usual case. + if test ! -d "$dstdir"; then + defaultIFS=' + ' + IFS="${IFS-$defaultIFS}" + + oIFS=$IFS + # Some sh's can't handle IFS=/ for some reason. + IFS='%' + set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` + shift + IFS=$oIFS + + pathcomp= + + while test $# -ne 0 ; do + pathcomp=$pathcomp$1 + shift + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # mkdir can fail with a `File exist' error in case several + # install-sh are creating the directory concurrently. This + # is OK. + test -d "$pathcomp" || exit + fi + pathcomp=$pathcomp/ + done + fi + + if test -n "$dir_arg"; then + $doit $mkdircmd "$dst" \ + && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } + + else + dstfile=`basename "$dst"` + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + trap '(exit $?); exit' 1 2 13 15 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dstdir/$dstfile"; then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ + || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ + || { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + } + } + fi || { (exit 1); exit 1; } +done + +# The final little trick to "correctly" pass the exit status to the exit trap. +{ + (exit 0); exit 0 +} + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/zerogs/opengl/memcpy_amd.cpp b/plugins/zerogs/opengl/memcpy_amd.cpp new file mode 100644 index 0000000000..0c78690760 --- /dev/null +++ b/plugins/zerogs/opengl/memcpy_amd.cpp @@ -0,0 +1,478 @@ +/****************************************************************************** + + Copyright (c) 2001 Advanced Micro Devices, Inc. + + LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY + EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, + NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY + PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY + DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, + BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR + INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY + OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION + OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY + NOT APPLY TO YOU. + + AMD does not assume any responsibility for any errors which may appear in the + Materials nor any responsibility to support or update the Materials. AMD retains + the right to make changes to its test specifications at any time, without notice. + + NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any + further information, software, technical information, know-how, or show-how + available to you. + + So that all may benefit from your experience, please report any problems + or suggestions about this software to 3dsdk.support@amd.com + + AMD Developer Technologies, M/S 585 + Advanced Micro Devices, Inc. + 5900 E. Ben White Blvd. + Austin, TX 78741 + 3dsdk.support@amd.com +******************************************************************************/ + +#include + +/***************************************************************************** +MEMCPY_AMD.CPP +******************************************************************************/ + +// Very optimized memcpy() routine for AMD Athlon and Duron family. +// This code uses any of FOUR different basic copy methods, depending +// on the transfer size. +// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or +// "Streaming Store"), and also uses the software prefetch instructions, +// be sure you're running on Athlon/Duron or other recent CPU before calling! + +#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". + +#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch +// Next is a copy that uses the MMX registers to copy 8 bytes at a time, +// also using the "unrolled loop" optimization. This code uses +// the software prefetch instruction to get the data into the cache. + +#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" + +#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch +#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. + +//#include + +// Inline assembly syntax for use with Visual C++ +#ifdef _WIN32 +#include +#endif + +extern "C" { +#include "PS2Etypes.h" + +#if defined(_MSC_VER) && !defined(__x86_64__) + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ + __asm { + mov ecx, [n] ; number of bytes to copy + mov edi, [dest] ; destination + mov esi, [src] ; source + mov ebx, ecx ; keep a copy of count + + cld + cmp ecx, TINY_BLOCK_COPY + jb $memcpy_ic_3 ; tiny? skip mmx copy + + cmp ecx, 32*1024 ; don't align between 32k-64k because + jbe $memcpy_do_align ; it appears to be slower + cmp ecx, 64*1024 + jbe $memcpy_align_done +$memcpy_do_align: + mov ecx, 8 ; a trick that's faster than rep movsb... + sub ecx, edi ; align destination to qword + and ecx, 111b ; get the low bits + sub ebx, ecx ; update copy count + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_align_done + jmp ecx ; jump to array of movsb's + +align 4 + movsb + movsb + movsb + movsb + movsb + movsb + movsb + movsb + +$memcpy_align_done: ; destination is dword aligned + mov ecx, ebx ; number of bytes left to copy + shr ecx, 6 ; get 64-byte block count + jz $memcpy_ic_2 ; finish the last few bytes + + cmp ecx, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy + jae $memcpy_uc_test + +// This is small block copy that uses the MMX registers to copy 8 bytes +// at a time. It uses the "unrolled loop" optimization, and also uses +// the software prefetch instruction to get the data into the cache. +align 16 +$memcpy_ic_1: ; 64-byte block copies, in-cache copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0, [esi+0] ; read 64 bits + movq mm1, [esi+8] + movq [edi+0], mm0 ; write 64 bits + movq [edi+8], mm1 ; note: the normal movq writes the + movq mm2, [esi+16] ; data to cache; a cache line will be + movq mm3, [esi+24] ; allocated as needed, to store the data + movq [edi+16], mm2 + movq [edi+24], mm3 + movq mm0, [esi+32] + movq mm1, [esi+40] + movq [edi+32], mm0 + movq [edi+40], mm1 + movq mm2, [esi+48] + movq mm3, [esi+56] + movq [edi+48], mm2 + movq [edi+56], mm3 + + add esi, 64 ; update source pointer + add edi, 64 ; update destination pointer + dec ecx ; count down + jnz $memcpy_ic_1 ; last 64-byte block? + +$memcpy_ic_2: + mov ecx, ebx ; has valid low 6 bits of the byte count +$memcpy_ic_3: + shr ecx, 2 ; dword count + and ecx, 1111b ; only look at the "remainder" bits + neg ecx ; set up to jump into the array + add ecx, offset $memcpy_last_few + jmp ecx ; jump to array of movsd's + +$memcpy_uc_test: + cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy + jae $memcpy_bp_1 + +$memcpy_64_test: + or ecx, ecx ; tail end of block prefetch will jump here + jz $memcpy_ic_2 ; no more 64-byte blocks left + +// For larger blocks, which will spill beyond the cache, it's faster to +// use the Streaming Store instruction MOVNTQ. This write instruction +// bypasses the cache and writes straight to main memory. This code also +// uses the software prefetch instruction to pre-read the data. +align 16 +$memcpy_uc_1: ; 64-byte blocks, uncached copy + + prefetchnta [esi + (200*64/34+192)] ; start reading ahead + + movq mm0,[esi+0] ; read 64 bits + add edi,64 ; update destination pointer + movq mm1,[esi+8] + add esi,64 ; update source pointer + movq mm2,[esi-48] + movntq [edi-64], mm0 ; write 64 bits, bypassing the cache + movq mm0,[esi-40] ; note: movntq also prevents the CPU + movntq [edi-56], mm1 ; from READING the destination address + movq mm1,[esi-32] ; into the cache, only to be over-written + movntq [edi-48], mm2 ; so that also helps performance + movq mm2,[esi-24] + movntq [edi-40], mm0 + movq mm0,[esi-16] + movntq [edi-32], mm1 + movq mm1,[esi-8] + movntq [edi-24], mm2 + movntq [edi-16], mm0 + dec ecx + movntq [edi-8], mm1 + jnz $memcpy_uc_1 ; last 64-byte block? + + jmp $memcpy_ic_2 ; almost done + +// For the largest size blocks, a special technique called Block Prefetch +// can be used to accelerate the read operations. Block Prefetch reads +// one address per cache line, for a series of cache lines, in a short loop. +// This is faster than using software prefetch. The technique is great for +// getting maximum read bandwidth, especially in DDR memory systems. +$memcpy_bp_1: ; large blocks, block prefetch copy + + cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? + jl $memcpy_64_test ; no, back to regular uncached copy + + mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X + add esi, CACHEBLOCK * 64 ; move to the top of the block +align 16 +$memcpy_bp_2: + mov edx, [esi-64] ; grab one address per cache line + mov edx, [esi-128] ; grab one address per cache line + sub esi, 128 ; go reverse order to suppress HW prefetcher + dec eax ; count down the cache lines + jnz $memcpy_bp_2 ; keep grabbing more lines into cache + + mov eax, CACHEBLOCK ; now that it's in cache, do the copy +align 16 +$memcpy_bp_3: + movq mm0, [esi ] ; read 64 bits + movq mm1, [esi+ 8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + add esi, 64 ; update source pointer + movntq [edi ], mm0 ; write 64 bits, bypassing cache + movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU + movntq [edi+16], mm2 ; from READING the destination address + movntq [edi+24], mm3 ; into the cache, only to be over-written, + movntq [edi+32], mm4 ; so that also helps performance + movntq [edi+40], mm5 + movntq [edi+48], mm6 + movntq [edi+56], mm7 + add edi, 64 ; update dest pointer + + dec eax ; count down + + jnz $memcpy_bp_3 ; keep copying + sub ecx, CACHEBLOCK ; update the 64-byte block count + jmp $memcpy_bp_1 ; keep processing chunks + +// The smallest copy uses the X86 "movsd" instruction, in an optimized +// form which is an "unrolled loop". Then it handles the last few bytes. +align 4 + movsd + movsd ; perform last 1-15 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + movsd + movsd ; perform last 1-7 dword copies + movsd + movsd + movsd + movsd + movsd + movsd + +$memcpy_last_few: ; dword aligned from before movsd's + mov ecx, ebx ; has valid low 2 bits of the byte count + and ecx, 11b ; the last few cows must come home + jz $memcpy_final ; no more, let's leave + rep movsb ; the last 1, 2, or 3 bytes + +$memcpy_final: + emms ; clean up the MMX state + sfence ; flush the write buffer + mov eax, [dest] ; ret value = destination pointer + + } +} + +// mmx memcpy implementation, size has to be a multiple of 8 +// returns 0 is equal, nonzero value if not equal +// ~10 times faster than standard memcmp +// (zerofrog) +u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +{ + assert( (cmpsize&7) == 0 ); + + __asm { +push esi + mov ecx, cmpsize + mov edx, src1 + mov esi, src2 + + cmp ecx, 32 + jl Done4 + + // custom test first 8 to make sure things are ok + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + movq mm2, [esi+16] + pmovmskb eax, mm0 + movq mm3, [esi+24] + + // check if eq + cmp eax, 0xff + je NextComp + mov eax, 1 + jmp End + +NextComp: + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je ContinueTest + mov eax, 1 + jmp End + + cmp ecx, 64 + jl Done8 + +Cmp8: + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + movq mm4, [esi+32] + movq mm5, [esi+40] + movq mm6, [esi+48] + movq mm7, [esi+56] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pcmpeqd mm4, [edx+32] + pand mm0, mm2 + pcmpeqd mm5, [edx+40] + pand mm0, mm3 + pcmpeqd mm6, [edx+48] + pand mm0, mm4 + pcmpeqd mm7, [edx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + je Continue + mov eax, 1 + jmp End + +Continue: + sub ecx, 64 + add esi, 64 + add edx, 64 +ContinueTest: + cmp ecx, 64 + jge Cmp8 + +Done8: + test ecx, 0x20 + jz Done4 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + movq mm3, [esi+24] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pcmpeqd mm3, [edx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub ecx, 32 + add esi, 32 + add edx, 32 + + // check if eq + cmp eax, 0xff + je Done4 + mov eax, 1 + jmp End + +Done4: + cmp ecx, 24 + jne Done2 + movq mm0, [esi] + movq mm1, [esi+8] + movq mm2, [esi+16] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pcmpeqd mm2, [edx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done2: + cmp ecx, 16 + jne Done1 + + movq mm0, [esi] + movq mm1, [esi+8] + pcmpeqd mm0, [edx] + pcmpeqd mm1, [edx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + // check if eq + cmp eax, 0xff + setne al + jmp End + +Done1: + cmp ecx, 8 + jne Done + + mov eax, [esi] + mov esi, [esi+4] + cmp eax, [edx] + je Next + mov eax, 1 + jmp End + +Next: + cmp esi, [edx+4] + setne al + jmp End + +Done: + xor eax, eax + +End: + pop esi + emms + } +} + +#else // _MSC_VER +// assume gcc or mingw or win x64 + +#include +#include + +void * memcpy_amd(void *dest, const void *src, size_t n) +{ +memcpy(dest, src, n); +return dest; +} + + +#endif + +} diff --git a/plugins/zerogs/opengl/missing b/plugins/zerogs/opengl/missing new file mode 100644 index 0000000000..894e786e16 --- /dev/null +++ b/plugins/zerogs/opengl/missing @@ -0,0 +1,360 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2005-06-08.21 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/zerogs/opengl/mkinstalldirs b/plugins/zerogs/opengl/mkinstalldirs new file mode 100644 index 0000000000..259dbfcd35 --- /dev/null +++ b/plugins/zerogs/opengl/mkinstalldirs @@ -0,0 +1,158 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2005-06-29.22 + +# Original author: Noah Friedman +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/zerogs/opengl/ps2hw.fx b/plugins/zerogs/opengl/ps2hw.fx new file mode 100644 index 0000000000..a4b1ba3474 --- /dev/null +++ b/plugins/zerogs/opengl/ps2hw.fx @@ -0,0 +1,841 @@ +// Cg Shaders for PS2 GS emulation + +// divides by z for every pixel, instead of in vertex shader +// fixes kh textures +#define PERSPECTIVE_CORRECT_TEX + +//#define TEST_AEM // tests AEM for black pixels +//#define REGION_REPEAT // set if texture wrapping mode is region repeat +//#define WRITE_DEPTH // set if depth is also written in a MRT +//#define ACCURATE_DECOMPRESSION // set for less capable hardware ATI Radeon 9000 series +//#define EXACT_COLOR // make sure the output color is clamped to 1/255 boundaries (for alpha testing) + +#ifdef PERSPECTIVE_CORRECT_TEX +#define TEX_XY tex.xy/tex.z +#define TEX_DECL float3 +#else +#define TEX_XY tex.xy +#define TEX_DECL float2 +#endif + +#ifdef WRITE_DEPTH +#define DOZWRITE(x) x +#else +#define DOZWRITE(x) +#endif + +#include "ps2hw_ctx.fx" + +// used to get the tiled offset into a page given the linear offset +uniform samplerRECT g_sSrcFinal : register(s2); +uniform sampler2D g_sBlocks : register(s3); +uniform sampler2D g_sBilinearBlocks : register(s4); +uniform sampler2D g_sConv16to32 : register(s4); +uniform sampler3D g_sConv32to16 : register(s4); +uniform sampler2D g_sBitwiseANDX : register(s5); +uniform sampler2D g_sBitwiseANDY : register(s6); +uniform samplerRECT g_sInterlace : register(s7); + +// used only on rare cases where the render target is PSMT8H +uniform sampler2D g_sCLUT : register(s2); + +// global pixel shader constants +uniform float4 g_fInvTexDims : register(c22); // similar to g_fClutOff +uniform float4 g_fFogColor : register(c23); + +// used for rectblitting +uniform float4 g_fBitBltZ : register(c24); + +uniform half4 g_fOneColor : register(c25); // col*.xxxy+.zzzw + +// vertex shader constants +uniform float4 g_fBitBltPos : register(c4); +uniform float4 g_fZ : register(c5); // transforms d3dcolor z into float z +uniform float4 g_fZNorm : register(c6); +uniform float4 g_fBitBltTex : register(c7); + +// pixel shader consts +// .z is used for the addressing fn +uniform half4 g_fExactColor : register(c27) = half4(0.5,0.5/256.0f,0,1/255.0f); +uniform float4 g_fBilinear : register(c28) = float4(-0.7f, -0.65f, 0.9,1/32767.0f); +uniform float4 g_fZBias : register(c29) = half4(1.0f/256.0f, 1.0004f, 1, 0.5); // also for vs +uniform float4 g_fc0 : register(c30) = float4(0,1, 0.001, 0.5f); // also for vs +uniform float4 g_fMult : register(c31) = float4(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f); + +// vertex shader consts +uniform float4 g_fBitBltTrans : register(c31) = float4(0.5f, -0.5f, 0.5, 0.5 + 0.4/416.0f); + +// given a local tex coord, returns the coord in the memory +float2 ps2memcoord(float2 realtex) +{ + float4 off; + + // block off + realtex.xy = realtex.xy * g_fTexDims.xy + g_fTexDims.zw; + realtex.xy = (realtex.xy - frac(realtex.xy)) * g_fMult.zw; + float2 fblock = frac(realtex.xy); + off.xy = realtex.xy-fblock.xy; + +#ifdef ACCURATE_DECOMPRESSION + off.zw = tex2D(g_sBlocks, g_fTexBlock.xy*fblock + g_fTexBlock.zw).ar; + off.x = dot(off.xyw, g_fTexOffset.xyw); + float f = frac(off.x); + float fadd = g_fTexOffset.z * off.z; + off.w = off.x + fadd; + off.x = frac(f + fadd); + off.w -= off.x; +#else + off.z = tex2D(g_sBlocks, g_fTexBlock.xy*fblock + g_fTexBlock.zw).a; + + // combine the two + off.x = dot(off.xyz, g_fTexOffset.xyz)+g_fTexOffset.w; + off.x = modf(off.x, off.w); +#endif + + off.xy = off.xw * g_fPageOffset.zy + g_fPageOffset.wx; + //off.y = off.w * g_fPageOffset.y + g_fPageOffset.x; + return off.xy; +} + +// find all texcoords for bilinear filtering +// assume that orgtex are already on boundaries +void ps2memcoord4(float4 orgtex, out float4 off0, out float4 off1) +{ + //float4 off0, off1, off2, off3; + float4 realtex; + + // block off + realtex = (orgtex * g_fTexDims.xyxy + g_fTexDims.zwzw);// * g_fMult.zwzw; + float4 fblock = frac(realtex.xyzw); + float4 ftransblock = g_fTexBlock.xyxy*fblock + g_fTexBlock.zwzw; + realtex -= fblock; + + float4 transvals = g_fTexOffset.x * realtex.xzxz + g_fTexOffset.y * realtex.yyww + g_fTexOffset.w; + + float4 colors;// = tex2D(g_sBilinearBlocks, ftransblock.xy); + + // this is faster on ffx ingame + colors.x = tex2D(g_sBlocks, ftransblock.xy).a; + colors.y = tex2D(g_sBlocks, ftransblock.zy).a; + colors.z = tex2D(g_sBlocks, ftransblock.xw).a; + colors.w = tex2D(g_sBlocks, ftransblock.zw).a; + + float4 fr, rem; + +#ifdef ACCURATE_DECOMPRESSION + fr = frac(transvals); + float4 fadd = colors * g_fTexOffset.z; + rem = transvals + fadd; + fr = frac(fr + fadd); + rem -= fr; +#else + transvals += colors * g_fTexOffset.z; + + fr = modf(transvals, rem); +#endif + + rem = rem * g_fPageOffset.y + g_fPageOffset.x; + fr = fr * g_fPageOffset.z + g_fPageOffset.w; + + // combine + off0 = g_fc0.yxyx * fr.xxyy + g_fc0.xyxy * rem.xxyy; + off1 = g_fc0.yxyx * fr.zzww + g_fc0.xyxy * rem.zzww; +} + +void ps2memcoord4_fast(float4 orgtex, out float4 off0, out float4 off1) +{ + float4 realtex; + + realtex = (orgtex * g_fTexDims.xyxy + g_fTexDims.zwzw);// * g_fMult.zwzw; + float4 fblock = frac(realtex.xyzw); + float2 ftransblock = g_fTexBlock.xy*fblock.xy + g_fTexBlock.zw; + realtex -= fblock; + + float4 transvals = g_fTexOffset.x * realtex.xzxz + g_fTexOffset.y * realtex.yyww + g_fTexOffset.w; + + float4 colors = tex2D(g_sBilinearBlocks, ftransblock.xy); + float4 fr, rem; + +#ifdef ACCURATE_DECOMPRESSION + fr = frac(transvals); + float4 fadd = colors * g_fTexOffset.z; + rem = transvals + fadd; + fr = frac(fr + fadd); + rem -= fr; +#else + transvals += colors * g_fTexOffset.z; + + fr = modf(transvals, rem); +#endif + + rem = rem * g_fPageOffset.y + g_fPageOffset.x; + fr = fr * g_fPageOffset.z; + + off0 = g_fc0.yxyx * fr.xxyy + g_fc0.xyxy * rem.xxyy; + off1 = g_fc0.yxyx * fr.zzww + g_fc0.xyxy * rem.zzww; +} + +// Wrapping modes +#if defined(REPEAT) + +float2 ps2addr(float2 coord) +{ + return frac(coord.xy); +} + +#elif defined(CLAMP) + +float2 ps2addr(float2 coord) +{ + return clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw); +} + +#elif defined(REGION_REPEAT) + +// computes the local tex coord along with addressing modes +float2 ps2addr(float2 coord) +{ + float2 final = frac(clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw)); + + if( TexWrapMode.x > g_fBilinear.z ) // region repeat mode for x (umsk&x)|ufix + final.x = tex2D(g_sBitwiseANDX, abs(coord.x)*TexWrapMode.zz).x * g_fClampExts.x + g_fClampExts.z; + if( TexWrapMode.y > g_fBilinear.z ) // region repeat mode for x (vmsk&x)|vfix + final.y = tex2D(g_sBitwiseANDY, abs(coord.y)*TexWrapMode.ww).x * g_fClampExts.y + g_fClampExts.w; + + return final; +} + +#else + +float2 ps2addr(float2 coord) +{ + return frac(clamp(coord.xy, g_fClampExts.xy, g_fClampExts.zw)); +} + +#endif + +half4 tex2DPS_32(float2 tex0) +{ + return texRECT(g_sMemory, ps2memcoord(tex0).xy); +} + +// use when texture is not tiled +half4 tex2DPS_tex32(float2 tex0) +{ + return texRECT(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw)*g_fZBias.zzzw+g_fPageOffset.w; +} + +// use when texture is not tiled +half4 tex2DPS_clut32(float2 tex0) +{ + float index = texRECT(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw).a+g_fPageOffset.w; + return tex2D(g_sCLUT, index*g_fExactColor.xz+g_fExactColor.yz); +} + +// use when texture is not tiled and converting from 32bit to 16bit +// don't convert on the block level, only on the column level +// so every other 8 pixels, use the upper bits instead of lower +half4 tex2DPS_tex32to16(float2 tex0) +{ + bool upper = false; + tex0.y += g_fPageOffset.z; + float2 ffrac = fmod(tex0, g_fTexOffset.xy); + tex0.xy = g_fc0.ww * (tex0.xy + ffrac); + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + upper = true; + } + if( ffrac.y >= g_fTexOffset.w ) { + tex0.y -= g_fTexOffset.w; + tex0.x += g_fc0.w; + } + + half4 color = texRECT(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw)*g_fZBias.zzzw+g_fPageOffset.w; + float2 uv = upper ? color.xw : color.zy; + return tex2D(g_sConv16to32, uv+g_fPageOffset.xy); +} + +// used when a 16 bit texture is used an 8h +half4 tex2DPS_tex16to8h(float2 tex0) +{ + float4 final; + float2 ffrac = fmod(tex0+g_fPageOffset.zw, g_fTexOffset.xy); + tex0.xy = g_fPageOffset.xy * tex0.xy - ffrac * g_fc0.yw; + + if( ffrac.x > g_fTexOffset.x*g_fc0.w ) + tex0.x += g_fTexOffset.x*g_fc0.w; + if( tex0.x >= g_fc0.y ) tex0 += g_fTexOffset.zw; + + float4 upper = texRECT(g_sMemory, g_fTexDims.xy*tex0+g_fTexDims.zw); + + // only need alpha + float index = tex3D(g_sConv32to16, upper.zyx-g_fc0.z).y + upper.w*g_fc0.w*g_fc0.w; + return tex2D(g_sCLUT, index+g_fExactColor.yz); +} + +//half4 f; +//f.w = old.y > (127.2f/255.0f) ? 1 : 0; +//old.y -= 0.5f * f.w; +//f.xyz = frac(old.yyx*half3(2.002*255.0f/256.0f, 64.025f*255.0f/256.0f, 8.002*255.0f/256.0f)); +//f.y += old.x * (0.25f*255.0f/256.0f); + +//////////////////////////////// +// calculates the texture color +//////////////////////////////// + +#define decl_ps2shade(num) \ +decl_ps2shade_##num(_32) \ +decl_ps2shade_##num(_tex32) \ +decl_ps2shade_##num(_clut32) \ +decl_ps2shade_##num(_tex32to16) \ +decl_ps2shade_##num(_tex16to8h) \ + +// nearest +#define decl_ps2shade_0(bit) \ +half4 ps2shade0##bit( TEX_DECL tex) \ +{ \ + return tex2DPS##bit( ps2addr(TEX_XY)); \ +} \ + +// do fast memcoord4 calcs when textures behave well +#ifdef REPEAT +#define PS2MEMCOORD4 ps2memcoord4 +#else +#define PS2MEMCOORD4 ps2memcoord4 +#endif + +#define decl_BilinearFilter(bit, addrfn) \ +half4 BilinearFilter##bit(float2 tex0) \ +{ \ + float4 off0, off1; \ + float4 ftex; \ + float2 ffrac; \ + ftex.xy = tex0 + g_fBilinear.xy * g_fRealTexDims.zw; \ + ffrac = frac(ftex.xy*g_fRealTexDims.xy); \ + ftex.xy -= ffrac.xy * g_fRealTexDims.zw; \ + \ + ftex.zw = ps2addr(ftex.xy + g_fRealTexDims.zw); \ + ftex.xy = ps2addr(ftex.xy); \ + \ + PS2MEMCOORD4(ftex, off0, off1); \ + half4 c0 = texRECT(g_sMemory, off0.xy); \ + half4 c1 = texRECT(g_sMemory, off0.zw); \ + half4 c2 = texRECT(g_sMemory, off1.xy); \ + half4 c3 = texRECT(g_sMemory, off1.zw); \ + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y ); \ +} \ + +decl_BilinearFilter(_32, ps2addr) +decl_BilinearFilter(_tex32, ps2addr) +decl_BilinearFilter(_clut32, ps2addr) +decl_BilinearFilter(_tex32to16, ps2addr) +decl_BilinearFilter(_tex16to8h, ps2addr) + +//TODO! For mip maps, only apply when LOD >= 0 +// lcm == 0, LOD = log(1/Q)*L + K, lcm == 1, LOD = K + +// bilinear +#define decl_ps2shade_1(bit) \ +half4 ps2shade1##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +// nearest, mip nearest +#define decl_ps2shade_2(bit) \ +half4 ps2shade2##bit(TEX_DECL tex) \ +{ \ + return tex2DPS##bit( ps2addr(TEX_XY)); \ +} \ + +// nearest, mip linear +#define decl_ps2shade_3(bit) \ +half4 ps2shade3##bit(TEX_DECL tex) \ +{ \ + return tex2DPS##bit(ps2addr(TEX_XY)); \ +} \ + +// linear, mip nearest +#define decl_ps2shade_4(bit) \ +half4 ps2shade4##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +// linear, mip linear +#define decl_ps2shade_5(bit) \ +half4 ps2shade5##bit(TEX_DECL tex) \ +{ \ + return BilinearFilter##bit(TEX_XY); \ +} \ + +decl_ps2shade(0) +decl_ps2shade(1) +decl_ps2shade(2) +decl_ps2shade(3) +decl_ps2shade(4) +decl_ps2shade(5) + +half4 ps2CalcShade(half4 texcol, half4 color) +{ +#ifdef TEST_AEM + if( dot(texcol.xyzw, g_fTestBlack.xyzw) <= g_fc0.z ) + texcol.w = g_fc0.x; + else +#endif + texcol.w = texcol.w * fTexAlpha.y + fTexAlpha.x; + + texcol = texcol * (fTexAlpha2.zzzw * color + fTexAlpha2.xxxy) + fTexAlpha.zzzw * color.wwww; + + return texcol; +} + +// final ops on the color +#ifdef EXACT_COLOR + +half4 ps2FinalColor(half4 col) +{ + // g_fOneColor has to scale by 255 + half4 temp = col * g_fOneColor.xxxy + g_fOneColor.zzzw; + temp.w = floor(temp.w)*g_fExactColor.w; + return temp; +} + +#else +half4 ps2FinalColor(half4 col) +{ + return col * g_fOneColor.xxxy + g_fOneColor.zzzw; +} +#endif + +//////////////// +// Techniques // +//////////////// + +// technique to copy a rectangle from source to target +struct VSOUT_ +{ + float4 pos : POSITION; + half4 color : COLOR0; + DOZWRITE(float4 z : TEXCOORD0;) +}; + +struct VSOUT_T +{ + float4 pos : POSITION; + half4 color : COLOR0; + TEX_DECL tex : TEXCOORD0; + DOZWRITE(float4 z : TEXCOORD1;) +}; + +struct VSOUT_F +{ + float4 pos : POSITION; + half4 color : COLOR0; + float fog : TEXCOORD0; + DOZWRITE(float4 z : TEXCOORD1;) +}; + +struct VSOUT_TF +{ + float4 pos : POSITION; + half4 color : COLOR0; + TEX_DECL tex : TEXCOORD0; + half fog : TEXCOORD1; + DOZWRITE(float4 z : TEXCOORD2;) +}; + +// just smooth shadering +VSOUT_ RegularVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : COLOR1 + ) +{ + VSOUT_ o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; // 1 + o.color = color; + + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) + return o; +} + +void RegularPS(VSOUT_ i, out float4 c0 : COLOR0 +#ifdef WRITE_DEPTH + , out float4 c1 : COLOR1 +#endif + ) +{ + // whenever outputting depth, make sure to mult by 255/256 and 1 + c0 = ps2FinalColor(i.color); + DOZWRITE(c1 = i.z;) +} + +// diffuse texture mapping +VSOUT_T TextureVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : COLOR1, + float3 tex0 : TEXCOORD0) +{ + VSOUT_T o; + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x + g_fZNorm.y; + o.pos.w = g_fc0.y; + o.color = color; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) +#ifdef PERSPECTIVE_CORRECT_TEX + o.tex = tex0; +#else + o.tex = tex0.xy/tex0.z; +#endif + return o; +} + +#ifdef WRITE_DEPTH + +#define DECL_TEXPS(num, bit) \ +void Texture##num##bit##PS(VSOUT_T i, out half4 c0 : COLOR0, out float4 c1 : COLOR1) \ +{ \ + c0 = ps2FinalColor(ps2CalcShade(ps2shade##num##bit(i.tex), i.color)); \ + c1 = i.z; \ +} \ + +#else + +#define DECL_TEXPS(num, bit) \ +void Texture##num##bit##PS(VSOUT_T i, out half4 c0 : COLOR0) \ +{ \ + c0 = ps2FinalColor(ps2CalcShade(ps2shade##num##bit(i.tex), i.color)); \ +} \ + +#endif + +#define DECL_TEXPS_(num) \ +DECL_TEXPS(num, _32) \ +DECL_TEXPS(num, _tex32) \ +DECL_TEXPS(num, _clut32) \ +DECL_TEXPS(num, _tex32to16) \ +DECL_TEXPS(num, _tex16to8h) \ + +DECL_TEXPS_(0) +DECL_TEXPS_(1) +DECL_TEXPS_(2) +DECL_TEXPS_(3) +DECL_TEXPS_(4) +DECL_TEXPS_(5) + +VSOUT_F RegularFogVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : COLOR1) +{ + VSOUT_F o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) + o.color = color; + o.fog = pos.z*g_fBilinear.w; + return o; +} + +void RegularFogPS(VSOUT_F i, out half4 c0 : COLOR0 +#ifdef WRITE_DEPTH + , out float4 c1 : COLOR1 +#endif + ) +{ + half4 c; + c.xyz = lerp(g_fFogColor.xyz, i.color.xyz, i.fog); + c.w = i.color.w; + c0 = ps2FinalColor(c); + DOZWRITE(c1 = i.z;) +} + +VSOUT_TF TextureFogVS(float4 pos : POSITION, + half4 color : COLOR0, + float4 z : COLOR1, + float3 tex0 : TEXCOORD0) +{ + VSOUT_TF o; + + o.pos.xy = pos.xy*g_fPosXY.xy+g_fPosXY.zw; + o.pos.z = log(g_fc0.y+dot(g_fZ, z.zyxw))*g_fZNorm.x+g_fZNorm.y; + o.pos.w = g_fc0.y; + o.color = color; + o.fog = pos.z*g_fBilinear.w; + DOZWRITE(o.z = z*g_fZBias.x+g_fZBias.y; o.z.w = g_fc0.y;) +#ifdef PERSPECTIVE_CORRECT_TEX + o.tex = tex0; +#else + o.tex = tex0.xy/tex0.z; +#endif + return o; +} + +#ifdef WRITE_DEPTH + +#define DECL_TEXFOGPS(num, bit) \ +void TextureFog##num##bit##PS(VSOUT_TF i, out half4 c0 : COLOR0, out float4 c1 : COLOR1 ) \ +{ \ + half4 c = ps2CalcShade(ps2shade##num##bit(i.tex), i.color); \ + c.xyz = lerp(g_fFogColor.xyz, c.xyz, i.fog); \ + c0 = ps2FinalColor(c); \ + c1 = i.z; \ +} \ + +#else + +#define DECL_TEXFOGPS(num, bit) \ +void TextureFog##num##bit##PS(VSOUT_TF i, out half4 c0 : COLOR0) \ +{ \ + half4 c = ps2CalcShade(ps2shade##num##bit(i.tex), i.color); \ + c.xyz = lerp(g_fFogColor.xyz, c.xyz, i.fog); \ + c0 = ps2FinalColor(c); \ +} \ + +#endif + +#define DECL_TEXFOGPS_(num) \ +DECL_TEXFOGPS(num, _32) \ +DECL_TEXFOGPS(num, _tex32) \ +DECL_TEXFOGPS(num, _clut32) \ +DECL_TEXFOGPS(num, _tex32to16) \ +DECL_TEXFOGPS(num, _tex16to8h) \ + +DECL_TEXFOGPS_(0) +DECL_TEXFOGPS_(1) +DECL_TEXFOGPS_(2) +DECL_TEXFOGPS_(3) +DECL_TEXFOGPS_(4) +DECL_TEXFOGPS_(5) + +//------------------------------------------------------- +// Techniques not related to the main primitive commands +half4 BilinearBitBlt(float2 tex0) +{ + float4 ftex; + float2 ffrac; + + ffrac.xy = frac(tex0*g_fRealTexDims.xy); + ftex.xy = tex0 - ffrac.xy * g_fRealTexDims.zw; + ftex.zw = ftex.xy + g_fRealTexDims.zw; + + float4 off0, off1; + ps2memcoord4_fast(ftex, off0, off1); + half4 c0 = texRECT(g_sMemory, off0.xy); + half4 c1 = texRECT(g_sMemory, off0.zw); + half4 c2 = texRECT(g_sMemory, off1.xy); + half4 c3 = texRECT(g_sMemory, off1.zw); + + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y ); +} + +void BitBltVS(in float4 pos : POSITION, + in half4 tex0 : COLOR1, + in float3 tex : TEXCOORD0, + out float4 opos : POSITION, + out float2 otex0 : TEXCOORD0, + out float2 ointerpos : TEXCOORD1) +{ + opos.xy = pos.xy * g_fBitBltPos.xy + g_fBitBltPos.zw; + ointerpos = opos.xy * g_fBitBltTrans.xy + g_fBitBltTrans.zw; + opos.zw = g_fc0.xy; + otex0 = tex.xy * g_fBitBltTex.xy + g_fBitBltTex.zw; +} + +half4 BitBltPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return texRECT(g_sMemory, ps2memcoord(tex0).xy)*g_fOneColor.xxxy; +} + +// used when AA +half4 BitBltAAPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return BilinearBitBlt(tex0)*g_fOneColor.xxxy; +} + +void BitBltDepthPS(in float2 tex0 : TEXCOORD0, + out float4 c : COLOR0, + out float depth : DEPTH) +{ + c = texRECT(g_sMemory, ps2memcoord(tex0)); + + depth = log(g_fc0.y+dot(c, g_fBitBltZ))*g_fOneColor.w; + c += g_fZBias.y; +} + +void BitBltDepthMRTPS(in float2 tex0 : TEXCOORD0, + out half4 c0 : COLOR0, + out float4 c1 : COLOR1, + out float depth : DEPTH) +{ + c1 = texRECT(g_sMemory, ps2memcoord(tex0)); + + depth = log(g_fc0.y+dot(c1, g_fBitBltZ))*g_fOneColor.w; + c1 += g_fZBias.y; + c0 = g_fc0.x; +} + +/*static const float BlurKernel[9] = { + 0.027601, + 0.066213, + 0.123701, + 0.179952, + 0.205065, + 0.179952, + 0.123701, + 0.066213, + 0.027601 +};*/ + +half4 BilinearFloat16(float2 tex0) +{ + /*float4 ffrac, ftex; + ffrac.xy = frac(tex0); + ftex.xy = (tex0 - ffrac.xy) * g_fInvTexDims.xy + g_fInvTexDims.zw; + ftex.zw = ftex.xy + g_fInvTexDims.xy; + + half4 c0 = texRECT(g_sSrcFinal, ftex.xy); + half4 c1 = texRECT(g_sSrcFinal, ftex.zy); + half4 c2 = texRECT(g_sSrcFinal, ftex.xw); + half4 c3 = texRECT(g_sSrcFinal, ftex.zw); + + return lerp( lerp(c0, c1, ffrac.x), lerp(c2, c3, ffrac.x), ffrac.y );*/ + return texRECT(g_sSrcFinal, tex0.xy); +// return 0.55f * texRECT(g_sSrcFinal, tex0.xy) + +// 0.15f * texRECT(g_sSrcFinal, tex0.xy+g_fInvTexDims.xz) + +// 0.15f * texRECT(g_sSrcFinal, tex0.xy+g_fInvTexDims.zy) + +// 0.15f * texRECT(g_sSrcFinal, tex0.xy+g_fInvTexDims.xy); +} + +half4 CRTCTargInterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float finter = texRECT(g_sInterlace, ointerpos.yy).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = BilinearFloat16(tex0); + c.w = g_fc0.w*c.w * g_fOneColor.x + g_fOneColor.y; + return c; +} + +half4 CRTCTargPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float4 c = BilinearFloat16(tex0); + c.w = g_fc0.w*c.w * g_fOneColor.x + g_fOneColor.y; + return c; +} + +half4 CRTCInterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + float finter = texRECT(g_sInterlace, ointerpos.yy).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = BilinearBitBlt(filtcoord); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c; +} + +// simpler +half4 CRTCInterPS_Nearest(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float finter = texRECT(g_sInterlace, ointerpos.yy).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = texRECT(g_sMemory, ps2memcoord(tex0).xy); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + return c; +} + +half4 CRTCPS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float2 filtcoord = (tex0/*-frac(tex0)*/)*g_fInvTexDims.xy+g_fInvTexDims.zw; + half4 c = BilinearBitBlt(filtcoord); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c; +} + +// simpler +half4 CRTCPS_Nearest(in float2 tex0 : TEXCOORD0) : COLOR +{ + half4 c = texRECT(g_sMemory, ps2memcoord(tex0).xy); + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + return c; +} + +half4 CRTC24InterPS(in float2 tex0 : TEXCOORD0, in float2 ointerpos : TEXCOORD1) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + float finter = texRECT(g_sInterlace, ointerpos.yy).x; + clip(finter * g_fOneColor.z + g_fOneColor.w); + + half4 c = texRECT(g_sMemory, ps2memcoord(filtcoord).xy).x; + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c; +} + +half4 CRTC24PS(in float2 tex0 : TEXCOORD0) : COLOR +{ + float2 filtcoord = (tex0-frac(tex0))*g_fInvTexDims.xy+g_fInvTexDims.zw; + half4 c = texRECT(g_sMemory, ps2memcoord(filtcoord).xy).x; + c.w = c.w * g_fOneColor.x + g_fOneColor.y; + + return c; +} + +half4 ZeroPS() : COLOR +{ + return g_fOneColor.x; +} + +half4 BaseTexturePS(in float2 tex0 : TEXCOORD0) : COLOR +{ + return texRECT(g_sSrcFinal, tex0) * g_fOneColor; +} + +half4 Convert16to32PS(float2 tex0 : TEXCOORD0) : COLOR +{ + float4 final; + float2 ffrac = fmod(tex0+g_fTexDims.zw, g_fTexOffset.xy); + tex0.xy = g_fTexDims.xy * tex0.xy - ffrac * g_fc0.yw; + + if( ffrac.x > g_fTexOffset.x*g_fc0.w ) + tex0.x += g_fTexOffset.x*g_fc0.w; + if( tex0.x >= g_fc0.y ) tex0 += g_fTexOffset.zw; + + float4 lower = texRECT(g_sSrcFinal, tex0); + float4 upper = texRECT(g_sSrcFinal, tex0+g_fPageOffset.xy); + + final.zy = tex3D(g_sConv32to16, lower.zyx).xy + lower.ww*g_fPageOffset.zw; + final.xw = tex3D(g_sConv32to16, upper.zyx).xy + upper.ww*g_fPageOffset.zw; + + return final; +} + +// use when texture is not tiled and converting from 32bit to 16bit +// don't convert on the block level, only on the column level +// so every other 8 pixels, use the upper bits instead of lower +half4 Convert32to16PS(float2 tex0 : TEXCOORD0) : COLOR +{ + bool upper = false; + float2 ffrac = fmod(tex0+g_fTexDims.zw, g_fTexOffset.xy); + tex0.xy = g_fc0.ww * (tex0.xy + ffrac); + if( ffrac.x > g_fTexOffset.z ) { + tex0.x -= g_fTexOffset.z; + upper = true; + } + if( ffrac.y >= g_fTexOffset.w ) { + tex0.y -= g_fTexOffset.w; + tex0.x += g_fc0.w; + } + + half4 color = texRECT(g_sSrcFinal, tex0*g_fTexDims.xy)*g_fc0.yyyw; + float2 uv = upper ? color.xw : color.zy; + return tex2D(g_sConv16to32, uv*g_fPageOffset.xy+g_fPageOffset.zw)*g_fTexDims.xxxy; +} diff --git a/plugins/zerogs/opengl/rasterfont.cpp b/plugins/zerogs/opengl/rasterfont.cpp new file mode 100644 index 0000000000..8e217e5205 --- /dev/null +++ b/plugins/zerogs/opengl/rasterfont.cpp @@ -0,0 +1,147 @@ + +#ifdef _WIN32 +#include +#endif + +#include +#include + +#include "rasterfont.h" +// globals + +GLubyte rasters[][13] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, + {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, + {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, + {0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, + {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, + {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, + {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, + {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, + {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, + {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, + {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, + {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, + {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, + {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, + {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, + {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, + {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, + {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, + {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, + {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, + {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, + {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, + {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00} +}; + +RasterFont::RasterFont() +{ + // set GL modes + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + // create the raster font + fontOffset = glGenLists (128); + for (int i = 32; i < 127; i++) { + glNewList(i+fontOffset, GL_COMPILE); + glBitmap(8, 13, 0.0f, 2.0f, 10.0f, 0.0f, rasters[i-32]); + glEndList(); + } +} + +RasterFont::~RasterFont() +{ + glDeleteLists(fontOffset, 128); +} + +void RasterFont::printString(const char *s, double x, double y, double z) +{ + // go to the right spot + glRasterPos3d(x, y, z); + + glPushAttrib (GL_LIST_BIT); + glListBase(fontOffset); + glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s); + glPopAttrib (); +} + +void RasterFont::printCenteredString(const char *s, double y, int screen_width, double z) +{ + int length = strlen(s); + int x = int(screen_width/2.0 - (length/2.0)*char_width); + + printString(s, x, y, z); +} + diff --git a/plugins/zerogs/opengl/rasterfont.h b/plugins/zerogs/opengl/rasterfont.h new file mode 100644 index 0000000000..2aaf8ba98f --- /dev/null +++ b/plugins/zerogs/opengl/rasterfont.h @@ -0,0 +1,22 @@ +#ifndef RasterFont_Header +#define RasterFont_Header + +class RasterFont { +protected: + int fontOffset; + +public: + RasterFont(); + ~RasterFont(void); + static int debug; + + // some useful constants + enum {char_width = 10}; + enum {char_height = 15}; + + // and the happy helper functions + void printString(const char *s, double x, double y, double z=0.0); + void printCenteredString(const char *s, double y, int screen_width, double z=0.0); +}; + +#endif diff --git a/plugins/zerogs/opengl/targets.cpp b/plugins/zerogs/opengl/targets.cpp new file mode 100644 index 0000000000..c5e3489875 --- /dev/null +++ b/plugins/zerogs/opengl/targets.cpp @@ -0,0 +1,3547 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 "GS.h" +#include +#include + +#include + +#include +#include +#include +#include + +#include "Mem.h" +#include "x86.h" +#include "zerogs.h" + +#include "targets.h" + +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +extern int g_GameSettings; +using namespace ZeroGS; +extern int g_TransferredToGPU; +extern BOOL g_bIsLost; +extern BOOL g_bUpdateStencil; +extern u32 s_uFramebuffer; + +#ifdef RELEASE_TO_PUBLIC +#define INC_RESOLVE() +#else +#define INC_RESOLVE() ++g_nResolve +extern u32 g_nResolve; +extern BOOL g_bSaveTrans; +#endif + +namespace ZeroGS { + CRenderTargetMngr s_RTs, s_DepthRTs; + CBitwiseTextureMngr s_BitwiseTextures; + CMemoryTargetMngr g_MemTargs; + + extern u8 s_AAx, s_AAy; + extern Vector g_vdepth; + extern int icurctx; + + extern VERTEXSHADER pvsBitBlt; + extern FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; + extern FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; + extern GLuint vboRect; +} + +extern u32 s_ptexCurSet[2]; +extern u32 ptexBilinearBlocks; +extern u32 ptexConv32to16; +BOOL g_bSaveZUpdate = 0; + +//////////////////// +// Render Targets // +//////////////////// +ZeroGS::CRenderTarget::CRenderTarget() : ptex(0), ptexFeedback(0), psys(NULL) +{ + nUpdateTarg = 0; +} + +ZeroGS::CRenderTarget::~CRenderTarget() +{ + Destroy(); +} + +bool ZeroGS::CRenderTarget::Create(const frameInfo& frame) +{ + Resolve(); + Destroy(); + + lastused = timeGetTime(); + fbp = frame.fbp; + fbw = frame.fbw; + fbh = frame.fbh; + psm = (u8)frame.psm; + fbm = frame.fbm; + + vposxy.x = 2.0f * (1.0f / 8.0f) / (float)fbw; + vposxy.y = 2.0f * (1.0f / 8.0f) / (float)fbh; + vposxy.z = -1-0.5f/fbw; + vposxy.w = -1+0.5f/fbh; + status = 0; + + if( fbw > 0 && fbh > 0 ) { + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + psys = _aligned_malloc( (fbh<= fbp ); + + dy = ((256/bpp)*(fbplocal-fbp)) / fbw; + + v.x = vposxy.x; + v.y = vposxy.y; + v.z = vposxy.z; + v.w = vposxy.w - dy*2.0f/(float)fbh; + cgGLSetParameter4fv(g_vparamPosXY[context], v); + } + else + cgGLSetParameter4fv(g_vparamPosXY[context], vposxy); + + // set render states + scissorrect.x = scissor.x0>>3; + scissorrect.y = (scissor.y0>>3) + dy; + scissorrect.w = (scissor.x1>>3)+1; + scissorrect.h = (scissor.y1>>3)+1+dy; + scissorrect.w = min(scissorrect.w, fbw) - scissorrect.x; + scissorrect.h = min(scissorrect.h, fbh) - scissorrect.y; + + scissorrect.x <<= s_AAx; + scissorrect.y <<= s_AAy; + scissorrect.w <<= s_AAx; + scissorrect.h <<= s_AAy; +} + +void ZeroGS::CRenderTarget::SetViewport() +{ + glViewport(0, 0, fbw< 10 || (g_GameSettings&GAME_NOTARGETRESOLVE) ) { + // don't resolve if depths aren't used + status = TS_Resolved; + return; + } + + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptex); + GL_REPORT_ERRORD(); + //glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), GetRenderFormat()==RFT_float16?GL_FLOAT:GL_UNSIGNED_BYTE, psys); + glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, GL_UNSIGNED_BYTE, psys); + GL_REPORT_ERRORD(); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + SaveTexture("resolved.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw< start ); // make sure it at least intersects + + if( ptex != 0 && !(status&TS_Resolved) && !(status&TS_NeedUpdate) ) { + + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveResolved ) { + SaveTexture("resolved.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw<>6); + + // in now way should data be overwritten!, instead resolve less + if( endrange < end ) { + // round down to nearest block and scanline + resolveheight = ((endrange-start)/(0x2000*(fbw>>6))) * blockheight; + if( resolveheight <= 32 ) { + status = TS_Resolved; + return; + } + } + else if( startrange > start ) { + // round up to nearest block and scanline + resolvefbp = startrange + scanlinewidth - 1; + resolvefbp -= resolvefbp % scanlinewidth; + + resolveheight = fbh-((resolvefbp-fbp)*blockheight/scanlinewidth); + if( resolveheight <= 64 ) { // this is a total hack, but kh doesn't resolve now + status = TS_Resolved; + return; + } + + resolvefbp >>= 8; + } + + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptex); + //glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), GetRenderFormat()==RFT_float16?GL_FLOAT:GL_UNSIGNED_BYTE, psys); + glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, GL_UNSIGNED_BYTE, psys); + GL_REPORT_ERRORD(); + + u8* pbits = (u8*)psys; + u32 Pitch = (fbw<SetDepthStencilSurface(psurfDepth); + ResetRenderTarget(1); + SetRenderTarget(0); + assert( pdepth != NULL ); + ((CDepthTarget*)pdepth)->SetDepthStencilSurface(); + + Vector v = Vector(1,-1,-0.5f/(float)(fbw<second == this ) { + ERROR_LOG("updating self"); + nUpdateTarg = 0; + } + } + else if( ittarg->second == this ) { + ERROR_LOG("updating self"); + nUpdateTarg = 0; + } + } + + SetViewport(); + + if( nUpdateTarg ) { + + cgGLSetTextureParameter(ppsBaseTexture.sFinal, ittarg->second->ptex); + cgGLEnableTextureParameter(ppsBaseTexture.sFinal); + + //assert( ittarg->second->fbw == fbw ); + int offset = (fbp-ittarg->second->fbp)*64/fbw; + if( psm & 2 ) // 16 bit + offset *= 2; + + v.x = (float)(fbw << s_AAx); + v.y = (float)(fbh << s_AAy); + v.z = 0.25f; + v.w = (float)(offset << s_AAy) + 0.25f; + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + v.x = v.y = v.z = v.w = 1; + cgGLSetParameter4fv(ppsBaseTexture.sOneColor, v); + + SETPIXELSHADER(ppsBaseTexture.prog); + nUpdateTarg = 0; + } + else { + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + tex0Info texframe; + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + + // write color and zero out stencil buf, always 0 context! + // force bilinear if using AA + SetTexVariablesInt(0, (s_AAx || s_AAy)?2:0, texframe, pmemtarg, &ppsBitBlt[s_AAx], 1); + cgGLSetTextureParameter(ppsBitBlt[s_AAx].sMemory, pmemtarg->ptex->tex); + cgGLEnableTextureParameter(ppsBitBlt[s_AAx].sMemory); + + v = Vector(1,1,0,0); + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, v); + + v.x = 1; + v.y = 2; + cgGLSetParameter4fv(ppsBitBlt[s_AAx].sOneColor, v); + + assert( ptex != 0 ); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + if( ZeroGS::IsWriteDestAlphaTest() ) { + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 0, 0xff); + glStencilMask(0xff); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + } + + // render with an AA shader if possible (bilinearly interpolates data) + //cgGLLoadProgram(ppsBitBlt[s_AAx].prog); + SETPIXELSHADER(ppsBitBlt[s_AAx].prog); + } + + SETVERTEXSHADER(pvsBitBlt.prog); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // fill stencil buf only + if( ZeroGS::IsWriteDestAlphaTest() && !(g_GameSettings&GAME_NOSTENCIL)) { + glColorMask(0,0,0,0); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GEQUAL, 1); + + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 1, 0xff); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glColorMask(1,1,1,1); + } + + glEnable(GL_SCISSOR_TEST); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + if( conf.mrtdepth && pdepth != NULL && ZeroGS::IsWriteDepth() ) + pdepth->SetRenderTarget(1); + + status = TS_Resolved; + + // reset since settings changed + vb[0].bVarsTexSync = 0; + ZeroGS::ResetAlphaVariables(); +} + +void ZeroGS::CRenderTarget::ConvertTo32() +{ + u32 ptexConv; + + // create new target + glGenTextures(1, &ptexConv); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexConv); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +void ZeroGS::CRenderTarget::ConvertTo16() +{ + u32 ptexConv; + + // create new target + glGenTextures(1, &ptexConv); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexConv); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<Create(frame); +// s_DepthRTs.mapDummyTargs[(fbw<<16)|fbh] = pnewdepth; +// } +// else pnewdepth = (CDepthTarget*)itdepth->second; +// +// assert( pnewdepth != NULL ); +// pd3dDevice->SetDepthStencilSurface(pnewdepth->pdepth); + + SetViewport(); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + // render with an AA shader if possible (bilinearly interpolates data) + SETVERTEXSHADER(pvsBitBlt.prog); + SETPIXELSHADER(ppsConvert32to16.prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + +#ifdef _DEBUG + //g_bSaveZUpdate = 1; + if( g_bSaveZUpdate ) { + SaveTexture("tex1.tga", GL_TEXTURE_RECTANGLE_NV, ptexConv, fbw<= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + vb[icurctx].bVarsSetTarg = 0; + } + vb[0].bVarsTexSync = 0; +} + +void ZeroGS::CRenderTarget::_CreateFeedback() +{ + if( ptexFeedback == 0 ) { + // create + glGenTextures(1, &ptexFeedback); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexFeedback); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GetRenderTargetFormat(), fbw<= 0 ) { + // reset since settings changed + vb[icurctx].bVarsTexSync = 0; + } + + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); +} + +void ZeroGS::CRenderTarget::SetRenderTarget(int targ) +{ + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+targ, GL_TEXTURE_RECTANGLE_NV, ptex, 0 ); + //assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); +} + +ZeroGS::CDepthTarget::CDepthTarget() : CRenderTarget(), pdepth(0), pstencil(0), icount(0) {} + +ZeroGS::CDepthTarget::~CDepthTarget() +{ + Destroy(); +} + +bool ZeroGS::CDepthTarget::Create(const frameInfo& frame) +{ + if( !CRenderTarget::Create(frame) ) + return false; + + if( psm == 0x31 ) fbm = 0xff000000; + else fbm = 0; + + assert( glGetError() == GL_NO_ERROR ); + + glGenRenderbuffersEXT( 1, &pdepth ); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, pdepth); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, fbw< 0 if depth is used + +void ZeroGS::CDepthTarget::Resolve() +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() && !(g_GameSettings&GAME_NODEPTHRESOLVE) ) + CRenderTarget::Resolve(); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +void ZeroGS::CDepthTarget::Resolve(int startrange, int endrange) +{ + if( g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() ) CRenderTarget::Resolve(startrange, endrange); + else { + // flush if necessary + if( vb[0].prndr == this || vb[0].pdepth == this ) Flush(0); + if( vb[1].prndr == this || vb[1].pdepth == this ) Flush(1); + + if( !(status & TS_Virtual) ) + status |= TS_Resolved; + } + + if( !(status&TS_Virtual) ) { + ZeroGS::SetWriteDepth(); + } +} + +extern int g_nDepthUpdateCount; + +void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) +{ + assert( !(status & TS_Virtual) ); + + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + tex0Info texframe; + texframe.tbp0 = fbp; + texframe.tbw = fbw; + texframe.tw = fbw; + texframe.th = fbh; + texframe.psm = psm; + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glEnable(GL_DEPTH_TEST); + glDepthMask(1); + glDisable(GL_STENCIL_TEST); + glDepthFunc(GL_ALWAYS); + + // write color and zero out stencil buf, always 0 context! + SetTexVariablesInt(0, 0, texframe, pmemtarg, &ppsBitBltDepth, 1); + cgGLSetTextureParameter(ppsBitBltDepth.sMemory, pmemtarg->ptex->tex); + cgGLEnableTextureParameter(ppsBaseTexture.sFinal); + + Vector v = Vector(1,-1,0.5f/(float)fbw,-0.5f/(float)fbh); + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, v); + + v.z = v.w = 0; + v *= 1/32767.0f; + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + v.x = 1; + v.y = 2; + v.z = (psm&3)==2?1.0f:0.0f; + v.w = g_filog32; + cgGLSetParameter4fv(ppsBitBltDepth.sOneColor, v); + + Vector vdepth = ((255.0f/256.0f)*g_vdepth); + if( psm == PSMT24Z ) vdepth.w = 0; + else if( psm != PSMT32Z ) { vdepth.z = vdepth.w = 0; } + assert( ppsBitBltDepth.sBitBltZ != 0 ); + cgGLSetParameter4fv(ppsBitBltDepth.sBitBltZ, ((255.0f/256.0f)*vdepth)); + + assert( pdepth != 0 ); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_NV, ptex, 0 ); + SetDepthStencilSurface(); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); + GLenum buffer = GL_COLOR_ATTACHMENT0_EXT; + if( glDrawBuffers != NULL ) + glDrawBuffers(1, &buffer); + int stat = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); + + SetViewport(); + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + SET_STREAM(); + + SETVERTEXSHADER(pvsBitBlt.prog); + SETPIXELSHADER(ppsBitBltDepth.prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + status = TS_Resolved; + + if( !ZeroGS::IsWriteDepth() ) { + ResetRenderTarget(1); + } + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glEnable(GL_SCISSOR_TEST); + +#ifdef _DEBUG + if( g_bSaveZUpdate ) { + SaveTex(&texframe, 1); + SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, ptex, fbw<second; + mapTargets.clear(); + for(MAPTARGETS::iterator it = mapDummyTargs.begin(); it != mapDummyTargs.end(); ++it) + delete it->second; + mapDummyTargs.clear(); +} + +void ZeroGS::CRenderTargetMngr::DestroyAllTargs(int start, int end, int fbw) +{ + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second->start < end && start < it->second->end ) { + // if is depth, only resolve if fbw is the same + if( !it->second->IsDepth() ) { + // only resolve if the widths are the same or it->second has bit outside the range + // shadow of colossus swaps between fbw=256,fbh=256 and fbw=512,fbh=448. This kills the game if doing || it->second->end > end + + // kh hack, sometimes kh movies do this to clear the target, so have a static count that periodically checks end + static int count = 0; + + if( it->second->fbw == fbw || (it->second->fbw != fbw && (it->second->start < start || ((count++&0xf)?0:it->second->end > end) )) ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + else { + if( it->second->fbw == fbw ) + it->second->Resolve(); + else { + if( vb[0].prndr == it->second || vb[0].pdepth == it->second ) Flush(0); + if( vb[1].prndr == it->second || vb[1].pdepth == it->second ) Flush(1); + + it->second->status |= CRenderTarget::TS_Resolved; + } + } + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + mapDummyTargs[dummykey] = it->second; + } + else + delete it->second; + mapTargets.erase(it++); + } + else ++it; + } +} + +void ZeroGS::CRenderTargetMngr::DestroyTarg(CRenderTarget* ptarg) +{ + for(int i = 0; i < 2; ++i) { + if( ptarg == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( ptarg == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + delete ptarg; +} + +void ZeroGS::CRenderTargetMngr::DestroyIntersecting(CRenderTarget* prndr) +{ + assert( prndr != NULL ); + + int start, end; + GetRectMemAddress(start, end, prndr->psm, 0, 0, prndr->fbw, prndr->fbh, prndr->fbp, prndr->fbw); + + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end();) { + if( it->second != prndr && it->second->start < end && start < it->second->end ) { + it->second->Resolve(); + + for(int i = 0; i < 2; ++i) { + if( it->second == vb[i].prndr ) { vb[i].prndr = NULL; vb[i].bNeedFrameCheck = 1; } + if( it->second == vb[i].pdepth ) { vb[i].pdepth = NULL; vb[i].bNeedZCheck = 1; } + } + + u32 dummykey = (it->second->fbw<<16)|it->second->fbh; + if( mapDummyTargs.find(dummykey) == mapDummyTargs.end() ) { + mapDummyTargs[dummykey] = it->second; + } + else + delete it->second; + + mapTargets.erase(it++); + } + else ++it; + } +} + +CRenderTarget* ZeroGS::CRenderTargetMngr::GetTarg(const frameInfo& frame, u32 opts, int maxposheight) +{ + if( frame.fbw <= 0 || frame.fbh <= 0 ) + return NULL; + + GL_REPORT_ERRORD(); + + u32 key = frame.fbp|(frame.fbw<<16); + MAPTARGETS::iterator it = mapTargets.find(key); + + // only enforce height if frame.fbh <= 0x1c0 + bool bfound = it != mapTargets.end(); + if( bfound ) { + if( opts&TO_StrictHeight ) { + bfound = it->second->fbh == frame.fbh; + } + else { + if( (frame.psm&2)==(it->second->psm&2) && !(g_GameSettings & GAME_FULL16BITRES) ) + bfound = (frame.fbh > 0x1c0 || it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + } + + if( !bfound ) { + // might be a virtual target + it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + bfound = it != mapTargets.end() && ((opts&TO_StrictHeight) ? it->second->fbh == frame.fbh : it->second->fbh >= frame.fbh) && it->second->fbh <= maxposheight; + } + + if( bfound ) { + + // can be both 16bit and 32bit + if( (frame.psm&2) != (it->second->psm&2) ) { + // a lot of games do this actually... +#ifdef _DEBUG + WARN_LOG("Really bad formats! %d %d\n", frame.psm, it->second->psm); +#endif +// if( g_GameSettings & GAME_VSSHACK ) { +// if( it->second->psm & 2 ) { +// it->second->status |= CRenderTarget::TS_NeedConvert32; +// it->second->fbh /= 2; +// } +// else { +// it->second->status |= CRenderTarget::TS_NeedConvert16; +// it->second->fbh *= 2; +// } +// } + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + else { + // certain variables have to be reset every time + if( (it->second->psm&~1) != (frame.psm&~1) ) { +#ifndef RELEASE_TO_PUBLIC + WARN_LOG("bad formats 2: %d %d\n", frame.psm, it->second->psm); +#endif + it->second->psm = frame.psm; + + // recalc extents + GetRectMemAddress(it->second->start, it->second->end, frame.psm, 0, 0, frame.fbw, it->second->fbh, it->second->fbp, frame.fbw); + } + } + + if( it->second->fbm != frame.fbm ) { + //WARN_LOG("bad fbm: 0x%8.8x 0x%8.8x, psm: %d\n", frame.fbm, it->second->fbm, frame.psm); + } + + it->second->fbm &= frame.fbm; + it->second->psm = frame.psm; // have to convert (ffx2) + + if( (it->first & TARGET_VIRTUAL_KEY) && !(opts&TO_Virtual) ) { + // switch + it->second->lastused = timeGetTime(); + return Promote(it->first&~TARGET_VIRTUAL_KEY); + } + + // check if there exists a more recent target that this target could update from + for(MAPTARGETS::iterator itnew = mapTargets.begin(); itnew != mapTargets.end(); ++itnew) { + if( itnew->second != it->second && itnew->second->start <= it->second->start && itnew->second->end >= it->second->end && + itnew->second->lastused > it->second->lastused && !(itnew->second->status & CRenderTarget::TS_NeedUpdate) ) { + + it->second->status |= CRenderTarget::TS_NeedUpdate; + it->second->nUpdateTarg = itnew->first; + break; + } + } + + it->second->lastused = timeGetTime(); + + return it->second; + } + + // NOTE: instead of resolving, if current render targ is completely outside of old, can transfer + // the data like that. + + // have to change, so recreate (find all intersecting targets and Resolve) + u32 besttarg = 0; + + if( !(opts & CRenderTargetMngr::TO_Virtual) ) { + + int start, end; + GetRectMemAddress(start, end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + if( !(opts & CRenderTargetMngr::TO_StrictHeight) ) { + + // if there is only one intersecting target and it encompasses the current one, update the new render target with + // its data instead of resolving then updating (ffx2). Do not change the original target. + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) { +// if( g_GameSettings&GAME_FASTUPDATE ) { +// besttarg = it->first; +// //break; +// } +// else { + if( (g_GameSettings&GAME_FASTUPDATE) || (it->second->fbp != frame.fbp && it->second->fbw == frame.fbw) ) { + + if( besttarg != 0 ) { + besttarg = 0; + break; + } + + if( start >= it->second->start && end <= it->second->end ) { + besttarg = it->first; + } + } +// } + } + } + } + + if( besttarg == 0 ) { + // if none found, resolve all + DestroyAllTargs(start, end, frame.fbw); + } + } + + if( mapTargets.size() > 8 ) { + // release some resources + it = GetOldestTarg(mapTargets); + + // if more than 5s passed since target used, destroy + if( timeGetTime()-it->second->lastused > 5000 ) { + delete it->second; + mapTargets.erase(it); + } + } + + if( mapDummyTargs.size() > 8 ) { + it = GetOldestTarg(mapDummyTargs); + + delete it->second; + mapDummyTargs.erase(it); + } + + // first search for the target + CRenderTarget* ptarg = NULL; + + it = mapDummyTargs.find( (frame.fbw<<16)|frame.fbh ); + if( it != mapDummyTargs.end() ) { + ptarg = it->second; + mapDummyTargs.erase(it); + + // restore all setttings + ptarg->psm = frame.psm; + ptarg->fbm = frame.fbm; + ptarg->fbp = frame.fbp; + GetRectMemAddress(ptarg->start, ptarg->end, frame.psm, 0, 0, frame.fbw, frame.fbh, frame.fbp, frame.fbw); + + ptarg->status = CRenderTarget::TS_NeedUpdate; + } + else { + // create anew + ptarg = (opts&TO_DepthBuffer) ? new CDepthTarget() : new CRenderTarget(); + CRenderTargetMngr* pmngrs[2] = { &s_DepthRTs, this == &s_RTs ? &s_RTs : NULL }; + int cur = 0; + + while( !ptarg->Create(frame) ) { + + // destroy unused targets + if( mapDummyTargs.size() > 0 ) { + it = mapDummyTargs.begin(); + delete it->second; + mapDummyTargs.erase(it); + continue; + } + + if( g_MemTargs.listClearedTargets.size() > 0 ) { + g_MemTargs.DestroyCleared(); + continue; + } + else + if( g_MemTargs.listTargets.size() > 32 ) { + g_MemTargs.DestroyOldest(); + continue; + } + + if( pmngrs[cur] == NULL ) { + cur = !cur; + if( pmngrs[cur] == NULL ) { + WARN_LOG("Out of memory!\n"); + delete ptarg; + return NULL; + } + } + + if( pmngrs[cur]->mapTargets.size() == 0 ) + { + pmngrs[cur] = NULL; + cur = !cur; + continue; + } + + it = GetOldestTarg(pmngrs[cur]->mapTargets); + + DestroyTarg(it->second); + pmngrs[cur]->mapTargets.erase(it); + cur = !cur; + } + } + + if( (opts & CRenderTargetMngr::TO_Virtual) ) { + ptarg->status = CRenderTarget::TS_Virtual; + key |= TARGET_VIRTUAL_KEY; + + if( (it = mapTargets.find(key)) != mapTargets.end() ) { + + DestroyTarg(it->second); + it->second = ptarg; + ptarg->nUpdateTarg = besttarg; + return ptarg; + } + } + else + assert( mapTargets.find(key) == mapTargets.end()); + + ptarg->nUpdateTarg = besttarg; + mapTargets[key] = ptarg; + return ptarg; +} + +ZeroGS::CRenderTargetMngr::MAPTARGETS::iterator ZeroGS::CRenderTargetMngr::GetOldestTarg(MAPTARGETS& m) +{ + if( m.size() == 0 ) { + return m.end(); + } + + // release some resources + u32 curtime = timeGetTime(); + MAPTARGETS::iterator itmaxtarg = m.begin(); + for(MAPTARGETS::iterator it = ++m.begin(); it != m.end(); ++it) { + if( itmaxtarg->second->lastused-curtime < it->second->lastused-curtime ) itmaxtarg = it; + } + + return itmaxtarg; +} + +void ZeroGS::CRenderTargetMngr::GetTargs(int start, int end, list& listTargets) const +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) listTargets.push_back(it->second); + } +} + +void ZeroGS::CRenderTargetMngr::Resolve(int start, int end) +{ + for(MAPTARGETS::const_iterator it = mapTargets.begin(); it != mapTargets.end(); ++it) { + if( it->second->start < end && start < it->second->end ) + it->second->Resolve(); + } +} + +void ZeroGS::CMemoryTargetMngr::Destroy() +{ + listTargets.clear(); + listClearedTargets.clear(); +} + +int memcmp_clut16(u16* pSavedBuffer, u16* pClutBuffer, int clutsize) +{ + assert( (clutsize&31) == 0 ); + + // left > 0 only when csa < 16 + int left = ((u32)(uptr)pClutBuffer & 2) ? 0 : (((u32)(uptr)pClutBuffer & 0x3ff)/2) + clutsize - 512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + clutsize -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + + if( left > 0 ) { + pClutBuffer = (u16*)(g_pbyGSClut + 2); + + while(left > 0) { + for(int i = 0; i < 16; ++i) { + if( pSavedBuffer[i] != pClutBuffer[2*i] ) + return 1; + } + + left -= 32; + pSavedBuffer += 16; + pClutBuffer += 32; + } + } + + return 0; +} + +bool ZeroGS::CMemoryTarget::ValidateClut(const tex0Info& tex0) +{ + assert( tex0.psm == psm && PSMT_ISCLUT(psm) && cpsm == tex0.cpsm ); + + int nClutOffset = 0; + int clutsize = 0; + + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 32 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + + assert( clutsize == clut.size() ); + + if( cpsm <= 1 ) { + if( memcmp_mmx(&clut[0], g_pbyGSClut+nClutOffset, clutsize) ) + return false; + } + else { + if( memcmp_clut16((u16*)&clut[0], (u16*)(g_pbyGSClut+nClutOffset), clutsize) ) + return false; + } + + return true; +} + +int VALIDATE_THRESH = 8; +u32 TEXDESTROY_THRESH = 16; + +bool ZeroGS::CMemoryTarget::ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex) +{ + if( clearmaxy == 0 ) + return true; + + int checkstarty = max(starttex, clearminy); + int checkendy = min(endtex, clearmaxy); + if( checkstarty >= checkendy ) + return true; + + if( validatecount++ > VALIDATE_THRESH ) { + height = 0; + return false; + } + + // lock and compare + assert( ptex != NULL && ptex->memptr != NULL); + + int result = memcmp_mmx(ptex->memptr + (checkstarty-realy)*4*GPU_TEXWIDTH, g_pbyGSMemory+checkstarty*4*GPU_TEXWIDTH, (checkendy-checkstarty)*4*GPU_TEXWIDTH); + + if( result == 0 || !bDeleteBadTex ) { + if( result == 0 ) clearmaxy = 0; + return result == 0; + } + + // delete clearminy, clearmaxy range (not the checkstarty, checkendy range) + int newstarty = 0; + if( clearminy <= starty ) { + if( clearmaxy < starty + height) { + // preserve end + height = starty+height-clearmaxy; + starty = clearmaxy; + assert(height > 0); + } + else { + // destroy + height = 0; + } + } + else { + // beginning can be preserved + height = clearminy-starty; + } + + clearmaxy = 0; + assert( starty >= realy && starty+height<=realy+realheight ); + + return false; +} + +// used to build clut textures (note that this is for both 16 and 32 bit cluts) +#define BUILDCLUT() { \ + switch(tex0.psm) { \ + case PSMT8: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/2; ++j) { \ + pdst[0] = pclut[psrc[0]]; \ + pdst[1] = pclut[psrc[1]]; \ + pdst[2] = pclut[psrc[2]]; \ + pdst[3] = pclut[psrc[3]]; \ + pdst[4] = pclut[psrc[4]]; \ + pdst[5] = pclut[psrc[5]]; \ + pdst[6] = pclut[psrc[6]]; \ + pdst[7] = pclut[psrc[7]]; \ + pdst += 8; \ + psrc += 8; \ + } \ + } \ + break; \ + case PSMT4: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH; ++j) { \ + pdst[0] = pclut[psrc[0]&15]; \ + pdst[1] = pclut[psrc[0]>>4]; \ + pdst[2] = pclut[psrc[1]&15]; \ + pdst[3] = pclut[psrc[1]>>4]; \ + pdst[4] = pclut[psrc[2]&15]; \ + pdst[5] = pclut[psrc[2]>>4]; \ + pdst[6] = pclut[psrc[3]&15]; \ + pdst[7] = pclut[psrc[3]>>4]; \ + \ + pdst += 8; \ + psrc += 4; \ + } \ + } \ + break; \ + case PSMT8H: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]]; \ + pdst[1] = pclut[psrc[7]]; \ + pdst[2] = pclut[psrc[11]]; \ + pdst[3] = pclut[psrc[15]]; \ + pdst[4] = pclut[psrc[19]]; \ + pdst[5] = pclut[psrc[23]]; \ + pdst[6] = pclut[psrc[27]]; \ + pdst[7] = pclut[psrc[31]]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HH: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]>>4]; \ + pdst[1] = pclut[psrc[7]>>4]; \ + pdst[2] = pclut[psrc[11]>>4]; \ + pdst[3] = pclut[psrc[15]>>4]; \ + pdst[4] = pclut[psrc[19]>>4]; \ + pdst[5] = pclut[psrc[23]>>4]; \ + pdst[6] = pclut[psrc[27]>>4]; \ + pdst[7] = pclut[psrc[31]>>4]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + case PSMT4HL: \ + for(int i = 0; i < targ->height; ++i) { \ + for(int j = 0; j < GPU_TEXWIDTH/8; ++j) { \ + pdst[0] = pclut[psrc[3]&15]; \ + pdst[1] = pclut[psrc[7]&15]; \ + pdst[2] = pclut[psrc[11]&15]; \ + pdst[3] = pclut[psrc[15]&15]; \ + pdst[4] = pclut[psrc[19]&15]; \ + pdst[5] = pclut[psrc[23]&15]; \ + pdst[6] = pclut[psrc[27]&15]; \ + pdst[7] = pclut[psrc[31]&15]; \ + pdst += 8; \ + psrc += 32; \ + } \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} \ + +#define TARGET_THRESH 0x500 + +extern int g_MaxTexWidth, g_MaxTexHeight; + +//#define SORT_TARGETS +inline list::iterator ZeroGS::CMemoryTargetMngr::DestroyTargetIter(list::iterator& it) +{ + // find the target and destroy + list::iterator itprev = it; ++it; + listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); + + if( listClearedTargets.size() > TEXDESTROY_THRESH ) { + listClearedTargets.pop_front(); + } + + return it; +} + +#if defined(_MSC_VER) && defined(__x86_64__) +extern "C" void UnswizzleZ16Target(void* dst, void* src, int iters); +#endif + +ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info& tex0, int forcevalidate) +{ + int nbStart, nbEnd; + GetRectMemAddress(nbStart, nbEnd, tex0.psm, 0, 0, tex0.tw, tex0.th, tex0.tbp0, tex0.tbw); + assert( nbStart < nbEnd ); + nbEnd = min(nbEnd, 0x00400000); + + int nClutOffset = 0; + int clutsize = 0; + + if( PSMT_ISCLUT(tex0.psm) ) { + int entries = (tex0.psm&3)==3 ? 256 : 16; + if( tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * tex0.csa; + clutsize = min(entries, 256-tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (tex0.csa&15) + (tex0.csa>=16?2:0); + clutsize = min(entries, 512-tex0.csa*16)*2; + } + } + + DVProfileFunc _pf("GetMemoryTarget"); + + int start = nbStart / (4*GPU_TEXWIDTH); + int end = (nbEnd + GPU_TEXWIDTH*4 - 1) / (4*GPU_TEXWIDTH); + assert( start < end ); + + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + + if( it->starty <= start && it->starty+it->height >= end ) { + + assert( it->psm != 0xd ); + + // using clut, validate that same data + if( PSMT_ISCLUT(it->psm) != PSMT_ISCLUT(tex0.psm) ) { + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( PSMT_ISCLUT(tex0.psm) ) { + assert( it->clut.size() > 0 ); + + if( it->psm != tex0.psm || it->cpsm != tex0.cpsm || it->clut.size() != clutsize ) { + // wrong clut + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + + if( tex0.cpsm <= 1 ) { + if( memcmp_mmx(&it->clut[0], g_pbyGSClut+nClutOffset, clutsize) ) { + ++it; + continue; + } + } + else { + if( memcmp_clut16((u16*)&it->clut[0], (u16*)(g_pbyGSClut+nClutOffset), clutsize) ) { + ++it; + continue; + } + } + } + else if( PSMT_IS16BIT(tex0.psm) != PSMT_IS16BIT(it->psm) ) { + + if( it->validatecount++ > VALIDATE_THRESH ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + + continue; + } + + if( forcevalidate ) {//&& listTargets.size() < TARGET_THRESH ) { + // do more validation checking. delete if not been used for a while + if( !it->ValidateTex(tex0, start, end, curstamp > it->usedstamp + 3) ) { + if( it->height <= 0 ) { + it = DestroyTargetIter(it); + if( listTargets.size() == 0 ) + break; + } + else + ++it; + continue; + } + } + + it->usedstamp = curstamp; + it->validatecount = 0; + + return &(*it); + } +#ifdef SORT_TARGETS + else if( it->starty >= end ) + break; +#endif + + ++it; + } + + // couldn't find so create + DVProfileFunc _pf1("GetMemoryTarget:Create"); + + CMemoryTarget* targ; + + u32 fmt = GL_UNSIGNED_BYTE; + if( (PSMT_ISCLUT(tex0.psm) && tex0.cpsm > 1) || tex0.psm == PSMCT16 || tex0.psm == PSMCT16S) { + fmt = GL_UNSIGNED_SHORT_1_5_5_5_REV; + } + + int widthmult = 1; + if( g_MaxTexHeight < 4096 ) { + if( end-start > g_MaxTexHeight ) + widthmult = 2; + } + + int channels = 1; + if( PSMT_ISCLUT(tex0.psm) ) { + if( tex0.psm == PSMT8 ) channels = 4; + else if( tex0.psm == PSMT4 ) channels = 8; + } + else { + if( PSMT_IS16BIT(tex0.psm) ) { + // 16z needs to be a8r8g8b8 + channels = 2; + } + } + + if( listClearedTargets.size() > 0 ) { + + list::iterator itbest = listClearedTargets.begin(); + while(itbest != listClearedTargets.end()) { + + if( end-start <= itbest->realheight && itbest->fmt == fmt && itbest->widthmult == widthmult && itbest->channels == channels ) { + // check channels + int targchannels = 1; + if( PSMT_ISCLUT(itbest->psm) ) { + if( itbest->psm == PSMT8 ) targchannels = 4; + else if( itbest->psm == PSMT4 ) targchannels = 8; + } + else if( PSMT_IS16BIT(itbest->psm) ) { + targchannels = 2; + } + if( targchannels == channels ) + break; + } + ++itbest; + } + + if( itbest != listClearedTargets.end()) { + listTargets.splice(listTargets.end(), listClearedTargets, itbest); + targ = &listTargets.back(); + targ->validatecount = 0; + } + else { + // create a new + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + } + else { + listTargets.push_back(CMemoryTarget()); + targ = &listTargets.back(); + } + + // fill local clut + if( PSMT_ISCLUT(tex0.psm) ) { + assert( clutsize > 0 ); + targ->cpsm = tex0.cpsm; + targ->clut.reserve(256*4); // no matter what + targ->clut.resize(clutsize); + + if( tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(&targ->clut[0], g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)&targ->clut[0]; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + } + + if( targ->ptex != NULL ) { + + assert( end-start <= targ->realheight && targ->fmt == fmt && targ->widthmult == widthmult ); + // good enough, so init + targ->realy = targ->starty = start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->height = end-start; + } + + if( targ->ptex == NULL ) { + + // not initialized yet + targ->fmt = fmt; + targ->realy = targ->starty = start; + targ->realheight = targ->height = end-start; + targ->usedstamp = curstamp; + targ->psm = tex0.psm; + targ->cpsm = tex0.cpsm; + targ->widthmult = widthmult; + targ->channels = channels; + + // alloc the mem + targ->ptex = new CMemoryTarget::TEXTURE(); + targ->ptex->ref = 1; + } + +#ifndef RELEASE_TO_PUBLIC + g_TransferredToGPU += GPU_TEXWIDTH * channels * 4 * targ->height; +#endif + + // fill with data + if( targ->ptex->memptr == NULL ) { + targ->ptex->memptr = (u8*)_aligned_malloc(4 * GPU_TEXWIDTH * targ->realheight, 16); + assert(targ->ptex->ref > 0 ); + } + + memcpy_amd(targ->ptex->memptr, g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy, 4 * GPU_TEXWIDTH * targ->height); + vector texdata; + u8* ptexdata = NULL; + + if( PSMT_ISCLUT(tex0.psm) ) { + + texdata.resize( (tex0.cpsm <= 1?4:2) *GPU_TEXWIDTH*channels*widthmult*(targ->realheight+widthmult-1)/widthmult); + ptexdata = &texdata[0]; + + u8* psrc = (u8*)(g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + if( tex0.cpsm <= 1 ) { // 32bit + u32* pclut = (u32*)&targ->clut[0]; + u32* pdst = (u32*)ptexdata; + + BUILDCLUT(); + } + else { + u16* pclut = (u16*)&targ->clut[0]; + u16* pdst = (u16*)ptexdata; + + BUILDCLUT(); + } + } + else { + if( tex0.psm == PSMT16Z || tex0.psm == PSMT16SZ ) { + + texdata.resize(4*GPU_TEXWIDTH*channels*widthmult*(targ->realheight+widthmult-1)/widthmult); + ptexdata = &texdata[0]; + // needs to be 8 bit, use xmm for unpacking + u16* dst = (u16*)ptexdata; + u16* src = (u16*)(g_pbyGSMemory + 4 * GPU_TEXWIDTH * targ->realy); + + assert( ((u32)(uptr)dst)%16 == 0 ); + +#if defined(ZEROGS_SSE2) + int iters = targ->height*GPU_TEXWIDTH/16; + +#if defined(_MSC_VER) + +#if defined(__x86_64__) + UnswizzleZ16Target(dst, src, iters); +#else + __asm { + mov edx, iters + pxor xmm7, xmm7 + mov eax, dst + mov ecx, src + +Z16Loop: + // unpack 64 bytes at a time + movdqa xmm0, [ecx] + movdqa xmm2, [ecx+16] + movdqa xmm4, [ecx+32] + movdqa xmm6, [ecx+48] + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm5, xmm4 + + punpcklwd xmm0, xmm7 + punpckhwd xmm1, xmm7 + punpcklwd xmm2, xmm7 + punpckhwd xmm3, xmm7 + + // start saving + movdqa [eax], xmm0 + movdqa [eax+16], xmm1 + + punpcklwd xmm4, xmm7 + punpckhwd xmm5, xmm7 + + movdqa [eax+32], xmm2 + movdqa [eax+48], xmm3 + + movdqa xmm0, xmm6 + punpcklwd xmm6, xmm7 + + movdqa [eax+64], xmm4 + movdqa [eax+80], xmm5 + + punpckhwd xmm0, xmm7 + + movdqa [eax+96], xmm6 + movdqa [eax+112], xmm0 + + add ecx, 64 + add eax, 128 + sub edx, 1 + jne Z16Loop + } +#endif // __x86_64__ +#else // _MSC_VER + + __asm__(".intel_syntax\n" + "pxor %%xmm7, %%xmm7\n" + + "Z16Loop:\n" + // unpack 64 bytes at a time + "movdqa %%xmm0, [%0]\n" + "movdqa %%xmm2, [%0+16]\n" + "movdqa %%xmm4, [%0+32]\n" + "movdqa %%xmm6, [%0+48]\n" + + "movdqa %%xmm1, %%xmm0\n" + "movdqa %%xmm3, %%xmm2\n" + "movdqa %%xmm5, %%xmm4\n" + + "punpcklwd %%xmm0, %%xmm7\n" + "punpckhwd %%xmm1, %%xmm7\n" + "punpcklwd %%xmm2, %%xmm7\n" + "punpckhwd %%xmm3, %%xmm7\n" + + // start saving + "movdqa [%1], %%xmm0\n" + "movdqa [%1+16], %%xmm1\n" + + "punpcklwd %%xmm4, %%xmm7\n" + "punpckhwd %%xmm5, %%xmm7\n" + + "movdqa [%1+32], %%xmm2\n" + "movdqa [%1+48], %%xmm3\n" + + "movdqa %%xmm0, %%xmm6\n" + "punpcklwd %%xmm6, %%xmm7\n" + + "movdqa [%1+64], %%xmm4\n" + "movdqa [%1+80], %%xmm5\n" + + "punpckhwd %%xmm0, %%xmm7\n" + + "movdqa [%1+96], %%xmm6\n" + "movdqa [%1+112], %%xmm0\n" + + "add %0, 64\n" + "add %1, 128\n" + "sub %2, 1\n" + "jne Z16Loop\n" + ".att_syntax\n" : "=r"(src), "=r"(dst), "=r"(iters) : "0"(src), "1"(dst), "2"(iters)); + +#endif // _MSC_VER +#else // ZEROGS_SSE2 + for(int i = 0; i < targ->height; ++i) { + for(int j = 0; j < GPU_TEXWIDTH; ++j) { + dst[0] = src[0]; dst[1] = 0; + dst[2] = src[1]; dst[3] = 0; + dst += 4; + src += 2; + } + } +#endif // ZEROGS_SSE2 + } + else { + ptexdata = targ->ptex->memptr; + } + } + + // create the texture + GL_REPORT_ERRORD(); + assert(ptexdata != NULL); + if( targ->ptex->tex == 0 ) + glGenTextures(1, &targ->ptex->tex); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, targ->ptex->tex); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, fmt==GL_UNSIGNED_BYTE?4:GL_RGB5_A1, GPU_TEXWIDTH*channels*widthmult, + (targ->realheight+widthmult-1)/widthmult, 0, GL_RGBA, fmt, ptexdata); + + int realheight = targ->realheight; + while( glGetError() != GL_NO_ERROR ) { + + // release resources until can create + if( listClearedTargets.size() > 0 ) + listClearedTargets.pop_front(); + else { + if( listTargets.size() == 0 ) { + ERROR_LOG("Failed to create %dx%x texture\n", GPU_TEXWIDTH*channels*widthmult, (realheight+widthmult-1)/widthmult); + channels = 1; + return NULL; + } + DestroyOldest(); + } + + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, GPU_TEXWIDTH*channels*widthmult, (targ->realheight+widthmult-1)/widthmult, 0, GL_RGBA, fmt, ptexdata); + } + + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_T, GL_CLAMP); + + assert( tex0.psm != 0xd ); + if( PSMT_ISCLUT(tex0.psm) ) + assert( targ->clut.size() > 0 ); + + return targ; +} + +void ZeroGS::CMemoryTargetMngr::ClearRange(int nbStartY, int nbEndY) +{ + int starty = nbStartY / (4*GPU_TEXWIDTH); + int endy = (nbEndY+4*GPU_TEXWIDTH-1) / (4*GPU_TEXWIDTH); + //int endy = (nbEndY+4096-1) / 4096; + + //if( listTargets.size() < TARGET_THRESH ) { + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + + if( it->starty < endy && (it->starty+it->height) > starty ) { + + // intersects, reduce valid texture mem (or totally delete texture) + // there are 4 cases + int miny = max(it->starty, starty); + int maxy = min(it->starty+it->height, endy); + assert(miny < maxy); + + if( it->clearmaxy == 0 ) { + it->clearminy = miny; + it->clearmaxy = maxy; + } + else { + if( it->clearminy > miny ) it->clearminy = miny; + if( it->clearmaxy < maxy ) it->clearmaxy = maxy; + } + } + + ++it; + } +// } +// else { +// for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { +// +// if( it->starty < endy && (it->starty+it->height) > starty ) { +// int newstarty = 0; +// if( starty <= it->starty ) { +// if( endy < it->starty + it->height) { +// // preserve end +// it->height = it->starty+it->height-endy; +// it->starty = endy; +// assert(it->height > 0); +// } +// else { +// // destroy +// it->height = 0; +// } +// } +// else { +// // beginning can be preserved +// it->height = starty-it->starty; +// } +// +// assert( it->starty >= it->realy && it->starty+it->height<=it->realy+it->realheight ); +// if( it->height <= 0 ) { +// list::iterator itprev = it; ++it; +// listClearedTargets.splice(listClearedTargets.end(), listTargets, itprev); +// continue; +// } +// } +// +// ++it; +// } +// } +} + +void ZeroGS::CMemoryTargetMngr::DestroyCleared() +{ + for(list::iterator it = listClearedTargets.begin(); it != listClearedTargets.end(); ) { + if( it->usedstamp < curstamp - 2 ) { + it = listClearedTargets.erase(it); + continue; + } + + ++it; + } + + if( (curstamp % 3) == 0 ) { + // purge old targets every 3 frames + for(list::iterator it = listTargets.begin(); it != listTargets.end(); ) { + if( it->usedstamp < curstamp - 3 ) { + it = listTargets.erase(it); + continue; + } + + ++it; + } + } + + ++curstamp; +} + +void ZeroGS::CMemoryTargetMngr::DestroyOldest() +{ + if( listTargets.size() == 0 ) + return; + + list::iterator it, itbest; + it = itbest = listTargets.begin(); + + while(it != listTargets.end()) { + if( it->usedstamp < itbest->usedstamp ) + itbest = it; + ++it; + } + + listTargets.erase(itbest); +} + +////////////////////////////////////// +// Texture Mngr For Bitwise AND Ops // +////////////////////////////////////// +void ZeroGS::CBitwiseTextureMngr::Destroy() +{ + for(map::iterator it = mapTextures.begin(); it != mapTextures.end(); ++it) + glDeleteTextures(1, &it->second); + mapTextures.clear(); +} + +u32 ZeroGS::CBitwiseTextureMngr::GetTexInt(u32 bitvalue, u32 ptexDoNotDelete) +{ + if( mapTextures.size() > 32 ) { + // randomly delete 8 + for(map::iterator it = mapTextures.begin(); it != mapTextures.end();) { + if( !(rand()&3) && it->second != ptexDoNotDelete) { + glDeleteTextures(1, &it->second); + mapTextures.erase(it++); + } + else ++it; + } + } + + // create a new tex + u32 ptex; + glGenTextures(1, &ptex); + + vector data(GPU_TEXMASKWIDTH); + for(u32 i = 0; i < GPU_TEXMASKWIDTH; ++i) + data[i] = ((i&bitvalue)<<6)|0x1f; // add the 1/2 offset so that + + glBindTexture(GL_TEXTURE_2D, ptex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, GPU_TEXMASKWIDTH, 1, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, &data[0]); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + if( glGetError() != GL_NO_ERROR ) { + ERROR_LOG("Failed to create bitmask texture\n"); + return 0; + } + + mapTextures[bitvalue] = ptex; + return ptex; +} + +void ZeroGS::CRangeManager::Insert(int start, int end) +{ + int imin = 0, imax = (int)ranges.size(), imid; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + switch( ranges.size() ) { + case 0: + ranges.push_back(RANGE(start, end)); + return; + + case 1: + if( end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + } + else if( start > ranges.front().end ) { + ranges.push_back(RANGE(start, end)); + } + else { + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + } + + return; + } + + // find where start is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end >= start && (imid == 0 || ranges[imid-1].end < start) ) { + imin = imid; + break; + } + else if( ranges[imid].start > start ) imax = imid; + else imin = imid+1; + } + + int startindex = imin; + + if( startindex >= (int)ranges.size() ) { + // non intersecting + assert( start > ranges.back().end ); + ranges.push_back(RANGE(start, end)); + return; + } + if( startindex == 0 && end < ranges.front().start ) { + ranges.insert(ranges.begin(), RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + imin = 0; imax = (int)ranges.size(); + + // find where end is + while(imin < imax) { + imid = (imin+imax)>>1; + + assert( imid < (int)ranges.size() ); + + if( ranges[imid].end <= end && (imid == ranges.size()-1 || ranges[imid+1].start > end ) ) { + imin = imid; + break; + } + else if( ranges[imid].start >= end ) imax = imid; + else imin = imid+1; + } + + int endindex = imin; + + if( startindex > endindex ) { + // create a new range + ranges.insert(ranges.begin()+startindex, RANGE(start, end)); + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + return; + } + + if( endindex >= (int)ranges.size()-1 ) { + // pop until startindex is reached + int lastend = ranges.back().end; + int numpop = (int)ranges.size() - startindex - 1; + while(numpop-- > 0 ) ranges.pop_back(); + + assert( start <= ranges.back().end ); + if( start < ranges.back().start ) ranges.back().start = start; + if( lastend > ranges.back().end ) ranges.back().end = lastend; + if( end > ranges.back().end ) ranges.back().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + + return; + } + + if( endindex == 0 ) { + assert( end >= ranges.front().start ); + if( start < ranges.front().start ) ranges.front().start = start; + if( end > ranges.front().end ) ranges.front().end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif + } + + // somewhere in the middle + if( ranges[startindex].start < start ) start = ranges[startindex].start; + + if( startindex < endindex ) { + ranges.erase(ranges.begin() + startindex, ranges.begin() + endindex ); + } + + if( start < ranges[startindex].start ) ranges[startindex].start = start; + if( end > ranges[startindex].end ) ranges[startindex].end = end; + +#ifdef _DEBUG + // sanity check + for(int i = 0; i < (int)ranges.size()-1; ++i) assert( ranges[i].end < ranges[i+1].start ); +#endif +} + +namespace ZeroGS { + +CRangeManager s_RangeMngr; // manages overwritten memory +static int gs_imageEnd = 0; + +void ResolveInRange(int start, int end) +{ + list listTargs; + s_DepthRTs.GetTargs(start, end, listTargs); + s_RTs.GetTargs(start, end, listTargs); + + if( listTargs.size() > 0 ) { + Flush(0); + Flush(1); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + // only resolve if not completely covered + (*it)->Resolve(); + } + } +} + +////////////////// +// Transferring // +////////////////// +void FlushTransferRanges(const tex0Info* ptex) +{ + assert( s_RangeMngr.ranges.size() > 0 ); + bool bHasFlushed = false; + list listTransmissionUpdateTargs; + + int texstart = -1, texend = -1; + if( ptex != NULL ) { + GetRectMemAddress(texstart, texend, ptex->psm, 0, 0, ptex->tw, ptex->th, ptex->tbp0, ptex->tbw); + } + + for(vector::iterator itrange = s_RangeMngr.ranges.begin(); itrange != s_RangeMngr.ranges.end(); ++itrange ) { + + int start = itrange->start; + int end = itrange->end; + + listTransmissionUpdateTargs.clear(); + s_DepthRTs.GetTargs(start, end, listTransmissionUpdateTargs); + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + +// if( !bHasFlushed && listTransmissionUpdateTargs.size() > 0 ) { +// Flush(0); +// Flush(1); +// +//#ifdef _DEBUG +// // make sure targets are still the same +// list::iterator it; +// FORIT(it, listTransmissionUpdateTargs) { +// CRenderTargetMngr::MAPTARGETS::iterator itmap; +// for(itmap = s_RTs.mapTargets.begin(); itmap != s_RTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// if( itmap == s_RTs.mapTargets.end() ) { +// +// for(itmap = s_DepthRTs.mapTargets.begin(); itmap != s_DepthRTs.mapTargets.end(); ++itmap) { +// if( itmap->second == *it ) +// break; +// } +// +// assert( itmap != s_DepthRTs.mapTargets.end() ); +// } +// } +//#endif +// } + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) ) + continue; + + if( !(ptarg->start < texend && ptarg->end > texstart) ) { + // chekc if target is currently being used + + if( !(g_GameSettings & GAME_NOQUICKRESOLVE) ) { + if( ptarg->fbp != vb[0].gsfb.fbp ) {//&& (vb[0].prndr == NULL || ptarg->fbp != vb[0].prndr->fbp) ) { + + if( ptarg->fbp != vb[1].gsfb.fbp ) { //&& (vb[1].prndr == NULL || ptarg->fbp != vb[1].prndr->fbp) ) { + // this render target currently isn't used and is not in the texture's way, so can safely ignore + // resolving it. Also the range has to be big enough compared to the target to really call it resolved + // (ffx changing screens, shadowhearts) + // start == ptarg->start, used for kh to transfer text + if( ptarg->IsDepth() || end-start > 0x50000 || ((g_GameSettings&GAME_QUICKRESOLVE1)&&start == ptarg->start) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate|CRenderTarget::TS_Resolved; + + continue; + } + } + } + } + else { +// if( start <= texstart && end >= texend ) { +// // texture taken care of so can skip!? +// continue; +// } + } + + // the first range check was very rough; some games (dragonball z) have the zbuf in the same page as textures (but not overlapping) + // so detect that condition + if( ptarg->fbh % m_Blocks[ptarg->psm].height ) { + + // get start of left-most boundry page + int targstart, targend; + ZeroGS::GetRectMemAddress(targstart, targend, ptarg->psm, 0, 0, ptarg->fbw, ptarg->fbh & ~(m_Blocks[ptarg->psm].height-1), ptarg->fbp, ptarg->fbw); + + if( start >= targend ) { + + // don't bother + if( (ptarg->fbh % m_Blocks[ptarg->psm].height) <= 2 ) + continue; + + // calc how many bytes of the block that the page spans + } + } + + if( !(ptarg->status & CRenderTarget::TS_Virtual) ) { + + if( start < ptarg->end && end > ptarg->start ) { + + // suikoden5 is faster with check, but too big of a value and kh screens mess up + if( end - start > 0x8000 ) { + // intersects, do only one sided resolves + if( end-start > 4*ptarg->fbw ) { // at least it be greater than one scanline (spiro is faster) + if( start > ptarg->start ) { + ptarg->Resolve(ptarg->start, start); + } + else if( end < ptarg->end ) { + ptarg->Resolve(end, ptarg->end); + } + } + } + + ptarg->status |= CRenderTarget::TS_Resolved; + if( !ptarg->IsDepth() || (!(g_GameSettings & GAME_NODEPTHUPDATE) || end-start > 0x1000) ) + ptarg->status |= CRenderTarget::TS_NeedUpdate; + } + } + } + + ZeroGS::g_MemTargs.ClearRange(start, end); + } + + s_RangeMngr.Clear(); +} + +static vector s_vTempBuffer, s_vTransferCache; + +void InitTransferHostLocal() +{ + if( g_bIsLost ) + return; + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + bool bHasFlushed = false; + + gs.imageX = gs.trxpos.dx; + gs.imageY = gs.trxpos.dy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + + assert( gs.imageEndX < 2048 && gs.imageEndY < 2048 ); + + // hack! viewful joe + if( gs.dstbuf.psm == 63 ) + gs.dstbuf.psm = 0; + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + if( end > 0x00400000 ) { + WARN_LOG("host local out of bounds!\n"); + //gs.imageTransfer = -1; + end = 0x00400000; + } + + gs_imageEnd = end; + + if( vb[0].nCount > 0 ) + Flush(0); + if( vb[1].nCount > 0 ) + Flush(1); + + //PRIM_LOG("trans: bp:%x x:%x y:%x w:%x h:%x\n", gs.dstbuf.bp, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew); + +// if( !bHasFlushed && (vb[0].bNeedFrameCheck || vb[0].bNeedZCheck || vb[1].bNeedFrameCheck || vb[1].bNeedZCheck)) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// +// // for all ranges, flush the targets +// // check if new rect intersects with current rendering texture, if so, flush +// if( vb[0].nCount > 0 && vb[0].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[0].tex0.psm, 0, 0, vb[0].tex0.tw, vb[0].tex0.th, vb[0].tex0.tbp0, vb[0].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } +// +// if( !bHasFlushed && vb[1].nCount > 0 && vb[1].curprim.tme ) { +// int tstart, tend; +// GetRectMemAddress(tstart, tend, vb[1].tex0.psm, 0, 0, vb[1].tex0.tw, vb[1].tex0.th, vb[1].tex0.tbp0, vb[1].tex0.tbw); +// +// if( start < tend && end > tstart ) { +// Flush(0); +// Flush(1); +// bHasFlushed = 1; +// } +// } + + //ZeroGS::g_MemTargs.ClearRange(start, end); + //s_RangeMngr.Insert(start, end); +} + +void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +{ + if( g_bIsLost ) + return; + + DVProfileFunc _pf("TransferHostLocal"); + + int start, end; + GetRectMemAddress(start, end, gs.dstbuf.psm, gs.imageX, gs.imageY, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + assert( start < gs_imageEnd ); + + end = gs_imageEnd; + + // sometimes games can decompress to alpha channel of render target only, in this case + // do a resolve right away. wolverine x2 + if( gs.dstbuf.psm == PSMT8H || gs.dstbuf.psm == PSMT4HL || gs.dstbuf.psm == PSMT4HH ) { + list listTransmissionUpdateTargs; + s_RTs.GetTargs(start, end, listTransmissionUpdateTargs); + + for(list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it) { + + CRenderTarget* ptarg = *it; + + if( (ptarg->status & CRenderTarget::TS_Virtual) ) + continue; + + //ERROR_LOG("resolving to alpha channel\n"); + ptarg->Resolve(); + } + } + + s_RangeMngr.Insert(start, min(end, start+(int)nQWordSize*16)); + + const u8* porgend = (const u8*)pbyMem + 4 * nQWordSize; + + if( s_vTransferCache.size() > 0 ) { + + int imagecache = s_vTransferCache.size(); + s_vTempBuffer.resize(imagecache + nQWordSize*4); + memcpy(&s_vTempBuffer[0], &s_vTransferCache[0], imagecache); + memcpy(&s_vTempBuffer[imagecache], pbyMem, nQWordSize*4); + + pbyMem = (const void*)&s_vTempBuffer[0]; + porgend = &s_vTempBuffer[0]+s_vTempBuffer.size(); + + int wordinc = imagecache / 4; + if( (nQWordSize * 4 + imagecache)/3 == ((nQWordSize+wordinc) * 4) / 3 ) { + // can use the data + nQWordSize += wordinc; + } + } + + int leftover = m_Blocks[gs.dstbuf.psm].TransferHostLocal(pbyMem, nQWordSize); + + if( leftover > 0 ) { + // copy the last gs.image24bitOffset to the cache + s_vTransferCache.resize(leftover); + memcpy(&s_vTransferCache[0], porgend - leftover, leftover); + } + else s_vTransferCache.resize(0); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +// left/right, top/down +//void TransferHostLocal(const void* pbyMem, u32 nQWordSize) +//{ +// assert( gs.imageTransfer == 0 ); +// u8* pstart = g_pbyGSMemory + gs.dstbuf.bp*256; +// +// const u8* pendbuf = (const u8*)pbyMem + nQWordSize*4; +// int i = gs.imageY, j = gs.imageX; +// +//#define DSTPSM gs.dstbuf.psm +// +//#define TRANSFERHOSTLOCAL(psm, T, widthlimit) { \ +// const T* pbuf = (const T*)pbyMem; \ +// u32 nSize = nQWordSize*(4/sizeof(T)); \ +// assert( (nSize%widthlimit) == 0 && widthlimit <= 4 ); \ +// if( ((gs.imageEndX-gs.trxpos.dx)%widthlimit) ) ERROR_LOG("Bad Transmission! %d %d, psm: %d\n", gs.trxpos.dx, gs.imageEndX, DSTPSM); \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += widthlimit, nSize -= widthlimit, pbuf += widthlimit) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, pbuf[0], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 1 ) { \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, pbuf[1], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 2 ) { \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, pbuf[2], gs.dstbuf.bw); \ +// \ +// if( widthlimit > 3 ) { \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, pbuf[3], gs.dstbuf.bw); \ +// } \ +// } \ +// } \ +// } \ +// \ +// if( j >= gs.imageEndX ) { assert(j == gs.imageEndX); j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +//#define TRANSFERHOSTLOCAL_4(psm) { \ +// const u8* pbuf = (const u8*)pbyMem; \ +// u32 nSize = nQWordSize*8; \ +// for(; i < gs.imageEndY; ++i) { \ +// for(; j < gs.imageEndX && nSize > 0; j += 8, nSize -= 8) { \ +// /* write as many pixel at one time as possible */ \ +// writePixel##psm##_0(pstart, j%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+1)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+2)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+3)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+4)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+5)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// writePixel##psm##_0(pstart, (j+6)%2048, i%2048, *pbuf&0x0f, gs.dstbuf.bw); \ +// writePixel##psm##_0(pstart, (j+7)%2048, i%2048, *pbuf>>4, gs.dstbuf.bw); \ +// pbuf++; \ +// } \ +// \ +// if( j >= gs.imageEndX ) { /*assert(j == gs.imageEndX);*/ j = gs.trxpos.dx; } \ +// else { assert( nSize == 0 ); goto End; } \ +// } \ +//} \ +// +// switch (gs.dstbuf.psm) { +// case 0x0: TRANSFERHOSTLOCAL(32, u32, 2); break; +// case 0x1: TRANSFERHOSTLOCAL(24, u32, 4); break; +// case 0x2: TRANSFERHOSTLOCAL(16, u16, 4); break; +// case 0xA: TRANSFERHOSTLOCAL(16S, u16, 4); break; +// case 0x13: +// if( ((gs.imageEndX-gs.trxpos.dx)%4) ) { +// TRANSFERHOSTLOCAL(8, u8, 1); +// } +// else { +// TRANSFERHOSTLOCAL(8, u8, 4); +// } +// break; +// +// case 0x14: +//// if( (gs.imageEndX-gs.trxpos.dx)%8 ) { +//// // hack +//// if( abs((int)nQWordSize*8 - (gs.imageEndY-i)*(gs.imageEndX-gs.trxpos.dx)+(j-gs.trxpos.dx)) <= 8 ) { +//// // don't transfer +//// ERROR_LOG("bad texture 4: %d %d %d\n", gs.trxpos.dx, gs.imageEndX, nQWordSize); +//// gs.imageEndX = gs.trxpos.dx + (gs.imageEndX-gs.trxpos.dx)&~7; +//// //i = gs.imageEndY; +//// //goto End; +//// gs.imageTransfer = -1; +//// } +//// } +// TRANSFERHOSTLOCAL_4(4); +// break; +// case 0x1B: TRANSFERHOSTLOCAL(8H, u8, 4); break; +// case 0x24: TRANSFERHOSTLOCAL_4(4HL); break; +// case 0x2C: TRANSFERHOSTLOCAL_4(4HH); break; +// case 0x30: TRANSFERHOSTLOCAL(32Z, u32, 2); break; +// case 0x31: TRANSFERHOSTLOCAL(24Z, u32, 4); break; +// case 0x32: TRANSFERHOSTLOCAL(16Z, u16, 4); break; +// case 0x3A: TRANSFERHOSTLOCAL(16SZ, u16, 4); break; +// } +// +//End: +// if( i >= gs.imageEndY ) { +// assert( i == gs.imageEndY ); +// gs.imageTransfer = -1; +// +// if( g_bSaveTrans ) { +// tex0Info t; +// t.tbp0 = gs.dstbuf.bp; +// t.tw = gs.imageWnew; +// t.th = gs.imageHnew; +// t.tbw = gs.dstbuf.bw; +// t.psm = gs.dstbuf.psm; +// SaveTex(&t, 0); +// } +// } +// else { +// /* update new params */ +// gs.imageY = i; +// gs.imageX = j; +// } +//} + +void InitTransferLocalHost() +{ + assert( gs.trxpos.sx+gs.imageWnew <= 2048 && gs.trxpos.sy+gs.imageHnew <= 2048 ); + +#ifndef RELEASE_TO_PUBLIC + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, width exceeds\n"); +#endif + + gs.imageX = gs.trxpos.sx; + gs.imageY = gs.trxpos.sy; + gs.imageEndX = gs.imageX + gs.imageWnew; + gs.imageEndY = gs.imageY + gs.imageHnew; + s_vTransferCache.resize(0); + + int start, end; + GetRectMemAddress(start, end, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + ResolveInRange(start, end); +} + +// left/right, top/down +void TransferLocalHost(void* pbyMem, u32 nQWordSize) +{ + assert( gs.imageTransfer == 1 ); + + u8* pstart = g_pbyGSMemory + 256*gs.srcbuf.bp; + int i = gs.imageY, j = gs.imageX; + +#define TRANSFERLOCALHOST(psm, T) { \ + T* pbuf = (T*)pbyMem; \ + u32 nSize = nQWordSize*16/sizeof(T); \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + *pbuf++ = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + +#define TRANSFERLOCALHOST_24(psm) { \ + u8* pbuf = (u8*)pbyMem; \ + u32 nSize = nQWordSize*16/3; \ + for(; i < gs.imageEndY; ++i) { \ + for(; j < gs.imageEndX && nSize > 0; ++j, --nSize) { \ + u32 p = readPixel##psm##_0(pstart, j%2048, i%2048, gs.srcbuf.bw); \ + pbuf[0] = (u8)p; \ + pbuf[1] = (u8)(p>>8); \ + pbuf[2] = (u8)(p>>16); \ + pbuf += 3; \ + } \ + \ + if( j >= gs.imageEndX ) { assert( j == gs.imageEndX); j = gs.trxpos.sx; } \ + else { assert( nSize == 0 ); break; } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case 0x0: TRANSFERLOCALHOST(32, u32); break; + case 0x1: TRANSFERLOCALHOST_24(24); break; + case 0x2: TRANSFERLOCALHOST(16, u16); break; + case 0xA: TRANSFERLOCALHOST(16S, u16); break; + case 0x13: TRANSFERLOCALHOST(8, u8); break; + case 0x1B: TRANSFERLOCALHOST(8H, u8); break; + case 0x30: TRANSFERLOCALHOST(32Z, u32); break; + case 0x31: TRANSFERLOCALHOST_24(24Z); break; + case 0x32: TRANSFERLOCALHOST(16Z, u16); break; + case 0x3A: TRANSFERLOCALHOST(16SZ, u16); break; + default: assert(0); + } + + gs.imageY = i; + gs.imageX = j; + + if( gs.imageY >= gs.imageEndY ) { + assert( gs.imageY == gs.imageEndY ); + gs.imageTransfer = -1; + } +} + +// dir depends on trxpos.dir +void TransferLocalLocal() +{ + assert( gs.imageTransfer == 2 ); + assert( gs.trxpos.sx+gs.imageWnew < 2048 && gs.trxpos.sy+gs.imageHnew < 2048 ); + assert( gs.trxpos.dx+gs.imageWnew < 2048 && gs.trxpos.dy+gs.imageHnew < 2048 ); + assert( (gs.srcbuf.psm&0x7) == (gs.dstbuf.psm&0x7) ); + if( gs.trxpos.sx+gs.imageWnew > gs.srcbuf.bw ) + WARN_LOG("Transfer error, src width exceeds\n"); + if( gs.trxpos.dx+gs.imageWnew > gs.dstbuf.bw ) + WARN_LOG("Transfer error, dst width exceeds\n"); + + int srcstart, srcend, dststart, dstend; + + GetRectMemAddress(srcstart, srcend, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw); + GetRectMemAddress(dststart, dstend, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw); + + // resolve the targs + ResolveInRange(srcstart, srcend); + + list listTargs; + s_RTs.GetTargs(dststart, dstend, listTargs); + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) { + if( !((*it)->status & CRenderTarget::TS_Virtual) ) { + (*it)->Resolve(); + (*it)->status |= CRenderTarget::TS_NeedUpdate; + } + } + + u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp*256; + u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp*256; + +#define TRANSFERLOCALLOCAL(srcpsm, dstpsm, widthlimit) { \ + assert( (gs.imageWnew&widthlimit)==0 && widthlimit <= 4); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; i++, i2++) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=widthlimit, j2+=widthlimit) { \ + \ + writePixel##dstpsm##_0(pDstBuf, j2%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, j%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 1 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+1)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+1)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 2 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+2)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+2)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + \ + if( widthlimit > 3 ) { \ + writePixel##dstpsm##_0(pDstBuf, (j2+3)%2048, i2%2048, \ + readPixel##srcpsm##_0(pSrcBuf, (j+3)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw); \ + } \ + } \ + } \ + } \ + } \ +} \ + +#define TRANSFERLOCALLOCAL_4(srcpsm, dstpsm) { \ + assert( (gs.imageWnew%8) == 0 ); \ + for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < gs.trxpos.sy+gs.imageHnew; ++i, ++i2) { \ + for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < gs.trxpos.sx+gs.imageWnew; j+=8, j2+=8) { \ + /* NOTE: the 2 conseq 4bit values are in NOT in the same byte */ \ + u32 read = getPixelAddress##srcpsm##_0(j%2048, i%2048, gs.srcbuf.bw); \ + u32 write = getPixelAddress##dstpsm##_0(j2%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+1)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+1)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + \ + read = getPixelAddress##srcpsm##_0((j+2)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+2)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f); \ + \ + read = getPixelAddress##srcpsm##_0((j+3)%2048, i%2048, gs.srcbuf.bw); \ + write = getPixelAddress##dstpsm##_0((j2+3)%2048, i2%2048, gs.dstbuf.bw); \ + pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0); \ + } \ + } \ +} \ + + switch (gs.srcbuf.psm) { + case PSMCT32: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32, 32Z, 2); + } + break; + + case PSMCT24: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24, 24Z, 4); + } + break; + + case PSMCT16: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16, 16SZ, 4); break; + } + break; + + case PSMCT16S: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16S, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16S, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16S, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16S, 16SZ, 4); break; + } + break; + + case PSMT8: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8, 8H, 4); + } + break; + + case PSMT4: + + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4, 4HH); break; + } + break; + + case PSMT8H: + if( gs.dstbuf.psm == PSMT8 ) { + TRANSFERLOCALLOCAL(8H, 8, 4); + } + else { + TRANSFERLOCALLOCAL(8H, 8H, 4); + } + break; + + case PSMT4HL: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HL, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HL, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HL, 4HH); break; + } + break; + case PSMT4HH: + switch(gs.dstbuf.psm ) { + case PSMT4: TRANSFERLOCALLOCAL_4(4HH, 4); break; + case PSMT4HL: TRANSFERLOCALLOCAL_4(4HH, 4HL); break; + case PSMT4HH: TRANSFERLOCALLOCAL_4(4HH, 4HH); break; + } + break; + + case PSMT32Z: + if( gs.dstbuf.psm == PSMCT32 ) { + TRANSFERLOCALLOCAL(32Z, 32, 2); + } + else { + TRANSFERLOCALLOCAL(32Z, 32Z, 2); + } + break; + + case PSMT24Z: + if( gs.dstbuf.psm == PSMCT24 ) { + TRANSFERLOCALLOCAL(24Z, 24, 4); + } + else { + TRANSFERLOCALLOCAL(24Z, 24Z, 4); + } + break; + + case PSMT16Z: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16Z, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16Z, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16Z, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16Z, 16SZ, 4); break; + } + break; + + case PSMT16SZ: + switch(gs.dstbuf.psm) { + case PSMCT16: TRANSFERLOCALLOCAL(16SZ, 16, 4); break; + case PSMCT16S: TRANSFERLOCALLOCAL(16SZ, 16S, 4); break; + case PSMT16Z: TRANSFERLOCALLOCAL(16SZ, 16Z, 4); break; + case PSMT16SZ: TRANSFERLOCALLOCAL(16SZ, 16SZ, 4); break; + } + break; + } + + g_MemTargs.ClearRange(dststart, dstend); + +#if !defined(RELEASE_TO_PUBLIC) && defined(_DEBUG) + if( g_bSaveTrans ) { + tex0Info t; + t.tbp0 = gs.dstbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.dstbuf.bw; + t.psm = gs.dstbuf.psm; + SaveTex(&t, 0); + + t.tbp0 = gs.srcbuf.bp; + t.tw = gs.imageWnew; + t.th = gs.imageHnew; + t.tbw = gs.srcbuf.bw; + t.psm = gs.srcbuf.psm; + SaveTex(&t, 0); + } +#endif +} + +void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw) +{ + if( m_Blocks[psm].bpp == 0 ) { + ERROR_LOG("ZeroGS: Bad psm 0x%x\n", psm); + start = 0; + end = 0x00400000; + return; + } + + if( (psm&0x30) == 0x30 || psm == 0xa ) { + + const BLOCK& b = m_Blocks[psm]; + + bw = (bw + b.width -1)/b.width; + start = bp*256 + ((y/b.height) * bw + (x/b.width) )*0x2000; + end = bp*256 + (((y+h-1)/b.height) * bw + (x + w + b.width - 1)/b.width)*0x2000; + } + else { + // just take the addresses + switch(psm) { + case 0x00: + case 0x01: + case 0x1b: + case 0x24: + case 0x2c: + start = 4*getPixelAddress32(x, y, bp, bw); + end = 4*getPixelAddress32(x+w-1, y+h-1, bp, bw) + 4; + break; + case 0x02: + start = 2*getPixelAddress16(x, y, bp, bw); + end = 2*getPixelAddress16(x+w-1, y+h-1, bp, bw)+2; + break; + case 0x13: + start = getPixelAddress8(x, y, bp, bw); + end = getPixelAddress8(x+w-1, y+h-1, bp, bw)+1; + break; + case 0x14: + { + start = getPixelAddress4(x, y, bp, bw)/2; + int newx = ((x+w-1+31)&~31)-1; + int newy = ((y+h-1+15)&~15)-1; + end = (getPixelAddress4(max(newx,x), max(newy,y), bp, bw)+2)/2; + break; + } + } + } +} + +void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm) +{ + //assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); + s_nResolved += 2; + + // align the rect to the nearest page + // note that fbp is always aligned on page boundaries + int start, end; + GetRectMemAddress(start, end, psm, 0, 0, fbw, fbh, fbp, fbw); + + PRIM_LOG("resolve: %x %x %x (%x-%x)\n", fbp, fbw, fbh, start, end); + + int i, j; + short smask1 = gs.smask&1; + short smask2 = gs.smask&2; + u32 mask, imask; + + if( psm&2 ) { // 16 bit + // mask is shifted + imask = RGBA32to16(fbm); + mask = (~imask)&0xffff; + } + else { + mask = ~fbm; + imask = fbm; + + if( (psm&0xf)>0 ) { + // preserve the alpha? + mask &= 0x00ffffff; + imask |= 0xff000000; + } + } + int Pitch; + +#define RESOLVE_32BIT(psm, T, Tsrc, blockbits, blockwidth, blockheight, convfn, frame, aax, aay) \ + { \ + Tsrc* src = (Tsrc*)psrc; \ + T* pPageOffset = (T*)g_pbyGSMemory + fbp*(256/sizeof(T)), *dst; \ + int srcpitch = Pitch * blockheight/sizeof(Tsrc); \ + int maxfbh = (0x00400000-fbp*256) / (sizeof(T) * fbw); \ + if( maxfbh > fbh ) maxfbh = fbh; \ + for(i = 0; i < (maxfbh&~(blockheight-1)); i += blockheight) { \ + /*if( smask2 && (i&1) == smask1 ) continue; */ \ + for(j = 0; j < fbw; j += blockwidth) { \ + /* have to write in the tiled format*/ \ + frame##SwizzleBlock##blockbits(pPageOffset + getPixelAddress##psm##_0(j, i, fbw), \ + src+(j< psm + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, u32, 16A4, 16, 8, RGBA32to16, Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, u32, 16A2, 16, 8, RGBA32to16, Frame, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, u32, 16, 16, 8, RGBA32to16, Frame, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, u32, 32A4, 8, 8, (u32), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, u32, 32A2, 8, 8, (u32), Frame, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, u32, 32, 8, 8, (u32), Frame, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A4, 16, 8, (u16), Frame, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, u32, 16A2, 16, 8, (u16), Frame, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, u32, 16, 16, 8, (u16), Frame, 0, 0); + } + + break; + } + } + else { // float16 + + Pitch = fbw * 8; + + switch(psm) { + case PSMCT32: + case PSMCT24: + if( s_AAy ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A4, 8, 8, Float16ToARGB, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32, u32, Vector_16F, 32A2, 8, 8, Float16ToARGB, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32, u32, Vector_16F, 32, 8, 8, Float16ToARGB, Frame16, 0, 0); + } + + break; + case PSMCT16: + if( s_AAy ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMCT16S: + if( s_AAy ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A4, 16, 8, Float16ToARGB16, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16S, u16, Vector_16F, 16A2, 16, 8, Float16ToARGB16, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16S, u16, Vector_16F, 16, 16, 8, Float16ToARGB16, Frame16, 0, 0); + } + + break; + case PSMT32Z: + case PSMT24Z: + if( s_AAy ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA4, 8, 8, Float16ToARGB_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32ZA2, 8, 8, Float16ToARGB_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(32Z, u32, Vector_16F, 32Z, 8, 8, Float16ToARGB_Z, Frame16, 0, 0); + } + + break; + case PSMT16Z: + if( s_AAy ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16Z, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + case PSMT16SZ: + if( s_AAy ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA4, 16, 8, Float16ToARGB16_Z, Frame16, 1, 1); + } + else if( s_AAx ) { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16ZA2, 16, 8, Float16ToARGB16_Z, Frame16, 1, 0); + } + else { + RESOLVE_32BIT(16SZ, u16, Vector_16F, 16Z, 16, 8, Float16ToARGB16_Z, Frame16, 0, 0); + } + + break; + } + } + + g_MemTargs.ClearRange(start, end); + INC_RESOLVE(); +} + +//////////// +// Saving // +//////////// +void SaveTex(tex0Info* ptex, int usevid) +{ + vector data(ptex->tw*ptex->th); + vector srcdata; + + u32* dst = &data[0]; + u8* psrc = g_pbyGSMemory; + + CMemoryTarget* pmemtarg = NULL; + + if( usevid ) { + + pmemtarg = g_MemTargs.GetMemoryTarget(*ptex, 0); + assert( pmemtarg != NULL ); + + glBindTexture(GL_TEXTURE_RECTANGLE_NV, pmemtarg->ptex->tex); + srcdata.resize(pmemtarg->realheight*GPU_TEXWIDTH*pmemtarg->widthmult*4*8); // max of 8 cannels + + glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, pmemtarg->fmt, &srcdata[0]); + + u32 offset = pmemtarg->realy * 4 * GPU_TEXWIDTH; + if( ptex->psm == PSMT8 ) offset *= ptex->cpsm <= 1 ? 4 : 2; + else if( ptex->psm == PSMT4 ) offset *= ptex->cpsm <= 1 ? 8 : 4; + + psrc = &srcdata[0] - offset; + } + + for(int i = 0; i < ptex->th; ++i) { + for(int j = 0; j < ptex->tw; ++j) { + u32 u, addr; + switch(ptex->psm) { + case PSMCT32: + addr = getPixelAddress32(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel32(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT24: + addr = getPixelAddress24(j, i, ptex->tbp0, ptex->tbw); + + if( addr*4 < 0x00400000 ) + u = readPixel24(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + + break; + case PSMCT16: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + + break; + case PSMCT16S: + addr = getPixelAddress16(j, i, ptex->tbp0, ptex->tbw); + + if( addr*2 < 0x00400000 ) { + u = readPixel16S(psrc, j, i, ptex->tbp0, ptex->tbw); + u = RGBA16to32(u); + } + else u = 0; + break; + + case PSMT8: + addr = getPixelAddress8(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4: + addr = getPixelAddress4(j, i, ptex->tbp0, ptex->tbw); + + if( addr < 2*0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT8H: + addr = getPixelAddress8H(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel8H(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + + break; + + case PSMT4HL: + addr = getPixelAddress4HL(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HL(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT4HH: + addr = getPixelAddress4HH(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) { + if( usevid ) { + if( ptex->cpsm <= 1 ) u = *(u32*)(psrc+4*addr); + else u = RGBA16to32(*(u16*)(psrc+2*addr)); + } + else + u = readPixel4HH(psrc, j, i, ptex->tbp0, ptex->tbw); + } + else u = 0; + break; + + case PSMT32Z: + addr = getPixelAddress32Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel32Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT24Z: + addr = getPixelAddress24Z(j, i, ptex->tbp0, ptex->tbw); + + if( 4*addr < 0x00400000 ) + u = readPixel24Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16Z: + addr = getPixelAddress16Z(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16Z(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + case PSMT16SZ: + addr = getPixelAddress16SZ(j, i, ptex->tbp0, ptex->tbw); + + if( 2*addr < 0x00400000 ) + u = readPixel16SZ(psrc, j, i, ptex->tbp0, ptex->tbw); + else u = 0; + break; + + default: + assert(0); + } + + *dst++ = u; + } + } + + SaveTGA("tex.tga", ptex->tw, ptex->th, &data[0]); +} + +} diff --git a/plugins/zerogs/opengl/targets.h b/plugins/zerogs/opengl/targets.h new file mode 100644 index 0000000000..6c7bfdf6a1 --- /dev/null +++ b/plugins/zerogs/opengl/targets.h @@ -0,0 +1,160 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#define TARGET_VIRTUAL_KEY 0x80000000 + +namespace ZeroGS { + + // manages render targets + class CRenderTargetMngr + { + public: + typedef map MAPTARGETS; + + enum TargetOptions + { + TO_DepthBuffer = 1, + TO_StrictHeight = 2, // height returned has to be the same as requested + TO_Virtual = 4 + }; + + ~CRenderTargetMngr() { Destroy(); } + + void Destroy(); + static MAPTARGETS::iterator GetOldestTarg(MAPTARGETS& m); + + CRenderTarget* GetTarg(const frameInfo& frame, u32 Options, int maxposheight); + inline CRenderTarget* GetTarg(int fbp, int fbw) { + MAPTARGETS::iterator it = mapTargets.find(fbp|(fbw<<16)); + return it != mapTargets.end() ? it->second : NULL; + } + + // gets all targets with a range + void GetTargs(int start, int end, list& listTargets) const; + + // resolves all targets within a range + __forceinline void Resolve(int start, int end); + __forceinline void ResolveAll() { + for(MAPTARGETS::iterator it = mapTargets.begin(); it != mapTargets.end(); ++it ) + it->second->Resolve(); + } + + void DestroyAllTargs(int start, int end, int fbw); + void DestroyIntersecting(CRenderTarget* prndr); + + // promotes a target from virtual to real + inline CRenderTarget* Promote(u32 key) { + assert( !(key & TARGET_VIRTUAL_KEY) ); + + // promote to regular targ + CRenderTargetMngr::MAPTARGETS::iterator it = mapTargets.find(key|TARGET_VIRTUAL_KEY); + assert( it != mapTargets.end() ); + + CRenderTarget* ptarg = it->second; + mapTargets.erase(it); + + DestroyIntersecting(ptarg); + + it = mapTargets.find(key); + if( it != mapTargets.end() ) { + DestroyTarg(it->second); + it->second = ptarg; + } + else + mapTargets[key] = ptarg; + + if( g_GameSettings & GAME_RESOLVEPROMOTED ) + ptarg->status = CRenderTarget::TS_Resolved; + else + ptarg->status = CRenderTarget::TS_NeedUpdate; + return ptarg; + } + + static void DestroyTarg(CRenderTarget* ptarg); + + MAPTARGETS mapTargets, mapDummyTargs; + }; + + class CMemoryTargetMngr + { + public: + CMemoryTargetMngr() : curstamp(0) {} + CMemoryTarget* GetMemoryTarget(const tex0Info& tex0, int forcevalidate); // pcbp is pointer to start of clut + + void Destroy(); // destroy all targs + + void ClearRange(int starty, int endy); // set all targets to cleared + void DestroyCleared(); // flush all cleared targes + void DestroyOldest(); + + list listTargets, listClearedTargets; + u32 curstamp; + + private: + list::iterator DestroyTargetIter(list::iterator& it); + }; + + class CBitwiseTextureMngr + { + public: + ~CBitwiseTextureMngr() { Destroy(); } + + void Destroy(); + + // since GetTex can delete textures to free up mem, it is dangerous if using that texture, so specify at least one other tex to save + __forceinline u32 GetTex(u32 bitvalue, u32 ptexDoNotDelete) { + map::iterator it = mapTextures.find(bitvalue); + if( it != mapTextures.end() ) + return it->second; + return GetTexInt(bitvalue, ptexDoNotDelete); + } + + private: + u32 GetTexInt(u32 bitvalue, u32 ptexDoNotDelete); + + map mapTextures; + }; + + // manages + class CRangeManager + { + public: + CRangeManager() + { + ranges.reserve(16); + } + + // [start, end) + struct RANGE + { + RANGE() {} + inline RANGE(int start, int end) : start(start), end(end) {} + int start, end; + }; + + // works in semi logN + void Insert(int start, int end); + inline void Clear() { ranges.resize(0); } + + vector ranges; // organized in ascending order, non-intersecting + }; + + extern CRenderTargetMngr s_RTs, s_DepthRTs; + extern CBitwiseTextureMngr s_BitwiseTextures; + extern CMemoryTargetMngr g_MemTargs; +} diff --git a/plugins/zerogs/opengl/x86-32.S b/plugins/zerogs/opengl/x86-32.S new file mode 100644 index 0000000000..73b11f11d6 --- /dev/null +++ b/plugins/zerogs/opengl/x86-32.S @@ -0,0 +1,1002 @@ +# Copyright (C) 2005-2006 zerofrog(@gmail.com) +# +# 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 ve%rsion 2, or (at your option) +# any later ve%rsion. +# +# 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 GNU Make see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +# +# +.intel_syntax + +## mmx memcpy implementation, size has to be a multiple of 8 +## returns 0 is equal, nonzero value if not equal +## ~10 times faster than standard memcmp +## (zerofrog) +#u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +.globl memcmp_mmx + .type memcmp_mmx, @function +memcmp_mmx: + push %esi + mov %ecx, dword ptr [%esp+16] + mov %edx, dword ptr [%esp+8] + mov %esi, dword ptr [%esp+12] + + cmp %ecx, 32 + jl Done4 + + // custom test first 8 to make sure things are ok + movq %mm0, [%esi] + movq %mm1, [%esi+8] + pcmpeqd %mm0, [%edx] + pcmpeqd %mm1, [%edx+8] + pand %mm0, %mm1 + movq %mm2, [%esi+16] + pmovmskb %eax, %mm0 + movq %mm3, [%esi+24] + + // check if eq + cmp %eax, 0xff + je NextComp + mov %eax, 1 + jmp End + +NextComp: + pcmpeqd %mm2, [%edx+16] + pcmpeqd %mm3, [%edx+24] + pand %mm2, %mm3 + pmovmskb %eax, %mm2 + + sub %ecx, 32 + add %esi, 32 + add %edx, 32 + + // check if eq + cmp %eax, 0xff + je ContinueTest + mov %eax, 1 + jmp End + + cmp %ecx, 64 + jl Done8 + +Cmp8: + movq %mm0, [%esi] + movq %mm1, [%esi+8] + movq %mm2, [%esi+16] + movq %mm3, [%esi+24] + movq %mm4, [%esi+32] + movq %mm5, [%esi+40] + movq %mm6, [%esi+48] + movq %mm7, [%esi+56] + pcmpeqd %mm0, [%edx] + pcmpeqd %mm1, [%edx+8] + pcmpeqd %mm2, [%edx+16] + pcmpeqd %mm3, [%edx+24] + pand %mm0, %mm1 + pcmpeqd %mm4, [%edx+32] + pand %mm0, %mm2 + pcmpeqd %mm5, [%edx+40] + pand %mm0, %mm3 + pcmpeqd %mm6, [%edx+48] + pand %mm0, %mm4 + pcmpeqd %mm7, [%edx+56] + pand %mm0, %mm5 + pand %mm0, %mm6 + pand %mm0, %mm7 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + je Continue + mov %eax, 1 + jmp End + +Continue: + sub %ecx, 64 + add %esi, 64 + add %edx, 64 +ContinueTest: + cmp %ecx, 64 + jge Cmp8 + +Done8: + test %ecx, 0x20 + jz Done4 + movq %mm0, [%esi] + movq %mm1, [%esi+8] + movq %mm2, [%esi+16] + movq %mm3, [%esi+24] + pcmpeqd %mm0, [%edx] + pcmpeqd %mm1, [%edx+8] + pcmpeqd %mm2, [%edx+16] + pcmpeqd %mm3, [%edx+24] + pand %mm0, %mm1 + pand %mm0, %mm2 + pand %mm0, %mm3 + pmovmskb %eax, %mm0 + sub %ecx, 32 + add %esi, 32 + add %edx, 32 + + // check if eq + cmp %eax, 0xff + je Done4 + mov %eax, 1 + jmp End + +Done4: + cmp %ecx, 24 + jne Done2 + movq %mm0, [%esi] + movq %mm1, [%esi+8] + movq %mm2, [%esi+16] + pcmpeqd %mm0, [%edx] + pcmpeqd %mm1, [%edx+8] + pcmpeqd %mm2, [%edx+16] + pand %mm0, %mm1 + pand %mm0, %mm2 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + setne %al + jmp End + +Done2: + cmp %ecx, 16 + jne Done1 + + movq %mm0, [%esi] + movq %mm1, [%esi+8] + pcmpeqd %mm0, [%edx] + pcmpeqd %mm1, [%edx+8] + pand %mm0, %mm1 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + setne %al + jmp End + +Done1: + cmp %ecx, 8 + jne Done + + mov %eax, [%esi] + mov %esi, [%esi+4] + cmp %eax, [%edx] + je Next + mov %eax, 1 + jmp End + +Next: + cmp %esi, [%edx+4] + setne %al + jmp End + +Done: + xor %eax, %eax + +End: + pop %esi + emms + ret + + +#ifdef ZEROGS_SSE2 +// SSE2 extensions +#define punpck(op, sd0, sd2, s1, s3, d1, d3) \ + movdqa %xmm##d1, %xmm##sd0; \ + pshufd %xmm##d3, %xmm##sd2, 0xe4; \ + punpckl##op %xmm##sd0, %xmm##s1; \ + punpckh##op %xmm##d1, %xmm##s1; \ + punpckl##op %xmm##sd2, %xmm##s3; \ + punpckh##op %xmm##d3, %xmm##s3; \ + + +#define punpcknb \ + movdqa %xmm4, %xmm0; \ + pshufd %xmm5, %xmm1, 0xe4; \ + \ + psllq %xmm1, 4; \ + psrlq %xmm4, 4; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm0, %xmm7; \ + pandn %xmm6, %xmm1; \ + por %xmm0, %xmm6; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm4, %xmm7; \ + pandn %xmm6, %xmm5; \ + por %xmm4, %xmm6; \ + \ + movdqa %xmm1, %xmm4; \ + \ + movdqa %xmm4, %xmm2; \ + pshufd %xmm5, %xmm3, 0xe4; \ + \ + psllq %xmm3, 4; \ + psrlq %xmm4, 4; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm2, %xmm7; \ + pandn %xmm6, %xmm3; \ + por %xmm2, %xmm6; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm4, %xmm7; \ + pandn %xmm6, %xmm5; \ + por %xmm4, %xmm6; \ + \ + movdqa %xmm3, %xmm4; \ + \ + punpck(bw, 0, 2, 1, 3, 4, 6); \ + + +// +// swizzling +// + +// +// SwizzleBlock32 +// + +.globl SwizzleBlock32_sse2 + .type SwizzleBlock32_sse2, @function +SwizzleBlock32_sse2: + + push %esi + push %edi + + mov %edi, %ecx + mov %esi, %edx + mov %edx, [%esp+4+8] + mov %ecx, 4 + + mov %eax, [%esp+8+8] + cmp %eax, 0xffffffff + jne SwizzleBlock32_sse2_2 + + .align 16 +SwizzleBlock32_sse2_1: + movdqa %xmm0, [%esi] + movdqa %xmm4, [%esi+16] + movdqa %xmm1, [%esi+%edx] + movdqa %xmm5, [%esi+%edx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movntps [%edi+16*0], %xmm0 + movntps [%edi+16*1], %xmm2 + movntps [%edi+16*2], %xmm4 + movntps [%edi+16*3], %xmm6 + + lea %esi, [%esi+%edx*2] + add %edi, 64 + + dec %ecx + jnz SwizzleBlock32_sse2_1 + + pop %edi + pop %esi + + ret 8 + +SwizzleBlock32_sse2_2: + + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock32_sse2_3: + movdqa %xmm0, [%esi] + movdqa %xmm4, [%esi+16] + movdqa %xmm1, [%esi+%edx] + movdqa %xmm5, [%esi+%edx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + + pandn %xmm3, [%edi+16*0] + pand %xmm0, %xmm7 + por %xmm0, %xmm3 + movntps [%edi+16*0], %xmm0 + + pandn %xmm5, [%edi+16*1] + pand %xmm2, %xmm7 + por %xmm2, %xmm5 + movntps [%edi+16*1], %xmm2 + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + + pandn %xmm3, [%edi+16*2] + pand %xmm4, %xmm7 + por %xmm4, %xmm3 + movntps [%edi+16*2], %xmm4 + + pandn %xmm5, [%edi+16*3] + pand %xmm6, %xmm7 + por %xmm6, %xmm5 + movntps [%edi+16*3], %xmm6 + + lea %esi, [%esi+%edx*2] + add %edi, 64 + + dec %ecx + jnz SwizzleBlock32_sse2_3 + + pop %edi + pop %esi + + ret 8 + +// +// SwizzleBlock16 +// + +.globl SwizzleBlock16_sse2 + .type SwizzleBlock16_sse2, @function +SwizzleBlock16_sse2: + + push %ebx + + mov %ebx, [%esp+4+4] + mov %eax, 4 + + .align 16 +SwizzleBlock16_sse2_1: + movdqa %xmm0, [%edx] + movdqa %xmm1, [%edx+16] + movdqa %xmm2, [%edx+%ebx] + movdqa %xmm3, [%edx+%ebx+16] + + punpck(wd, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 5) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm1 + movntps [%ecx+16*2], %xmm4 + movntps [%ecx+16*3], %xmm5 + + lea %edx, [%edx+%ebx*2] + add %ecx, 64 + + dec %eax + jnz SwizzleBlock16_sse2_1 + + pop %ebx + + ret 4 + +// +// SwizzleBlock8 +// + +.globl SwizzleBlock8_sse2 + .type SwizzleBlock8_sse2, @function +SwizzleBlock8_sse2: + + push %ebx + + mov %ebx, [%esp+4+4] + mov %eax, 2 + + .align 16 +SwizzleBlock8_sse2_1: + // col 0, 2 + + movdqa %xmm0, [%edx] + movdqa %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + pshufd %xmm1, [%edx], 0xb1 + pshufd %xmm3, [%edx+%ebx], 0xb1 + lea %edx, [%edx+%ebx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm4 + movntps [%ecx+16*2], %xmm1 + movntps [%ecx+16*3], %xmm5 + + // col 1, 3 + + pshufd %xmm0, [%edx], 0xb1 + pshufd %xmm2, [%edx+%ebx], 0xb1 + lea %edx, [%edx+%ebx*2] + + movdqa %xmm1, [%edx] + movdqa %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movntps [%ecx+16*4], %xmm0 + movntps [%ecx+16*5], %xmm4 + movntps [%ecx+16*6], %xmm1 + movntps [%ecx+16*7], %xmm5 + + add %ecx, 128 + + dec %eax + jnz SwizzleBlock8_sse2_1 + + pop %ebx + + ret 4 + +// +// SwizzleBlock4 +// + +.globl SwizzleBlock4_sse2 + .type SwizzleBlock4_sse2, @function +SwizzleBlock4_sse2: + + push %ebx + + mov %eax, 0xf0f0f0f + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + mov %ebx, [%esp+4+4] + mov %eax, 2 + + .align 16 +SwizzleBlock4_sse2_1: + // col 0, 2 + + movdqa %xmm0, [%edx] + movdqa %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + movdqa %xmm1, [%edx] + movdqa %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + pshuflw %xmm1, %xmm1, 0xb1 + pshuflw %xmm3, %xmm3, 0xb1 + pshufhw %xmm1, %xmm1, 0xb1 + pshufhw %xmm3, %xmm3, 0xb1 + + punpcknb + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm1 + movntps [%ecx+16*2], %xmm4 + movntps [%ecx+16*3], %xmm3 + + // col 1, 3 + + movdqa %xmm0, [%edx] + movdqa %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + movdqa %xmm1, [%edx] + movdqa %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + pshuflw %xmm0, %xmm0, 0xb1 + pshuflw %xmm2, %xmm2, 0xb1 + pshufhw %xmm0, %xmm0, 0xb1 + pshufhw %xmm2, %xmm2, 0xb1 + + punpcknb + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movntps [%ecx+16*4], %xmm0 + movntps [%ecx+16*5], %xmm1 + movntps [%ecx+16*6], %xmm4 + movntps [%ecx+16*7], %xmm3 + + add %ecx, 128 + + dec %eax + jnz SwizzleBlock4_sse2_1 + + pop %ebx + + ret 4 + +// +// swizzling with unaligned reads +// + +// +// SwizzleBlock32u +// + +.globl SwizzleBlock32u_sse2 + .type SwizzleBlock32u_sse2, @function +SwizzleBlock32u_sse2: + + push %esi + push %edi + + mov %edi, %ecx + mov %esi, %edx + mov %edx, [%esp+4+8] + mov %ecx, 4 + + mov %eax, [%esp+8+8] + cmp %eax, 0xffffffff + jne SwizzleBlock32u_sse2_2 + + .align 16 +SwizzleBlock32u_sse2_1: + movdqu %xmm0, [%esi] + movdqu %xmm4, [%esi+16] + movdqu %xmm1, [%esi+%edx] + movdqu %xmm5, [%esi+%edx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movntps [%edi+16*0], %xmm0 + movntps [%edi+16*1], %xmm2 + movntps [%edi+16*2], %xmm4 + movntps [%edi+16*3], %xmm6 + + lea %esi, [%esi+%edx*2] + add %edi, 64 + + dec %ecx + jnz SwizzleBlock32u_sse2_1 + + pop %edi + pop %esi + + ret 8 + +SwizzleBlock32u_sse2_2: + + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock32u_sse2_3: + movdqu %xmm0, [%esi] + movdqu %xmm4, [%esi+16] + movdqu %xmm1, [%esi+%edx] + movdqu %xmm5, [%esi+%edx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + + pandn %xmm3, [%edi+16*0] + pand %xmm0, %xmm7 + por %xmm0, %xmm3 + movdqa [%edi+16*0], %xmm0 + + pandn %xmm5, [%edi+16*1] + pand %xmm2, %xmm7 + por %xmm2, %xmm5 + movdqa [%edi+16*1], %xmm2 + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + + pandn %xmm3, [%edi+16*2] + pand %xmm4, %xmm7 + por %xmm4, %xmm3 + movdqa [%edi+16*2], %xmm4 + + pandn %xmm5, [%edi+16*3] + pand %xmm6, %xmm7 + por %xmm6, %xmm5 + movdqa [%edi+16*3], %xmm6 + + lea %esi, [%esi+%edx*2] + add %edi, 64 + + dec %ecx + jnz SwizzleBlock32u_sse2_3 + + pop %edi + pop %esi + + ret 8 + +// +// SwizzleBlock16u +// + +.globl SwizzleBlock16u_sse2 + .type SwizzleBlock16u_sse2, @function +SwizzleBlock16u_sse2: + + push %ebx + + mov %ebx, [%esp+4+4] + mov %eax, 4 + + .align 16 +SwizzleBlock16u_sse2_1: + movdqu %xmm0, [%edx] + movdqu %xmm1, [%edx+16] + movdqu %xmm2, [%edx+%ebx] + movdqu %xmm3, [%edx+%ebx+16] + + punpck(wd, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 5) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm1 + movntps [%ecx+16*2], %xmm4 + movntps [%ecx+16*3], %xmm5 + + lea %edx, [%edx+%ebx*2] + add %ecx, 64 + + dec %eax + jnz SwizzleBlock16u_sse2_1 + + pop %ebx + + ret 4 + +// +// SwizzleBlock8u +// + +.globl SwizzleBlock8u_sse2 + .type SwizzleBlock8u_sse2, @function +SwizzleBlock8u_sse2: + + push %ebx + + mov %ebx, [%esp+4+4] + mov %eax, 2 + + .align 16 +SwizzleBlock8u_sse2_1: + // col 0, 2 + + movdqu %xmm0, [%edx] + movdqu %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + movdqu %xmm1, [%edx] + movdqu %xmm3, [%edx+%ebx] + pshufd %xmm1, %xmm1, 0xb1 + pshufd %xmm3, %xmm3, 0xb1 + lea %edx, [%edx+%ebx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm4 + movntps [%ecx+16*2], %xmm1 + movntps [%ecx+16*3], %xmm5 + + // col 1, 3 + + movdqu %xmm0, [%edx] + movdqu %xmm2, [%edx+%ebx] + pshufd %xmm0, %xmm0, 0xb1 + pshufd %xmm2, %xmm2, 0xb1 + lea %edx, [%edx+%ebx*2] + + movdqu %xmm1, [%edx] + movdqu %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movntps [%ecx+16*4], %xmm0 + movntps [%ecx+16*5], %xmm4 + movntps [%ecx+16*6], %xmm1 + movntps [%ecx+16*7], %xmm5 + + add %ecx, 128 + + dec %eax + jnz SwizzleBlock8u_sse2_1 + + pop %ebx + + ret 4 + +// +// SwizzleBlock4u +// + +.globl SwizzleBlock4u_sse2 + .type SwizzleBlock4u_sse2, @function +SwizzleBlock4u_sse2: + + push %ebx + + mov %eax, 0xf0f0f0f + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + mov %ebx, [%esp+4+4] + mov %eax, 2 + + .align 16 +SwizzleBlock4u_sse2_1: + // col 0, 2 + + movdqu %xmm0, [%edx] + movdqu %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + movdqu %xmm1, [%edx] + movdqu %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + pshuflw %xmm1, %xmm1, 0xb1 + pshuflw %xmm3, %xmm3, 0xb1 + pshufhw %xmm1, %xmm1, 0xb1 + pshufhw %xmm3, %xmm3, 0xb1 + + punpcknb + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movntps [%ecx+16*0], %xmm0 + movntps [%ecx+16*1], %xmm1 + movntps [%ecx+16*2], %xmm4 + movntps [%ecx+16*3], %xmm3 + + // col 1, 3 + + movdqu %xmm0, [%edx] + movdqu %xmm2, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + movdqu %xmm1, [%edx] + movdqu %xmm3, [%edx+%ebx] + lea %edx, [%edx+%ebx*2] + + pshuflw %xmm0, %xmm0, 0xb1 + pshuflw %xmm2, %xmm2, 0xb1 + pshufhw %xmm0, %xmm0, 0xb1 + pshufhw %xmm2, %xmm2, 0xb1 + + punpcknb + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movntps [%ecx+16*4], %xmm0 + movntps [%ecx+16*5], %xmm1 + movntps [%ecx+16*6], %xmm4 + movntps [%ecx+16*7], %xmm3 + + add %ecx, 128 + + dec %eax + jnz SwizzleBlock4u_sse2_1 + + pop %ebx + + ret 4 + + + .align 16 +s_clut16mask: + .long 0xffff0000 + .long 0xffff0000 + .long 0xffff0000 + .long 0xffff0000 + + .align 16 +s_clut16mask2: + .long 0x0000ffff + .long 0x0000ffff + .long 0x0000ffff + .long 0x0000ffff + +.globl WriteCLUT_T16_I4_CSM1_sse2 + .type WriteCLUT_T16_I4_CSM1_sse2, @function +WriteCLUT_T16_I4_CSM1_sse2: + movdqa %xmm0, xmmword ptr [%ecx] + movdqa %xmm1, xmmword ptr [%ecx+16] + movdqa %xmm2, xmmword ptr [%ecx+32] + movdqa %xmm3, xmmword ptr [%ecx+48] + + // rearrange + pshuflw %xmm0, %xmm0, 0x88 + pshufhw %xmm0, %xmm0, 0x88 + pshuflw %xmm1, %xmm1, 0x88 + pshufhw %xmm1, %xmm1, 0x88 + pshuflw %xmm2, %xmm2, 0x88 + pshufhw %xmm2, %xmm2, 0x88 + pshuflw %xmm3, %xmm3, 0x88 + pshufhw %xmm3, %xmm3, 0x88 + + shufps %xmm0, %xmm1, 0x88 + shufps %xmm2, %xmm3, 0x88 + + pshufd %xmm0, %xmm0, 0xd8 + pshufd %xmm2, %xmm2, 0xd8 + + pxor %xmm6, %xmm6 + + test %edx, 15 + jnz WriteUnaligned + + movdqa %xmm7, [s_clut16mask] // saves upper 16 bits + + // have to save interlaced with the old data + movdqa %xmm4, [%edx] + movdqa %xmm5, [%edx+32] + movhlps %xmm1, %xmm0 + movlhps %xmm0, %xmm2 // lower 8 colors + + pand %xmm4, %xmm7 + pand %xmm5, %xmm7 + + shufps %xmm1, %xmm2, 0xe4 // upper 8 colors + movdqa %xmm2, %xmm0 + movdqa %xmm3, %xmm1 + + punpcklwd %xmm0, %xmm6 + punpcklwd %xmm1, %xmm6 + por %xmm0, %xmm4 + por %xmm1, %xmm5 + + punpckhwd %xmm2, %xmm6 + punpckhwd %xmm3, %xmm6 + + movdqa [%edx], %xmm0 + movdqa [%edx+32], %xmm1 + + movdqa %xmm5, %xmm7 + pand %xmm7, [%edx+16] + pand %xmm5, [%edx+48] + + por %xmm2, %xmm7 + por %xmm3, %xmm5 + + movdqa [%edx+16], %xmm2 + movdqa [%edx+48], %xmm3 + jmp WriteCLUT_T16_I4_CSM1_End + +WriteUnaligned: + // %edx is offset by 2 + sub %edx, 2 + + movdqa %xmm7, [s_clut16mask2] // saves lower 16 bits + + // have to save interlaced with the old data + movdqa %xmm4, [%edx] + movdqa %xmm5, [%edx+32] + movhlps %xmm1, %xmm0 + movlhps %xmm0, %xmm2 // lower 8 colors + + pand %xmm4, %xmm7 + pand %xmm5, %xmm7 + + shufps %xmm1, %xmm2, 0xe4 // upper 8 colors + movdqa %xmm2, %xmm0 + movdqa %xmm3, %xmm1 + + punpcklwd %xmm0, %xmm6 + punpcklwd %xmm1, %xmm6 + pslld %xmm0, 16 + pslld %xmm1, 16 + por %xmm0, %xmm4 + por %xmm1, %xmm5 + + punpckhwd %xmm2, %xmm6 + punpckhwd %xmm3, %xmm6 + pslld %xmm2, 16 + pslld %xmm3, 16 + + movdqa [%edx], %xmm0 + movdqa [%edx+32], %xmm1 + + movdqa %xmm5, %xmm7 + pand %xmm7, [%edx+16] + pand %xmm5, [%edx+48] + + por %xmm2, %xmm7 + por %xmm3, %xmm5 + + movdqa [%edx+16], %xmm2 + movdqa [%edx+48], %xmm3 +WriteCLUT_T16_I4_CSM1_End: + ret + + +.globl WriteCLUT_T32_I8_CSM1_sse2 + .type WriteCLUT_T32_I8_CSM1_sse2, @function +WriteCLUT_T32_I8_CSM1_sse2: + push %ebx + xor %ebx, %ebx +.L231: + xor %eax, %eax + .align 16 +.L232: + movdqa %xmm3, XMMWORD PTR [%eax+16+%ecx] + movdqa %xmm4, XMMWORD PTR [%eax+48+%ecx] + movdqa %xmm1, XMMWORD PTR [%eax+%ecx] + movdqa %xmm2, XMMWORD PTR [%eax+32+%ecx] + movdqa %xmm0, %xmm1 + punpckhqdq %xmm1, %xmm3 + punpcklqdq %xmm0, %xmm3 + movdqa XMMWORD PTR [%edx+32+%eax*2], %xmm1 + movdqa XMMWORD PTR [%edx+%eax*2], %xmm0 + movdqa %xmm0, %xmm2 + punpckhqdq %xmm2, %xmm4 + punpcklqdq %xmm0, %xmm4 + movdqa XMMWORD PTR [%edx+48+%eax*2], %xmm2 + movdqa XMMWORD PTR [%edx+16+%eax*2], %xmm0 + movdqa %xmm1, XMMWORD PTR [%eax+256+%ecx] + movdqa %xmm3, XMMWORD PTR [%eax+272+%ecx] + movdqa %xmm2, XMMWORD PTR [%eax+288+%ecx] + movdqa %xmm4, XMMWORD PTR [%eax+304+%ecx] + movdqa %xmm0, %xmm1 + punpckhqdq %xmm1, %xmm3 + punpcklqdq %xmm0, %xmm3 + movdqa XMMWORD PTR [%edx+96+%eax*2], %xmm1 + movdqa XMMWORD PTR [%edx+64+%eax*2], %xmm0 + movdqa %xmm0, %xmm2 + punpckhqdq %xmm2, %xmm4 + punpcklqdq %xmm0, %xmm4 + movdqa XMMWORD PTR [%edx+112+%eax*2], %xmm2 + movdqa XMMWORD PTR [%edx+80+%eax*2], %xmm0 + add %eax, 64 + cmp %eax, 256 + jne .L232 + add %edx, 512 + add %ecx, 512 + add %ebx, 512 + cmp %ebx, 1024 + jne .L231 + pop %ebx + ret + +.globl WriteCLUT_T32_I4_CSM1_sse2 + .type WriteCLUT_T32_I4_CSM1_sse2, @function +WriteCLUT_T32_I4_CSM1_sse2: + movdqa %xmm1, XMMWORD PTR [%ecx] + movdqa %xmm3, XMMWORD PTR [%ecx+16] + movdqa %xmm2, XMMWORD PTR [%ecx+32] + movdqa %xmm4, XMMWORD PTR [%ecx+48] + movdqa %xmm0, %xmm1 + punpckhqdq %xmm1, %xmm3 + punpcklqdq %xmm0, %xmm3 + movdqa XMMWORD PTR [%edx+32], %xmm1 + movdqa XMMWORD PTR [%edx], %xmm0 + movdqa %xmm0, %xmm2 + punpckhqdq %xmm2, %xmm4 + punpcklqdq %xmm0, %xmm4 + movdqa XMMWORD PTR [%edx+48], %xmm2 + movdqa XMMWORD PTR [%edx+16], %xmm0 + ret + +#endif diff --git a/plugins/zerogs/opengl/x86-32.asm b/plugins/zerogs/opengl/x86-32.asm new file mode 100644 index 0000000000..1507d2192d --- /dev/null +++ b/plugins/zerogs/opengl/x86-32.asm @@ -0,0 +1,652 @@ +; Copyright (C) 2003-2005 Gabest +; http://www.gabest.org +; +; 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, 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 GNU Make; see the file COPYING. If not, write to +; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +; http://www.gnu.org/copyleft/gpl.html +; +; + .686 + .model flat + .mmx + .xmm + + .const + + __uvmin DD 0d01502f9r ; -1e+010 + __uvmax DD 0501502f9r ; +1e+010 + + .code + +; +; swizzling +; + +punpck macro op, sd0, sd2, s1, s3, d1, d3 + + movdqa @CatStr(xmm, %d1), @CatStr(xmm, %sd0) + pshufd @CatStr(xmm, %d3), @CatStr(xmm, %sd2), 0e4h + + @CatStr(punpckl, op) @CatStr(xmm, %sd0), @CatStr(xmm, %s1) + @CatStr(punpckh, op) @CatStr(xmm, %d1), @CatStr(xmm, %s1) + @CatStr(punpckl, op) @CatStr(xmm, %sd2), @CatStr(xmm, %s3) + @CatStr(punpckh, op) @CatStr(xmm, %d3), @CatStr(xmm, %s3) + + endm + +punpcknb macro + + movdqa xmm4, xmm0 + pshufd xmm5, xmm1, 0e4h + + psllq xmm1, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm0, xmm7 + pandn xmm6, xmm1 + por xmm0, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm1, xmm4 + + movdqa xmm4, xmm2 + pshufd xmm5, xmm3, 0e4h + + psllq xmm3, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm2, xmm7 + pandn xmm6, xmm3 + por xmm2, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm3, xmm4 + + punpck bw, 0, 2, 1, 3, 4, 6 + + endm + + +; +; swizzling +; + +; +; SwizzleBlock32 +; + +@SwizzleBlock32_sse2@16 proc public + + + push esi + push edi + + mov edi, ecx + mov esi, edx + mov edx, [esp+4+8] + mov ecx, 4 + + mov eax, [esp+8+8] + cmp eax, 0ffffffffh + jne SwizzleBlock32_sse2@WM + + align 16 +@@: + movdqa xmm0, [esi] + movdqa xmm4, [esi+16] + movdqa xmm1, [esi+edx] + movdqa xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movntps [edi+16*0], xmm0 + movntps [edi+16*1], xmm2 + movntps [edi+16*2], xmm4 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +SwizzleBlock32_sse2@WM: + + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqa xmm0, [esi] + movdqa xmm4, [esi+16] + movdqa xmm1, [esi+edx] + movdqa xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movntps [edi+16*0], xmm0 + + pandn xmm5, [edi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movntps [edi+16*1], xmm2 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*2] + pand xmm4, xmm7 + por xmm4, xmm3 + movntps [edi+16*2], xmm4 + + pandn xmm5, [edi+16*3] + pand xmm6, xmm7 + por xmm6, xmm5 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +@SwizzleBlock32_sse2@16 endp + +; +; SwizzleBlock16 +; + +@SwizzleBlock16_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqa xmm0, [edx] + movdqa xmm1, [edx+16] + movdqa xmm2, [edx+ebx] + movdqa xmm3, [edx+ebx+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm5 + + lea edx, [edx+ebx*2] + add ecx, 64 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock16_sse2@12 endp + +; +; SwizzleBlock8 +; + +@SwizzleBlock8_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + pshufd xmm1, [edx], 0b1h + pshufd xmm3, [edx+ebx], 0b1h + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm4 + movntps [ecx+16*2], xmm1 + movntps [ecx+16*3], xmm5 + + ; col 1, 3 + + pshufd xmm0, [edx], 0b1h + pshufd xmm2, [edx+ebx], 0b1h + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm4 + movntps [ecx+16*6], xmm1 + movntps [ecx+16*7], xmm5 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock8_sse2@12 endp + +; +; SwizzleBlock4 +; + +@SwizzleBlock4_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm3 + + ; col 1, 3 + + movdqa xmm0, [edx] + movdqa xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqa xmm1, [edx] + movdqa xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm1 + movntps [ecx+16*6], xmm4 + movntps [ecx+16*7], xmm3 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock4_sse2@12 endp + +; +; swizzling with unaligned reads +; + +; +; SwizzleBlock32u +; + +@SwizzleBlock32u_sse2@16 proc public + + push esi + push edi + + mov edi, ecx + mov esi, edx + mov edx, [esp+4+8] + mov ecx, 4 + + mov eax, [esp+8+8] + cmp eax, 0ffffffffh + jne SwizzleBlock32u_sse2@WM + + align 16 +@@: + movdqu xmm0, [esi] + movdqu xmm4, [esi+16] + movdqu xmm1, [esi+edx] + movdqu xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movntps [edi+16*0], xmm0 + movntps [edi+16*1], xmm2 + movntps [edi+16*2], xmm4 + movntps [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +SwizzleBlock32u_sse2@WM: + + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqu xmm0, [esi] + movdqu xmm4, [esi+16] + movdqu xmm1, [esi+edx] + movdqu xmm5, [esi+edx+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [edi+16*0], xmm0 + + pandn xmm5, [edi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [edi+16*1], xmm2 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + + pandn xmm3, [edi+16*2] + pand xmm4, xmm7 + por xmm4, xmm3 + movdqa [edi+16*2], xmm4 + + pandn xmm5, [edi+16*3] + pand xmm6, xmm7 + por xmm6, xmm5 + movdqa [edi+16*3], xmm6 + + lea esi, [esi+edx*2] + add edi, 64 + + dec ecx + jnz @B + + pop edi + pop esi + + ret 8 + +@SwizzleBlock32u_sse2@16 endp + +; +; SwizzleBlock16u +; + +@SwizzleBlock16u_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 4 + + align 16 +@@: + movdqu xmm0, [edx] + movdqu xmm1, [edx+16] + movdqu xmm2, [edx+ebx] + movdqu xmm3, [edx+ebx+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm5 + + lea edx, [edx+ebx*2] + add ecx, 64 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock16u_sse2@12 endp + +; +; SwizzleBlock8u +; + +@SwizzleBlock8u_sse2@12 proc public + + push ebx + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + pshufd xmm1, xmm1, 0b1h + pshufd xmm3, xmm3, 0b1h + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm4 + movntps [ecx+16*2], xmm1 + movntps [ecx+16*3], xmm5 + + ; col 1, 3 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm4 + movntps [ecx+16*6], xmm1 + movntps [ecx+16*7], xmm5 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock8u_sse2@12 endp + +; +; SwizzleBlock4u +; + +@SwizzleBlock4u_sse2@12 proc public + + push ebx + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + mov ebx, [esp+4+4] + mov eax, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*0], xmm0 + movntps [ecx+16*1], xmm1 + movntps [ecx+16*2], xmm4 + movntps [ecx+16*3], xmm3 + + ; col 1, 3 + + movdqu xmm0, [edx] + movdqu xmm2, [edx+ebx] + lea edx, [edx+ebx*2] + + movdqu xmm1, [edx] + movdqu xmm3, [edx+ebx] + lea edx, [edx+ebx*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknb + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movntps [ecx+16*4], xmm0 + movntps [ecx+16*5], xmm1 + movntps [ecx+16*6], xmm4 + movntps [ecx+16*7], xmm3 + + add ecx, 128 + + dec eax + jnz @B + + pop ebx + + ret 4 + +@SwizzleBlock4u_sse2@12 endp + + end \ No newline at end of file diff --git a/plugins/zerogs/opengl/x86-64.S b/plugins/zerogs/opengl/x86-64.S new file mode 100644 index 0000000000..6f221e7b33 --- /dev/null +++ b/plugins/zerogs/opengl/x86-64.S @@ -0,0 +1,906 @@ +## Copyright (C) 2005-2006 zerofrog(@gmail.com) +# +# 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 ve%rsion 2, or (at your option) +# any later ve%rsion. +# +# 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 GNU Make see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +# +# +.intel_syntax + +## mmx memcpy implementation, size has to be a multiple of 8 +## returns 0 is equal, nonzero value if not equal +## ~10 times faster than standard memcmp +## (zerofrog) +## u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +## %rdi - src1 +## %rsi - src2 +## edx - cmpsize +.globl memcmp_mmx + .type memcmp_mmx, @function +memcmp_mmx: + cmp %edx, 32 + jl Done4 + + ## custom test first 8 to make sure things are ok + movq %mm0, [%rsi] + movq %mm1, [%rsi+8] + pcmpeqd %mm0, [%rdi] + pcmpeqd %mm1, [%rdi+8] + pand %mm0, %mm1 + movq %mm2, [%rsi+16] + pmovmskb %eax, %mm0 + movq %mm3, [%rsi+24] + + // check if eq + cmp %eax, 0xff + je NextComp + mov %eax, 1 + jmp End + +NextComp: + pcmpeqd %mm2, [%rdi+16] + pcmpeqd %mm3, [%rdi+24] + pand %mm2, %mm3 + pmovmskb %eax, %mm2 + + sub %edx, 32 + add %rsi, 32 + add %rdi, 32 + + // check if eq + cmp %eax, 0xff + je ContinueTest + mov %eax, 1 + jmp End + + cmp %edx, 64 + jl Done8 + +Cmp8: + movq %mm0, [%rsi] + movq %mm1, [%rsi+8] + movq %mm2, [%rsi+16] + movq %mm3, [%rsi+24] + movq %mm4, [%rsi+32] + movq %mm5, [%rsi+40] + movq %mm6, [%rsi+48] + movq %mm7, [%rsi+56] + pcmpeqd %mm0, [%rdi] + pcmpeqd %mm1, [%rdi+8] + pcmpeqd %mm2, [%rdi+16] + pcmpeqd %mm3, [%rdi+24] + pand %mm0, %mm1 + pcmpeqd %mm4, [%rdi+32] + pand %mm0, %mm2 + pcmpeqd %mm5, [%rdi+40] + pand %mm0, %mm3 + pcmpeqd %mm6, [%rdi+48] + pand %mm0, %mm4 + pcmpeqd %mm7, [%rdi+56] + pand %mm0, %mm5 + pand %mm0, %mm6 + pand %mm0, %mm7 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + je Continue + mov %eax, 1 + jmp End + +Continue: + sub %edx, 64 + add %rsi, 64 + add %rdi, 64 +ContinueTest: + cmp %edx, 64 + jge Cmp8 + +Done8: + test %edx, 0x20 + jz Done4 + movq %mm0, [%rsi] + movq %mm1, [%rsi+8] + movq %mm2, [%rsi+16] + movq %mm3, [%rsi+24] + pcmpeqd %mm0, [%rdi] + pcmpeqd %mm1, [%rdi+8] + pcmpeqd %mm2, [%rdi+16] + pcmpeqd %mm3, [%rdi+24] + pand %mm0, %mm1 + pand %mm0, %mm2 + pand %mm0, %mm3 + pmovmskb %eax, %mm0 + sub %edx, 32 + add %rsi, 32 + add %rdi, 32 + + // check if eq + cmp %eax, 0xff + je Done4 + mov %eax, 1 + jmp End + +Done4: + cmp %edx, 24 + jne Done2 + movq %mm0, [%rsi] + movq %mm1, [%rsi+8] + movq %mm2, [%rsi+16] + pcmpeqd %mm0, [%rdi] + pcmpeqd %mm1, [%rdi+8] + pcmpeqd %mm2, [%rdi+16] + pand %mm0, %mm1 + pand %mm0, %mm2 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + je Done + mov %eax, 1 + jmp End + +Done2: + cmp %edx, 16 + jne Done1 + + movq %mm0, [%rsi] + movq %mm1, [%rsi+8] + pcmpeqd %mm0, [%rdi] + pcmpeqd %mm1, [%rdi+8] + pand %mm0, %mm1 + pmovmskb %eax, %mm0 + + // check if eq + cmp %eax, 0xff + je Done + mov %eax, 1 + jmp End + +Done1: + cmp %edx, 8 + jne Done + + mov %eax, [%rsi] + mov %rsi, [%rsi+4] + cmp %eax, [%rdi] + je Next + mov %eax, 1 + jmp End + +Next: + cmp %rsi, [%rdi+4] + je Done + mov %eax, 1 + jmp End + +Done: + xor %eax, %eax + +End: + emms + ret + +#ifdef ZEROGS_SSE2 +// SSE2 extensions + +#define punpck(op, sd0, sd2, s1, s3, d1, d3) \ + movdqa %xmm##d1, %xmm##sd0; \ + pshufd %xmm##d3, %xmm##sd2, 0xe4; \ + punpckl##op %xmm##sd0, %xmm##s1; \ + punpckh##op %xmm##d1, %xmm##s1; \ + punpckl##op %xmm##sd2, %xmm##s3; \ + punpckh##op %xmm##d3, %xmm##s3; \ + +#define punpcknbl \ + movdqa %xmm4, %xmm0; \ + pshufd %xmm5, %xmm1, 0xe4; \ + \ + psllq %xmm1, 4; \ + psrlq %xmm4, 4; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm0, %xmm7; \ + pandn %xmm6, %xmm1; \ + por %xmm0, %xmm6; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm4, %xmm7; \ + pandn %xmm6, %xmm5; \ + por %xmm4, %xmm6; \ + \ + movdqa %xmm1, %xmm4; \ + \ + movdqa %xmm4, %xmm2; \ + pshufd %xmm5, %xmm3, 0xe4; \ + \ + psllq %xmm3, 4; \ + psrlq %xmm4, 4; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm2, %xmm7; \ + pandn %xmm6, %xmm3; \ + por %xmm2, %xmm6; \ + \ + movdqa %xmm6, %xmm7; \ + pand %xmm4, %xmm7; \ + pandn %xmm6, %xmm5; \ + por %xmm4, %xmm6; \ + \ + movdqa %xmm3, %xmm4; \ + \ + punpck(bw, 0, 2, 1, 3, 4, 6); \ + +#define punpcknbh \ + movdqa %xmm12, %xmm8; \ + pshufd %xmm13, %xmm9, 0xe4; \ + \ + psllq %xmm9, 4; \ + psrlq %xmm12, 4; \ + \ + movdqa %xmm14, %xmm15; \ + pand %xmm8, %xmm15; \ + pandn %xmm14, %xmm9; \ + por %xmm8, %xmm14; \ + \ + movdqa %xmm14, %xmm15; \ + pand %xmm12, %xmm15; \ + pandn %xmm14, %xmm13; \ + por %xmm12, %xmm14; \ + \ + movdqa %xmm9, %xmm12; \ + \ + movdqa %xmm12, %xmm10; \ + pshufd %xmm13, %xmm11, 0xe4; \ + \ + psllq %xmm11, 4; \ + psrlq %xmm12, 4; \ + \ + movdqa %xmm14, %xmm15; \ + pand %xmm10, %xmm15; \ + pandn %xmm14, %xmm11; \ + por %xmm10, %xmm14; \ + \ + movdqa %xmm14, %xmm15; \ + pand %xmm12, %xmm15; \ + pandn %xmm14, %xmm13; \ + por %xmm12, %xmm14; \ + \ + movdqa %xmm11, %xmm12; \ + \ + punpck(bw, 8, 10, 9, 11, 12, 14); \ + +// +// SwizzleBlock32_sse2 +// + +.globl SwizzleBlock32_sse2 + .type SwizzleBlock32_sse2, @function +SwizzleBlock32_sse2: + + mov %eax, 4 + + cmp %ecx, 0xffffffff + jne SwizzleBlock32_sse2_2 + + .align 16 +SwizzleBlock32_sse2_1: + movdqa %xmm0, [%rsi] + movdqa %xmm4, [%rsi+16] + movdqa %xmm1, [%rsi+%rdx] + movdqa %xmm5, [%rsi+%rdx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm2 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm6 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock32_sse2_1 + + ret + +SwizzleBlock32_sse2_2: + + movd %xmm7, %rcx + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock32_sse2_3: + movdqa %xmm0, [%rsi] + movdqa %xmm4, [%rsi+16] + movdqa %xmm1, [%rsi+%rdx] + movdqa %xmm5, [%rsi+%rdx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + movdqa %xmm9, %xmm7 + pshufd %xmm11, %xmm7, 0xe4 + + pandn %xmm3, [%rdi+16*0] + pand %xmm0, %xmm7 + por %xmm0, %xmm3 + movdqa [%rdi+16*0], %xmm0 + + pandn %xmm5, [%rdi+16*1] + pand %xmm2, %xmm7 + por %xmm2, %xmm5 + movdqa [%rdi+16*1], %xmm2 + + pandn %xmm9, [%rdi+16*2] + pand %xmm4, %xmm7 + por %xmm4, %xmm9 + movdqa [%rdi+16*2], %xmm4 + + pandn %xmm11, [%rdi+16*3] + pand %xmm6, %xmm7 + por %xmm6, %xmm11 + movdqa [%rdi+16*3], %xmm6 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock32_sse2_3 + + ret + +// +// SwizzleBlock16_sse2 +// + +.globl SwizzleBlock16_sse2 + .type SwizzleBlock16_sse2, @function +SwizzleBlock16_sse2: + + mov %eax, 4 + + .align 16 +SwizzleBlock16_sse2_1: + movdqa %xmm0, [%rsi] + movdqa %xmm1, [%rsi+16] + movdqa %xmm2, [%rsi+%rdx] + movdqa %xmm3, [%rsi+%rdx+16] + + punpck(wd, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 5) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm1 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm5 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock16_sse2_1 + + ret + +// +// SwizzleBlock8 +// + +.globl SwizzleBlock8_sse2 + .type SwizzleBlock8_sse2, @function +SwizzleBlock8_sse2: + + mov %ecx, 2 + + .align 16 +SwizzleBlock8_sse2_1: + // col 0, 2 + + movdqa %xmm0, [%rsi] + movdqa %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshufd %xmm1, [%rsi], 0xb1 + pshufd %xmm3, [%rsi+%rdx], 0xb1 + lea %rsi, [%rsi+%rdx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm4 + movdqa [%rdi+16*2], %xmm1 + movdqa [%rdi+16*3], %xmm5 + + // col 1, 3 + + pshufd %xmm0, [%rsi], 0xb1 + pshufd %xmm2, [%rsi+%rdx], 0xb1 + lea %rsi, [%rsi+%rdx*2] + + movdqa %xmm1, [%rsi] + movdqa %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movdqa [%rdi+16*4], %xmm0 + movdqa [%rdi+16*5], %xmm4 + movdqa [%rdi+16*6], %xmm1 + movdqa [%rdi+16*7], %xmm5 + + add %rdi, 128 + + dec %ecx + jnz SwizzleBlock8_sse2_1 + + ret + +// +// SwizzleBlock4 +// + +.globl SwizzleBlock4_sse2 + .type SwizzleBlock4_sse2, @function +SwizzleBlock4_sse2: + + mov %ecx, 2 + + mov %eax, 0x0f0f0f0f + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock4_sse2_1: + // col 0, 2 + + movdqa %xmm0, [%rsi] + movdqa %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + movdqa %xmm1, [%rsi] + movdqa %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshuflw %xmm1, %xmm1, 0xb1 + pshuflw %xmm3, %xmm3, 0xb1 + pshufhw %xmm1, %xmm1, 0xb1 + pshufhw %xmm3, %xmm3, 0xb1 + + punpcknbl + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm1 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm3 + + // col 1, 3 + + movdqa %xmm0, [%rsi] + movdqa %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + movdqa %xmm1, [%rsi] + movdqa %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshuflw %xmm0, %xmm0, 0xb1 + pshuflw %xmm2, %xmm2, 0xb1 + pshufhw %xmm0, %xmm0, 0xb1 + pshufhw %xmm2, %xmm2, 0xb1 + + punpcknbl + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movdqa [%rdi+16*4], %xmm0 + movdqa [%rdi+16*5], %xmm1 + movdqa [%rdi+16*6], %xmm4 + movdqa [%rdi+16*7], %xmm3 + + add %rdi, 128 + + dec %ecx + jnz SwizzleBlock4_sse2_1 + + ret + +// +// swizzling with unaligned reads +// + +// +// SwizzleBlock32u_sse2 +// + +.globl SwizzleBlock32u_sse2 + .type SwizzleBlock32u_sse2, @function +SwizzleBlock32u_sse2: + + mov %eax, 4 + + cmp %ecx, 0xffffffff + jne SwizzleBlock32u_sse2_2 + + .align 16 +SwizzleBlock32u_sse2_1: + movdqu %xmm0, [%rsi] + movdqu %xmm4, [%rsi+16] + movdqu %xmm1, [%rsi+%rdx] + movdqu %xmm5, [%rsi+%rdx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm2 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm6 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock32u_sse2_1 + + ret + +SwizzleBlock32u_sse2_2: + + movd %xmm7, %rcx + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock32u_sse2_3: + movdqu %xmm0, [%rsi] + movdqu %xmm4, [%rsi+16] + movdqu %xmm1, [%rsi+%rdx] + movdqu %xmm5, [%rsi+%rdx+16] + + punpck(qdq, 0, 4, 1, 5, 2, 6) + + movdqa %xmm3, %xmm7 + pshufd %xmm5, %xmm7, 0xe4 + movdqa %xmm9, %xmm7 + pshufd %xmm11, %xmm7, 0xe4 + + pandn %xmm3, [%rdi+16*0] + pand %xmm0, %xmm7 + por %xmm0, %xmm3 + movdqa [%rdi+16*0], %xmm0 + + pandn %xmm5, [%rdi+16*1] + pand %xmm2, %xmm7 + por %xmm2, %xmm5 + movdqa [%rdi+16*1], %xmm2 + + pandn %xmm9, [%rdi+16*2] + pand %xmm4, %xmm7 + por %xmm4, %xmm9 + movdqa [%rdi+16*2], %xmm4 + + pandn %xmm11, [%rdi+16*3] + pand %xmm6, %xmm7 + por %xmm6, %xmm11 + movdqa [%rdi+16*3], %xmm6 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock32u_sse2_3 + + ret + +// +// SwizzleBlock16u_sse2 +// + +.globl SwizzleBlock16u_sse2 + .type SwizzleBlock16u_sse2, @function +SwizzleBlock16u_sse2: + mov %eax, 4 + + .align 16 +SwizzleBlock16u_sse2_1: + movdqu %xmm0, [%rsi] + movdqu %xmm1, [%rsi+16] + movdqu %xmm2, [%rsi+%rdx] + movdqu %xmm3, [%rsi+%rdx+16] + + punpck(wd, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 5) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm1 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm5 + + lea %rsi, [%rsi+%rdx*2] + add %rdi, 64 + + dec %eax + jnz SwizzleBlock16u_sse2_1 + + ret + +// +// SwizzleBlock8u +// + +.globl SwizzleBlock8u_sse2 + .type SwizzleBlock8u_sse2, @function +SwizzleBlock8u_sse2: + mov %ecx, 2 + + .align 16 +SwizzleBlock8u_sse2_1: + // col 0, 2 + + movdqu %xmm0, [%rsi] + movdqu %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshufd %xmm1, %xmm0, 0xb1 + pshufd %xmm3, %xmm2, 0xb1 + lea %rsi, [%rsi+%rdx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm4 + movdqa [%rdi+16*2], %xmm1 + movdqa [%rdi+16*3], %xmm5 + + // col 1, 3 + + movdqu %xmm0, [%rsi] + movdqu %xmm2, [%rsi+%rdx] + pshufd %xmm0, %xmm0, 0xb1 + pshufd %xmm2, %xmm2, 0xb1 + lea %rsi, [%rsi+%rdx*2] + + movdqu %xmm1, [%rsi] + movdqu %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(wd, 0, 2, 4, 6, 1, 3) + punpck(qdq, 0, 1, 2, 3, 4, 5) + + movdqa [%rdi+16*4], %xmm0 + movdqa [%rdi+16*5], %xmm4 + movdqa [%rdi+16*6], %xmm1 + movdqa [%rdi+16*7], %xmm5 + + add %rdi, 128 + + dec %ecx + jnz SwizzleBlock8u_sse2_1 + + ret + +// +// SwizzleBlock4u +// + +.globl SwizzleBlock4u_sse2 + .type SwizzleBlock4u_sse2, @function +SwizzleBlock4u_sse2: + + mov %ecx, 2 + + mov %eax, 0xf0f0f0f + movd %xmm7, %eax + pshufd %xmm7, %xmm7, 0 + + .align 16 +SwizzleBlock4u_sse2_1: + // col 0, 2 + + movdqu %xmm0, [%rsi] + movdqu %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + movdqu %xmm1, [%rsi] + movdqu %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshuflw %xmm1, %xmm1, 0xb1 + pshuflw %xmm3, %xmm3, 0xb1 + pshufhw %xmm1, %xmm1, 0xb1 + pshufhw %xmm3, %xmm3, 0xb1 + + punpcknbl + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movdqa [%rdi+16*0], %xmm0 + movdqa [%rdi+16*1], %xmm1 + movdqa [%rdi+16*2], %xmm4 + movdqa [%rdi+16*3], %xmm3 + + // col 1, 3 + + movdqu %xmm0, [%rsi] + movdqu %xmm2, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + movdqu %xmm1, [%rsi] + movdqu %xmm3, [%rsi+%rdx] + lea %rsi, [%rsi+%rdx*2] + + pshuflw %xmm0, %xmm0, 0xb1 + pshuflw %xmm2, %xmm2, 0xb1 + pshufhw %xmm0, %xmm0, 0xb1 + pshufhw %xmm2, %xmm2, 0xb1 + + punpcknbl + punpck(bw, 0, 2, 4, 6, 1, 3) + punpck(bw, 0, 2, 1, 3, 4, 6) + punpck(qdq, 0, 4, 2, 6, 1, 3) + + movdqa [%rdi+16*4], %xmm0 + movdqa [%rdi+16*5], %xmm1 + movdqa [%rdi+16*6], %xmm4 + movdqa [%rdi+16*7], %xmm3 + + add %rdi, 128 + + dec %ecx + jnz SwizzleBlock4u_sse2_1 + + ret + + + .align 16 +s_clut16mask: + .long 0xffff0000 + .long 0xffff0000 + .long 0xffff0000 + .long 0xffff0000 + + .align 16 +s_clut16mask2: + + .long 0x0000ffff + .long 0x0000ffff + .long 0x0000ffff + .long 0x0000ffff + +.globl WriteCLUT_T16_I4_CSM1_sse2 + .type WriteCLUT_T16_I4_CSM1_sse2, @function +WriteCLUT_T16_I4_CSM1_sse2: + movdqa %xmm0, xmmword ptr [%rdi] + movdqa %xmm1, xmmword ptr [%rdi+16] + movdqa %xmm2, xmmword ptr [%rdi+32] + movdqa %xmm3, xmmword ptr [%rdi+48] + + // rearrange + pshuflw %xmm0, %xmm0, 0x88 + pshufhw %xmm0, %xmm0, 0x88 + pshuflw %xmm1, %xmm1, 0x88 + pshufhw %xmm1, %xmm1, 0x88 + pshuflw %xmm2, %xmm2, 0x88 + pshufhw %xmm2, %xmm2, 0x88 + pshuflw %xmm3, %xmm3, 0x88 + pshufhw %xmm3, %xmm3, 0x88 + + shufps %xmm0, %xmm1, 0x88 + shufps %xmm2, %xmm3, 0x88 + + pshufd %xmm0, %xmm0, 0xd8 + pshufd %xmm2, %xmm2, 0xd8 + + pxor %xmm6, %xmm6 + + test %rsi, 15 + jnz WriteUnaligned + + movdqa %xmm7, [%rip+s_clut16mask] // saves upper 16 bits + + // have to save interlaced with the old data + movdqa %xmm4, [%rsi] + movdqa %xmm5, [%rsi+32] + movhlps %xmm1, %xmm0 + movlhps %xmm0, %xmm2 // lower 8 colors + + pand %xmm4, %xmm7 + pand %xmm5, %xmm7 + + shufps %xmm1, %xmm2, 0xe4 // upper 8 colors + movdqa %xmm2, %xmm0 + movdqa %xmm3, %xmm1 + + punpcklwd %xmm0, %xmm6 + punpcklwd %xmm1, %xmm6 + por %xmm0, %xmm4 + por %xmm1, %xmm5 + + punpckhwd %xmm2, %xmm6 + punpckhwd %xmm3, %xmm6 + + movdqa [%rsi], %xmm0 + movdqa [%rsi+32], %xmm1 + + movdqa %xmm5, %xmm7 + pand %xmm7, [%rsi+16] + pand %xmm5, [%rsi+48] + + por %xmm2, %xmm7 + por %xmm3, %xmm5 + + movdqa [%rsi+16], %xmm2 + movdqa [%rsi+48], %xmm3 + jmp WriteCLUT_T16_I4_CSM1_End + +WriteUnaligned: + // %rsi is offset by 2 + sub %rsi, 2 + + movdqa %xmm7, [%rip+s_clut16mask2] // saves lower 16 bits + + // have to save interlaced with the old data + movdqa %xmm4, [%rsi] + movdqa %xmm5, [%rsi+32] + movhlps %xmm1, %xmm0 + movlhps %xmm0, %xmm2 // lower 8 colors + + pand %xmm4, %xmm7 + pand %xmm5, %xmm7 + + shufps %xmm1, %xmm2, 0xe4 // upper 8 colors + movdqa %xmm2, %xmm0 + movdqa %xmm3, %xmm1 + + punpcklwd %xmm0, %xmm6 + punpcklwd %xmm1, %xmm6 + pslld %xmm0, 16 + pslld %xmm1, 16 + por %xmm0, %xmm4 + por %xmm1, %xmm5 + + punpckhwd %xmm2, %xmm6 + punpckhwd %xmm3, %xmm6 + pslld %xmm2, 16 + pslld %xmm3, 16 + + movdqa [%rsi], %xmm0 + movdqa [%rsi+32], %xmm1 + + movdqa %xmm5, %xmm7 + pand %xmm7, [%rsi+16] + pand %xmm5, [%rsi+48] + + por %xmm2, %xmm7 + por %xmm3, %xmm5 + + movdqa [%rsi+16], %xmm2 + movdqa [%rsi+48], %xmm3 +WriteCLUT_T16_I4_CSM1_End: + ret + +#endif diff --git a/plugins/zerogs/opengl/x86-64.asm b/plugins/zerogs/opengl/x86-64.asm new file mode 100644 index 0000000000..6d476dfc6d --- /dev/null +++ b/plugins/zerogs/opengl/x86-64.asm @@ -0,0 +1,1091 @@ +; Copyright (C) 2003-2005 Gabest/zerofrog +; http:;;www.gabest.org +; +; 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, 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 GNU Make; see the file COPYING. If not, write to +; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +; http:;;www.gnu.org/copyleft/gpl.html +; +; + +extern s_clut16mask:ptr + + .code + +; mmx memcpy implementation, size has to be a multiple of 8 +; returns 0 is equal, nonzero value if not equal +; ~10 times faster than standard memcmp +; (zerofrog) +; u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) +; rcx - src1 +; rdx - src2 +; r8d - cmpsize +memcmp_mmx proc public + cmp r8d, 32 + jl Done4 + + ; custom test first 8 to make sure things are ok + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pand mm0, mm1 + movq mm2, [rdx+16] + pmovmskb eax, mm0 + movq mm3, [rdx+24] + + ; check if eq + cmp eax, 0ffh + je NextComp + mov eax, 1 + jmp Finish + +NextComp: + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm2, mm3 + pmovmskb eax, mm2 + + sub r8d, 32 + add rdx, 32 + add rcx, 32 + + ; check if eq + cmp eax, 0ffh + je ContinueTest + mov eax, 1 + jmp Finish + + cmp r8d, 64 + jl Done8 + +Cmp8: + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + movq mm4, [rdx+32] + movq mm5, [rdx+40] + movq mm6, [rdx+48] + movq mm7, [rdx+56] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm0, mm1 + pcmpeqd mm4, [rcx+32] + pand mm0, mm2 + pcmpeqd mm5, [rcx+40] + pand mm0, mm3 + pcmpeqd mm6, [rcx+48] + pand mm0, mm4 + pcmpeqd mm7, [rcx+56] + pand mm0, mm5 + pand mm0, mm6 + pand mm0, mm7 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Continue + mov eax, 1 + jmp Finish + +Continue: + sub r8d, 64 + add rdx, 64 + add rcx, 64 +ContinueTest: + cmp r8d, 64 + jge Cmp8 + +Done8: + test r8d, 020h + jz Done4 + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + movq mm3, [rdx+24] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pcmpeqd mm3, [rcx+24] + pand mm0, mm1 + pand mm0, mm2 + pand mm0, mm3 + pmovmskb eax, mm0 + sub r8d, 32 + add rdx, 32 + add rcx, 32 + + ; check if eq + cmp eax, 0ffh + je Done4 + mov eax, 1 + jmp Finish + +Done4: + cmp r8d, 24 + jne Done2 + movq mm0, [rdx] + movq mm1, [rdx+8] + movq mm2, [rdx+16] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pcmpeqd mm2, [rcx+16] + pand mm0, mm1 + pand mm0, mm2 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Done + mov eax, 1 + jmp Finish + +Done2: + cmp r8d, 16 + jne Done1 + + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+8] + pand mm0, mm1 + pmovmskb eax, mm0 + + ; check if eq + cmp eax, 0ffh + je Done + mov eax, 1 + jmp Finish + +Done1: + cmp r8d, 8 + jne Done + + mov eax, [rdx] + mov rdx, [rdx+4] + cmp eax, [rcx] + je Next + mov eax, 1 + jmp Finish + +Next: + cmp rdx, [rcx+4] + je Done + mov eax, 1 + jmp Finish + +Done: + xor eax, eax + +Finish: + emms + ret + +memcmp_mmx endp + +; TestClutChangeMMX +; mov rdx, dst +; mov rcx, src +; mov r8d, entries +TestClutChangeMMX proc public + +Start: + movq mm0, [rdx] + movq mm1, [rdx+8] + pcmpeqd mm0, [rcx] + pcmpeqd mm1, [rcx+16] + + movq mm2, [rdx+16] + movq mm3, [rdx+24] + pcmpeqd mm2, [rcx+32] + pcmpeqd mm3, [rcx+48] + + pand mm0, mm1 + pand mm2, mm3 + movq mm4, [rdx+32] + movq mm5, [rdx+40] + pcmpeqd mm4, [rcx+8] + pcmpeqd mm5, [rcx+24] + + pand mm0, mm2 + pand mm4, mm5 + movq mm6, [rdx+48] + movq mm7, [rdx+56] + pcmpeqd mm6, [rcx+40] + pcmpeqd mm7, [rcx+56] + + pand mm0, mm4 + pand mm6, mm7 + pand mm0, mm6 + + pmovmskb eax, mm0 + cmp eax, 0ffh + je Continue + mov byte ptr [r9], 1 + jmp Return + +Continue: + cmp r8d, 16 + jle Return + + test r8d, 010h + jz AddRcx + sub rcx, 448 ; go back and down one column, +AddRcx: + add rcx, 256 ; go to the right block + + + jne Continue1 + add rcx, 256 ; skip whole block +Continue1: + add rdx, 64 + sub r8d, 16 + jmp Start + +Return: + emms + ret + +TestClutChangeMMX endp + +UnswizzleZ16Target proc public + pxor xmm7, xmm7 + +Z16Loop: + ;; unpack 64 bytes at a time + movdqa xmm0, [rdx] + movdqa xmm2, [rdx+16] + movdqa xmm4, [rdx+32] + movdqa xmm6, [rdx+48] + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm5, xmm4 + + punpcklwd xmm0, xmm7 + punpckhwd xmm1, xmm7 + punpcklwd xmm2, xmm7 + punpckhwd xmm3, xmm7 + + ;; start saving + movdqa [rcx], xmm0 + movdqa [rcx+16], xmm1 + + punpcklwd xmm4, xmm7 + punpckhwd xmm5, xmm7 + + movdqa [rcx+32], xmm2 + movdqa [rcx+48], xmm3 + + movdqa xmm0, xmm6 + punpcklwd xmm6, xmm7 + + movdqa [rcx+64], xmm4 + movdqa [rcx+80], xmm5 + + punpckhwd xmm0, xmm7 + + movdqa [rcx+96], xmm6 + movdqa [rcx+112], xmm0 + + add rdx, 64 + add rcx, 128 + sub r9d, 1 + jne Z16Loop + + ret +UnswizzleZ16Target endp + +; +; swizzling +; + +punpck macro op, sd0, sd2, s1, s3, d1, d3 + + movdqa @CatStr(xmm, %d1), @CatStr(xmm, %sd0) + pshufd @CatStr(xmm, %d3), @CatStr(xmm, %sd2), 0e4h + + @CatStr(punpckl, op) @CatStr(xmm, %sd0), @CatStr(xmm, %s1) + @CatStr(punpckh, op) @CatStr(xmm, %d1), @CatStr(xmm, %s1) + @CatStr(punpckl, op) @CatStr(xmm, %sd2), @CatStr(xmm, %s3) + @CatStr(punpckh, op) @CatStr(xmm, %d3), @CatStr(xmm, %s3) + + endm + +punpcknbl macro + + movdqa xmm4, xmm0 + pshufd xmm5, xmm1, 0e4h + + psllq xmm1, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm0, xmm7 + pandn xmm6, xmm1 + por xmm0, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm1, xmm4 + + movdqa xmm4, xmm2 + pshufd xmm5, xmm3, 0e4h + + psllq xmm3, 4 + psrlq xmm4, 4 + + movdqa xmm6, xmm7 + pand xmm2, xmm7 + pandn xmm6, xmm3 + por xmm2, xmm6 + + movdqa xmm6, xmm7 + pand xmm4, xmm7 + pandn xmm6, xmm5 + por xmm4, xmm6 + + movdqa xmm3, xmm4 + + punpck bw, 0, 2, 1, 3, 4, 6 + + endm + +punpcknbh macro + + movdqa xmm12, xmm8 + pshufd xmm13, xmm9, 0e4h + + psllq xmm9, 4 + psrlq xmm12, 4 + + movdqa xmm14, xmm15 + pand xmm8, xmm15 + pandn xmm14, xmm9 + por xmm8, xmm14 + + movdqa xmm14, xmm15 + pand xmm12, xmm15 + pandn xmm14, xmm13 + por xmm12, xmm14 + + movdqa xmm9, xmm12 + + movdqa xmm12, xmm10 + pshufd xmm13, xmm11, 0e4h + + psllq xmm11, 4 + psrlq xmm12, 4 + + movdqa xmm14, xmm15 + pand xmm10, xmm15 + pandn xmm14, xmm11 + por xmm10, xmm14 + + movdqa xmm14, xmm15 + pand xmm12, xmm15 + pandn xmm14, xmm13 + por xmm12, xmm14 + + movdqa xmm11, xmm12 + + punpck bw, 8, 10, 9, 11, 12, 14 + + endm + +; +; SwizzleBlock32_sse2 +; + +SwizzleBlock32_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + cmp r9d, 0ffffffffh + jne SwizzleBlock32_sse2@WM + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm4, [rsi+16] + movdqa xmm1, [rsi+r8] + movdqa xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm2 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32_sse2@WM: + + movd xmm7, r9d + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm4, [rsi+16] + movdqa xmm1, [rsi+r8] + movdqa xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + movdqa xmm9, xmm7 + pshufd xmm11, xmm7, 0e4h + + pandn xmm3, [rdi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [rdi+16*0], xmm0 + + pandn xmm5, [rdi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [rdi+16*1], xmm2 + + pandn xmm9, [rdi+16*2] + pand xmm4, xmm7 + por xmm4, xmm9 + movdqa [rdi+16*2], xmm4 + + pandn xmm11, [rdi+16*3] + pand xmm6, xmm7 + por xmm6, xmm11 + movdqa [edi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32_sse2 endp + +; +; SwizzleBlock16_sse2 +; + +SwizzleBlock16_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + align 16 +@@: + movdqa xmm0, [rsi] + movdqa xmm1, [rsi+16] + movdqa xmm2, [rsi+r8] + movdqa xmm3, [rsi+r8+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm5 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock16_sse2 endp + +; +; SwizzleBlock8 +; + +SwizzleBlock8_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov ecx, 2 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshufd xmm1, [rsi], 0b1h + pshufd xmm3, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm4 + movdqa [rdi+16*2], xmm1 + movdqa [rdi+16*3], xmm5 + + ; col 1, 3 + + pshufd xmm0, [rsi], 0b1h + pshufd xmm2, [rsi+r8], 0b1h + lea rsi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm4 + movdqa [rdi+16*6], xmm1 + movdqa [rdi+16*7], xmm5 + + add edi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock8_sse2 endp + +; +; SwizzleBlock4 +; + +SwizzleBlock4_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 2 + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + ; col 0, 2 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm3 + + ; col 1, 3 + + movdqa xmm0, [rsi] + movdqa xmm2, [rsi+r8] + lea esi, [rsi+r8*2] + + movdqa xmm1, [rsi] + movdqa xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm1 + movdqa [rdi+16*6], xmm4 + movdqa [rdi+16*7], xmm3 + + add rdi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock4_sse2 endp + +; +; swizzling with unaligned reads +; + +; +; SwizzleBlock32u_sse2 +; + +SwizzleBlock32u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + cmp r9d, 0ffffffffh + jne SwizzleBlock32u_sse2@WM + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm4, [rsi+16] + movdqu xmm1, [rsi+r8] + movdqu xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm2 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32u_sse2@WM: + + movd xmm7, r9d + pshufd xmm7, xmm7, 0 + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm4, [rsi+16] + movdqu xmm1, [rsi+r8] + movdqu xmm5, [rsi+r8+16] + + punpck qdq, 0, 4, 1, 5, 2, 6 + + movdqa xmm3, xmm7 + pshufd xmm5, xmm7, 0e4h + movdqa xmm9, xmm7 + pshufd xmm11, xmm7, 0e4h + + pandn xmm3, [rdi+16*0] + pand xmm0, xmm7 + por xmm0, xmm3 + movdqa [rdi+16*0], xmm0 + + pandn xmm5, [rdi+16*1] + pand xmm2, xmm7 + por xmm2, xmm5 + movdqa [rdi+16*1], xmm2 + + pandn xmm9, [rdi+16*2] + pand xmm4, xmm7 + por xmm4, xmm9 + movdqa [rdi+16*2], xmm4 + + pandn xmm11, [rdi+16*3] + pand xmm6, xmm7 + por xmm6, xmm11 + movdqa [edi+16*3], xmm6 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock32u_sse2 endp + +; +; SwizzleBlock16u_sse2 +; + +SwizzleBlock16u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 4 + + align 16 +@@: + movdqu xmm0, [rsi] + movdqu xmm1, [rsi+16] + movdqu xmm2, [rsi+r8] + movdqu xmm3, [rsi+r8+16] + + punpck wd, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm5 + + lea rsi, [rsi+r8*2] + add rdi, 64 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock16u_sse2 endp + +; +; SwizzleBlock8u +; + +SwizzleBlock8u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov ecx, 2 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshufd xmm1, xmm0, 0b1h + pshufd xmm3, xmm2, 0b1h + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm4 + movdqa [rdi+16*2], xmm1 + movdqa [rdi+16*3], xmm5 + + ; col 1, 3 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + pshufd xmm0, xmm0, 0b1h + pshufd xmm2, xmm2, 0b1h + lea rsi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + punpck bw, 0, 2, 1, 3, 4, 6 + punpck wd, 0, 2, 4, 6, 1, 3 + punpck qdq, 0, 1, 2, 3, 4, 5 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm4 + movdqa [rdi+16*6], xmm1 + movdqa [rdi+16*7], xmm5 + + add edi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock8u_sse2 endp + +; +; SwizzleBlock4u +; + +SwizzleBlock4u_sse2 proc public + + push rsi + push rdi + + mov rdi, rcx + mov rsi, rdx + mov rcx, 2 + + mov eax, 0f0f0f0fh + movd xmm7, eax + pshufd xmm7, xmm7, 0 + + align 16 +@@: + ; col 0, 2 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea rsi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm1, xmm1, 0b1h + pshuflw xmm3, xmm3, 0b1h + pshufhw xmm1, xmm1, 0b1h + pshufhw xmm3, xmm3, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*0], xmm0 + movdqa [rdi+16*1], xmm1 + movdqa [rdi+16*2], xmm4 + movdqa [rdi+16*3], xmm3 + + ; col 1, 3 + + movdqu xmm0, [rsi] + movdqu xmm2, [rsi+r8] + lea esi, [rsi+r8*2] + + movdqu xmm1, [rsi] + movdqu xmm3, [rsi+r8] + lea rsi, [rsi+r8*2] + + pshuflw xmm0, xmm0, 0b1h + pshuflw xmm2, xmm2, 0b1h + pshufhw xmm0, xmm0, 0b1h + pshufhw xmm2, xmm2, 0b1h + + punpcknbl + punpck bw, 0, 2, 4, 6, 1, 3 + punpck bw, 0, 2, 1, 3, 4, 6 + punpck qdq, 0, 4, 2, 6, 1, 3 + + movdqa [rdi+16*4], xmm0 + movdqa [rdi+16*5], xmm1 + movdqa [rdi+16*6], xmm4 + movdqa [rdi+16*7], xmm3 + + add rdi, 128 + + dec rcx + jnz @B + + pop rdi + pop rsi + + ret + +SwizzleBlock4u_sse2 endp + +WriteCLUT_T16_I4_CSM1_sse2 proc public + movdqa xmm0, XMMWORD PTR [rcx] + movdqa xmm1, XMMWORD PTR [rcx+16] + movdqa xmm2, XMMWORD PTR [rcx+32] + movdqa xmm3, XMMWORD PTR [rcx+48] + + ;; rearrange + pshuflw xmm0, xmm0, 088h + pshufhw xmm0, xmm0, 088h + pshuflw xmm1, xmm1, 088h + pshufhw xmm1, xmm1, 088h + pshuflw xmm2, xmm2, 088h + pshufhw xmm2, xmm2, 088h + pshuflw xmm3, xmm3, 088h + pshufhw xmm3, xmm3, 088h + + shufps xmm0, xmm1, 088h + shufps xmm2, xmm3, 088h + + pshufd xmm0, xmm0, 0d8h + pshufd xmm2, xmm2, 0d8h + + pxor xmm6, xmm6 + mov rax, offset s_clut16mask + + test rdx, 15 + jnz WriteUnaligned + + movdqa xmm7, XMMWORD PTR [rax] ;; saves upper 16 bits + + ;; have to save interlaced with the old data + movdqa xmm4, [rdx] + movdqa xmm5, [rdx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 ;; lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0e4h ;; upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + + movdqa [rdx], xmm0 + movdqa [rdx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [rdx+16] + pand xmm5, [rdx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [rdx+16], xmm2 + movdqa [rdx+48], xmm3 + jmp WriteCLUT_T16_I4_CSM1_End + +WriteUnaligned: + ;; rdx is offset by 2 + sub rdx, 2 + + movdqa xmm7, XMMWORD PTR [rax+16] ;; saves lower 16 bits + + ;; have to save interlaced with the old data + movdqa xmm4, [rdx] + movdqa xmm5, [rdx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 ;; lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0e4h ;; upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + pslld xmm0, 16 + pslld xmm1, 16 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + pslld xmm2, 16 + pslld xmm3, 16 + + movdqa [rdx], xmm0 + movdqa [rdx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [rdx+16] + pand xmm5, [rdx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [rdx+16], xmm2 + movdqa [rdx+48], xmm3 +WriteCLUT_T16_I4_CSM1_End: + ret + +WriteCLUT_T16_I4_CSM1_sse2 endp + +end \ No newline at end of file diff --git a/plugins/zerogs/opengl/x86.cpp b/plugins/zerogs/opengl/x86.cpp new file mode 100644 index 0000000000..cb33e0302c --- /dev/null +++ b/plugins/zerogs/opengl/x86.cpp @@ -0,0 +1,571 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "GS.h" +#include "Mem.h" +#include "x86.h" + +#if defined(ZEROGS_SSE2) && (defined(_WIN32)||defined(__x86_64__)) +#include +#include +#endif + +// swizzling + +void __fastcall SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask) +{ + u32* d = &g_columnTable32[0][0]; + + if(WriteMask == 0xffffffff) + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = ((u32*)src)[i]; + } + else + { + for(int j = 0; j < 8; j++, d += 8, src += srcpitch) + for(int i = 0; i < 8; i++) + ((u32*)dst)[d[i]] = (((u32*)dst)[d[i]] & ~WriteMask) | (((u32*)src)[i] & WriteMask); + } +} + +void __fastcall SwizzleBlock16_c(u8* dst, u8* src, int srcpitch) +{ + u32* d = &g_columnTable16[0][0]; + + for(int j = 0; j < 8; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + ((u16*)dst)[d[i]] = ((u16*)src)[i]; +} + +void __fastcall SwizzleBlock8_c(u8* dst, u8* src, int srcpitch) +{ + u32* d = &g_columnTable8[0][0]; + + for(int j = 0; j < 16; j++, d += 16, src += srcpitch) + for(int i = 0; i < 16; i++) + dst[d[i]] = src[i]; +} + +void __fastcall SwizzleBlock4_c(u8* dst, u8* src, int srcpitch) +{ + u32* d = &g_columnTable4[0][0]; + + for(int j = 0; j < 16; j++, d += 32, src += srcpitch) + { + for(int i = 0; i < 32; i++) + { + u32 addr = d[i]; + u8 c = (src[i>>1] >> ((i&1) << 2)) & 0x0f; + u32 shift = (addr&1) << 2; + dst[addr >> 1] = (dst[addr >> 1] & (0xf0 >> shift)) | (c << shift); + } + } +} + +#define _FrameSwizzleBlock(type, transfer, transfer16, incsrc) \ +/* FrameSwizzleBlock32 */ \ +void __fastcall FrameSwizzleBlock32##type##c(u32* dst, u32* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + \ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = (transfer); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + dst[d[j]] = ((transfer)&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* FrameSwizzleBlock16 */ \ +void __fastcall FrameSwizzleBlock16##type##c(u16* dst, u32* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( WriteMask == 0xffff ) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + dst[d[j]] = RGBA32to16(temp); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + u32 temp = (transfer); \ + u32 dsrc = RGBA32to16(temp); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ +} \ +\ +/* Frame16SwizzleBlock32 */ \ +void __fastcall Frame16SwizzleBlock32##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ +\ + if( WriteMask == 0xffffffff ) { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ +\ +/* Frame16SwizzleBlock32Z */ \ +void __fastcall Frame16SwizzleBlock32Z##type##c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable32[0][0]; \ + if( WriteMask == 0xffffffff ) { /* breaks KH text if not checked */ \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 8) { \ + for(int j = 0; j < 8; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB_Z(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16 */ \ +void __fastcall Frame16SwizzleBlock16##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + if( (WriteMask&0xfff8f8f8) == 0xfff8f8f8) { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + else { \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + u32 dsrc = Float16ToARGB16(dsrc16); \ + dst[d[j]] = (dsrc&WriteMask)|(dst[d[j]]&~WriteMask); \ + } \ + src += srcpitch << incsrc; \ + } \ + } \ + } \ + \ + /* Frame16SwizzleBlock16Z */ \ +void __fastcall Frame16SwizzleBlock16Z##type##c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask) \ +{ \ + u32* d = &g_columnTable16[0][0]; \ + \ + for(int i = 0; i < 8; ++i, d += 16) { \ + for(int j = 0; j < 16; ++j) { \ + Vector_16F dsrc16 = (transfer16); \ + dst[d[j]] = Float16ToARGB16_Z(dsrc16); \ + } \ + src += srcpitch << incsrc; \ + } \ +} \ + +_FrameSwizzleBlock(_, src[j], src[j], 0); +_FrameSwizzleBlock(A2_, (src[2*j]+src[2*j+1])>>1, src[2*j], 0); +_FrameSwizzleBlock(A4_, (src[2*j]+src[2*j+1]+src[2*j+srcpitch]+src[2*j+srcpitch+1])>>2, src[2*j], 1); + +#ifdef ZEROGS_SSE2 + +//void __fastcall WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut) +//{ +// __asm { +// mov eax, vm +// mov ecx, clut +// mov edx, 8 +// } +// +//Extract32x2: +// __asm { +// movdqa xmm0, qword ptr [eax] +// movdqa xmm1, qword ptr [eax+16] +// movdqa xmm2, qword ptr [eax+32] +// movdqa xmm3, qword ptr [eax+48] +// +// // rearrange +// pshuflw xmm0, xmm0, 0xd8 +// pshufhw xmm0, xmm0, 0xd8 +// pshuflw xmm1, xmm1, 0xd8 +// pshufhw xmm1, xmm1, 0xd8 +// pshuflw xmm2, xmm2, 0xd8 +// pshufhw xmm2, xmm2, 0xd8 +// pshuflw xmm3, xmm3, 0xd8 +// pshufhw xmm3, xmm3, 0xd8 +// +// movdqa xmm4, xmm0 +// movdqa xmm6, xmm2 +// +// shufps xmm0, xmm1, 0x88 +// shufps xmm2, xmm3, 0x88 +// +// shufps xmm4, xmm1, 0xdd +// shufps xmm6, xmm3, 0xdd +// +// pshufd xmm0, xmm0, 0xd8 +// pshufd xmm2, xmm2, 0xd8 +// pshufd xmm4, xmm4, 0xd8 +// pshufd xmm6, xmm6, 0xd8 +// +// // left column +// movhlps xmm1, xmm0 +// movlhps xmm0, xmm2 +// //movdqa xmm7, [ecx] +// +// movdqa [ecx], xmm0 +// shufps xmm1, xmm2, 0xe4 +// movdqa [ecx+16], xmm1 +// +// // right column +// movhlps xmm3, xmm4 +// movlhps xmm4, xmm6 +// movdqa [ecx+32], xmm4 +// shufps xmm3, xmm6, 0xe4 +// movdqa [ecx+48], xmm3 +// +// add eax, 16*4 +// add ecx, 16*8 +// sub edx, 1 +// cmp edx, 0 +// jne Extract32x2 +// } +//} + +#if (defined(_WIN32)||defined(__x86_64__)) + +extern "C" void __fastcall WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + for(int j = 0; j < 64; j += 32, src += 32, dst += 32) + { + for(int i = 0; i < 16; i += 4) + { + __m128i r0 = _mm_load_si128(&src[i+0]); + __m128i r1 = _mm_load_si128(&src[i+1]); + __m128i r2 = _mm_load_si128(&src[i+2]); + __m128i r3 = _mm_load_si128(&src[i+3]); + + _mm_store_si128(&dst[i*2+0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[i*2+2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+3], _mm_unpackhi_epi64(r2, r3)); + + __m128i r4 = _mm_load_si128(&src[i+0+16]); + __m128i r5 = _mm_load_si128(&src[i+1+16]); + __m128i r6 = _mm_load_si128(&src[i+2+16]); + __m128i r7 = _mm_load_si128(&src[i+3+16]); + + _mm_store_si128(&dst[i*2+4], _mm_unpacklo_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+5], _mm_unpacklo_epi64(r6, r7)); + _mm_store_si128(&dst[i*2+6], _mm_unpackhi_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+7], _mm_unpackhi_epi64(r6, r7)); + } + } +} + +extern "C" void __fastcall WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut) +{ + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + __m128i r0 = _mm_load_si128(&src[0]); + __m128i r1 = _mm_load_si128(&src[1]); + __m128i r2 = _mm_load_si128(&src[2]); + __m128i r3 = _mm_load_si128(&src[3]); + + _mm_store_si128(&dst[0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[3], _mm_unpackhi_epi64(r2, r3)); +} +#endif + +#if defined(_MSC_VER) + +extern "C" { +PCSX2_ALIGNED16(int s_clut16mask2[4]) = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; +PCSX2_ALIGNED16(int s_clut16mask[8]) = { 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, + 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}; +} + +#if !defined(__x86_64__) + +extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut) +{ + __asm { + mov eax, vm + mov ecx, clut + movdqa xmm0, qword ptr [eax] + movdqa xmm1, qword ptr [eax+16] + movdqa xmm2, qword ptr [eax+32] + movdqa xmm3, qword ptr [eax+48] + + // rearrange + pshuflw xmm0, xmm0, 0x88 + pshufhw xmm0, xmm0, 0x88 + pshuflw xmm1, xmm1, 0x88 + pshufhw xmm1, xmm1, 0x88 + pshuflw xmm2, xmm2, 0x88 + pshufhw xmm2, xmm2, 0x88 + pshuflw xmm3, xmm3, 0x88 + pshufhw xmm3, xmm3, 0x88 + + shufps xmm0, xmm1, 0x88 + shufps xmm2, xmm3, 0x88 + + pshufd xmm0, xmm0, 0xd8 + pshufd xmm2, xmm2, 0xd8 + + pxor xmm6, xmm6 + + test ecx, 15 + jnz WriteUnaligned + + movdqa xmm7, s_clut16mask // saves upper 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 + jmp End + +WriteUnaligned: + // ecx is offset by 2 + sub ecx, 2 + + movdqa xmm7, s_clut16mask2 // saves lower 16 bits + + // have to save interlaced with the old data + movdqa xmm4, [ecx] + movdqa xmm5, [ecx+32] + movhlps xmm1, xmm0 + movlhps xmm0, xmm2 // lower 8 colors + + pand xmm4, xmm7 + pand xmm5, xmm7 + + shufps xmm1, xmm2, 0xe4 // upper 8 colors + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + + punpcklwd xmm0, xmm6 + punpcklwd xmm1, xmm6 + pslld xmm0, 16 + pslld xmm1, 16 + por xmm0, xmm4 + por xmm1, xmm5 + + punpckhwd xmm2, xmm6 + punpckhwd xmm3, xmm6 + pslld xmm2, 16 + pslld xmm3, 16 + + movdqa [ecx], xmm0 + movdqa [ecx+32], xmm1 + + movdqa xmm5, xmm7 + pand xmm7, [ecx+16] + pand xmm5, [ecx+48] + + por xmm2, xmm7 + por xmm3, xmm5 + + movdqa [ecx+16], xmm2 + movdqa [ecx+48], xmm3 +End: + } +} +#endif // __x86_64__ +#endif // _MSC_VER + +#endif // ZEROGS_SSE2 + +void __fastcall WriteCLUT_T16_I8_CSM1_c(u32* _vm, u32* _clut) +{ + const static u32 map[] = + { + 0, 2, 8, 10, 16, 18, 24, 26, + 4, 6, 12, 14, 20, 22, 28, 30, + 1, 3, 9, 11, 17, 19, 25, 27, + 5, 7, 13, 15, 21, 23, 29, 31 + }; + + u16* vm = (u16*)_vm; + u16* clut = (u16*)_clut; + + int left = ((u32)(uptr)clut&2) ? 512 : 512-(((u32)(uptr)clut)&0x3ff)/2; + + for(int j = 0; j < 8; j++, vm += 32, clut += 64, left -= 32) + { + if(left == 32) { + assert( left == 32 ); + for(int i = 0; i < 16; i++) + clut[2*i] = vm[map[i]]; + + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + + for(int i = 16; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + else { + if( left == 0 ) { + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + left = -1; + } + + for(int i = 0; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + } +} + +void __fastcall WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + for(int j = 0; j < 2; j++, src += 32) { + for(int i = 0; i < 4; i++, dst+=16, src+=8) + { + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; + + dst[8] = src[32]; + dst[9] = src[32+2]; + dst[10] = src[32+4]; + dst[11] = src[32+6]; + dst[12] = src[32+1]; + dst[13] = src[32+3]; + dst[14] = src[32+5]; + dst[15] = src[32+7]; + } + } +} + +void __fastcall WriteCLUT_T16_I4_CSM1_c(u32* _vm, u32* _clut) +{ + u16* dst = (u16*)_clut; + u16* src = (u16*)_vm; + + dst[0] = src[0]; dst[2] = src[2]; + dst[4] = src[8]; dst[6] = src[10]; + dst[8] = src[16]; dst[10] = src[18]; + dst[12] = src[24]; dst[14] = src[26]; + dst[16] = src[4]; dst[18] = src[6]; + dst[20] = src[12]; dst[22] = src[14]; + dst[24] = src[20]; dst[26] = src[22]; + dst[28] = src[28]; dst[30] = src[30]; +} + +void __fastcall WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)clut; + + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; +} diff --git a/plugins/zerogs/opengl/x86.h b/plugins/zerogs/opengl/x86.h new file mode 100644 index 0000000000..94cb01e3e3 --- /dev/null +++ b/plugins/zerogs/opengl/x86.h @@ -0,0 +1,182 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 Gabest/zerofrog@gmail.com + * http://www.gabest.org + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifndef ZEROGS_X86 +#define ZEROGS_X86 + +#include "GS.h" + +extern "C" void __fastcall SwizzleBlock32_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); +extern "C" void __fastcall SwizzleBlock16_sse2(u8* dst, u8* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock8_sse2(u8* dst, u8* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock4_sse2(u8* dst, u8* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock32u_sse2(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); +extern "C" void __fastcall SwizzleBlock16u_sse2(u8* dst, u8* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock8u_sse2(u8* dst, u8* src, int srcpitch); +extern "C" void __fastcall SwizzleBlock4u_sse2(u8* dst, u8* src, int srcpitch); + +// frame swizzling + +// no AA +extern "C" void __fastcall FrameSwizzleBlock32_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall FrameSwizzleBlock16_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32Z_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16Z_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +// AA 2x +extern "C" void __fastcall FrameSwizzleBlock32A2_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall FrameSwizzleBlock16A2_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32A2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32ZA2_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16A2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16ZA2_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +// AA 4x +extern "C" void __fastcall FrameSwizzleBlock32A4_sse2(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall FrameSwizzleBlock16A4_sse2(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32A4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock32ZA4_sse2(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16A4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern "C" void __fastcall Frame16SwizzleBlock16ZA4_sse2(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +extern void __fastcall SwizzleBlock32_c(u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); +extern void __fastcall SwizzleBlock16_c(u8* dst, u8* src, int srcpitch); +extern void __fastcall SwizzleBlock8_c(u8* dst, u8* src, int srcpitch); +extern void __fastcall SwizzleBlock4_c(u8* dst, u8* src, int srcpitch); + +// no AA +extern void __fastcall FrameSwizzleBlock32_c(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall FrameSwizzleBlock16_c(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32Z_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16Z_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +// AA 2x +extern void __fastcall FrameSwizzleBlock32A2_c(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall FrameSwizzleBlock16A2_c(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32A2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32ZA2_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16A2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16ZA2_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +// AA 4x +extern void __fastcall FrameSwizzleBlock32A4_c(u32* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall FrameSwizzleBlock16A4_c(u16* dst, u32* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32A4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock32ZA4_c(u32* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16A4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); +extern void __fastcall Frame16SwizzleBlock16ZA4_c(u16* dst, Vector_16F* src, int srcpitch, u32 WriteMask); + +extern void __fastcall SwizzleColumn32_c(int y, u8* dst, u8* src, int srcpitch, u32 WriteMask = 0xffffffff); +extern void __fastcall SwizzleColumn16_c(int y, u8* dst, u8* src, int srcpitch); +extern void __fastcall SwizzleColumn8_c(int y, u8* dst, u8* src, int srcpitch); +extern void __fastcall SwizzleColumn4_c(int y, u8* dst, u8* src, int srcpitch); + +extern "C" void __fastcall WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut); +extern "C" void __fastcall WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut); +extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut); +extern "C" void __fastcall WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut); +extern void __fastcall WriteCLUT_T16_I8_CSM1_c(u32* vm, u32* clut); +extern void __fastcall WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut); + +extern void __fastcall WriteCLUT_T16_I4_CSM1_c(u32* vm, u32* clut); +extern void __fastcall WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut); + +#ifdef ZEROGS_SSE2 + +#define SwizzleBlock32 SwizzleBlock32_sse2 +#define SwizzleBlock16 SwizzleBlock16_sse2 +#define SwizzleBlock8 SwizzleBlock8_sse2 +#define SwizzleBlock4 SwizzleBlock4_sse2 +#define SwizzleBlock32u SwizzleBlock32u_sse2 +#define SwizzleBlock16u SwizzleBlock16u_sse2 +#define SwizzleBlock8u SwizzleBlock8u_sse2 +#define SwizzleBlock4u SwizzleBlock4u_sse2 + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_sse2 +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_sse2 +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_sse2 +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_sse2 + +#else + +#define SwizzleBlock32 SwizzleBlock32_c +#define SwizzleBlock16 SwizzleBlock16_c +#define SwizzleBlock8 SwizzleBlock8_c +#define SwizzleBlock4 SwizzleBlock4_c +#define SwizzleBlock32u SwizzleBlock32_c +#define SwizzleBlock16u SwizzleBlock16_c +#define SwizzleBlock8u SwizzleBlock8_c +#define SwizzleBlock4u SwizzleBlock4_c + +#define FrameSwizzleBlock32 FrameSwizzleBlock32_c +#define FrameSwizzleBlock16 FrameSwizzleBlock16_c +#define Frame16SwizzleBlock32 Frame16SwizzleBlock32_c +#define Frame16SwizzleBlock32Z Frame16SwizzleBlock32Z_c +#define Frame16SwizzleBlock16 Frame16SwizzleBlock16_c +#define Frame16SwizzleBlock16Z Frame16SwizzleBlock16Z_c + +#define FrameSwizzleBlock32A2 FrameSwizzleBlock32A2_c +#define FrameSwizzleBlock16A2 FrameSwizzleBlock16A2_c +#define Frame16SwizzleBlock32A2 Frame16SwizzleBlock32A2_c +#define Frame16SwizzleBlock32ZA2 Frame16SwizzleBlock32ZA2_c +#define Frame16SwizzleBlock16A2 Frame16SwizzleBlock16A2_c +#define Frame16SwizzleBlock16ZA2 Frame16SwizzleBlock16ZA2_c + +#define FrameSwizzleBlock32A4 FrameSwizzleBlock32A4_c +#define FrameSwizzleBlock16A4 FrameSwizzleBlock16A4_c +#define Frame16SwizzleBlock32A4 Frame16SwizzleBlock32A4_c +#define Frame16SwizzleBlock32ZA4 Frame16SwizzleBlock32ZA4_c +#define Frame16SwizzleBlock16A4 Frame16SwizzleBlock16A4_c +#define Frame16SwizzleBlock16ZA4 Frame16SwizzleBlock16ZA4_c + +#define WriteCLUT_T16_I8_CSM1 WriteCLUT_T16_I8_CSM1_c +#define WriteCLUT_T32_I8_CSM1 WriteCLUT_T32_I8_CSM1_c +#define WriteCLUT_T16_I4_CSM1 WriteCLUT_T16_I4_CSM1_c +#define WriteCLUT_T32_I4_CSM1 WriteCLUT_T32_I4_CSM1_c + +#endif + +#endif diff --git a/plugins/zerogs/opengl/zerogs.cpp b/plugins/zerogs/opengl/zerogs.cpp new file mode 100644 index 0000000000..4bbfc5fd2e --- /dev/null +++ b/plugins/zerogs/opengl/zerogs.cpp @@ -0,0 +1,6016 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 + */ + +#if defined(_WIN32) +#include +#include + +#include "resource.h" +#endif + +#include + +#include +#include +#include +#include + +#include "GS.h" +#include "Mem.h" +#include "x86.h" +#include "zerogs.h" +#include "zpipe.h" + +#include "ZeroGSShaders/zerogsshaders.h" +#include "targets.h" +#include "rasterfont.h" // simple font + +#define VB_BUFFERSIZE 0x400 +#define VB_NUMBUFFERS 512 +#define SIZEOF_VB sizeof(ZeroGS::VB)//((u32)((u8*)&vb[0].buffers-(u8*)&vb[0])) + +#define MINMAX_SHIFT 3 +#define MAX_ACTIVECLUTS 16 + +#define ZEROGS_SAVEVER 0xaa000005 + +#define STENCIL_ALPHABIT 1 // if set, dest alpha >= 0x80 +#define STENCIL_PIXELWRITE 2 // if set, pixel just written (reset after every Flush) +#define STENCIL_FBA 4 // if set, just written pixel's alpha >= 0 (reset after every Flush) +#define STENCIL_SPECIAL 8 // if set, indicates that pixel passed its alpha test (reset after every Flush) +//#define STENCIL_PBE 16 +#define STENCIL_CLEAR (2|4|8|16) + +#define VBSAVELIMIT ((u32)((u8*)&vb[0].nNextFrameHeight-(u8*)&vb[0])) + +using namespace ZeroGS; + +extern u32 g_nGenVars, g_nTexVars, g_nAlphaVars, g_nResolve; +extern char *libraryName; +extern int g_nFrame, g_nRealFrame; +extern float fFPS; +extern unsigned char zgsrevision, zgsbuild, zgsminor; + +BOOL g_bDisplayMsg = 1; + +#ifdef _WIN32 +HDC hDC=NULL; // Private GDI Device Context +HGLRC hRC=NULL; // Permanent Rendering Context +#endif + +BOOL g_bCRTCBilinear = TRUE; +BOOL g_bSaveFlushedFrame = 0; +BOOL g_bIsLost = 0; +int g_nFrameRender = 10; +int g_nFramesSkipped = 0; + +#ifdef RELEASE_TO_PUBLIC + +#define INC_GENVARS() +#define INC_TEXVARS() +#define INC_ALPHAVARS() +#define INC_RESOLVE() + +#define g_bUpdateEffect 0 +#define g_bSaveTex 0 +#define g_bSaveTrans 0 +#define g_bSaveFrame 0 +#define g_bSaveFinalFrame 0 +#define g_bSaveResolved 0 + +#else + +#define INC_GENVARS() ++g_nGenVars +#define INC_TEXVARS() ++g_nTexVars +#define INC_ALPHAVARS() ++g_nAlphaVars +#define INC_RESOLVE() ++g_nResolve + +BOOL g_bSaveTrans = 0; +BOOL g_bUpdateEffect = 0; +BOOL g_bSaveTex = 0; // saves the curent texture +BOOL g_bSaveFrame = 0; // saves the current psurfTarget +BOOL g_bSaveFinalFrame = 0; // saves the input to the CRTC +BOOL g_bSaveResolved = 0; + +#ifdef _WIN32 +//#define EFFECT_NAME "f:\\ps2dev\\svn\\pcsx2\\ZeroGS\\opengl\\" +char* EFFECT_DIR = "C:\\programming\\ps2dev\\zerogs\\opengl\\"; +char* EFFECT_NAME = "C:\\programming\\ps2dev\\zerogs\\opengl\\ps2hw.fx"; +#else +char EFFECT_DIR[255] = "~/pcsx2/plugins/gs/zerogs/opengl/"; +char EFFECT_NAME[255] = "~/pcsx2/plugins/gs/zerogs/opengl/ps2hw.fx"; +#endif + +#endif + +BOOL g_bUpdateStencil = 1; // only needed for dest alpha test (unfortunately, it has to be on all the time) + +#define DRAW() glDrawArrays(primtype[curvb.curprim.prim], 0, curvb.nCount) + +#define GL_BLEND_RGB(src, dst) { \ + s_srcrgb = src; \ + s_dstrgb = dst; \ + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ +} + +#define GL_BLEND_ALPHA(src, dst) { \ + s_srcalpha = src; \ + s_dstalpha = dst; \ + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ +} + +#define GL_BLEND_ALL(srcrgb, dstrgb, srcalpha, dstalpha) { \ + s_srcrgb = srcrgb; \ + s_dstrgb = dstrgb; \ + s_srcalpha = srcalpha; \ + s_dstalpha = dstalpha; \ + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); \ +} + +#define GL_BLEND_SET() zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha) + +#define GL_ZTEST(enable) { \ + if( enable ) glEnable(GL_DEPTH_TEST); \ + else glDisable(GL_DEPTH_TEST); \ +} + +#define GL_ALPHATEST(enable) { \ + if( enable ) glEnable(GL_ALPHA_TEST); \ + else glDisable(GL_ALPHA_TEST); \ +} + +#define GL_BLENDEQ_RGB(eq) { \ + s_rgbeq = eq; \ + zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); \ +} + +#define GL_BLENDEQ_ALPHA(eq) { \ + s_alphaeq = eq; \ + zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); \ +} + +#define GL_STENCILFUNC(func, ref, mask) { \ + s_stencilfunc = func; \ + s_stencilref = ref; \ + s_stencilmask = mask; \ + glStencilFunc(func, ref, mask); \ +} + +#define GL_STENCILFUNC_SET() glStencilFunc(s_stencilfunc, s_stencilref, s_stencilmask) + +#define COLORMASK_RED 1 +#define COLORMASK_GREEN 2 +#define COLORMASK_BLUE 4 +#define COLORMASK_ALPHA 8 +#define GL_COLORMASK(mask) glColorMask(!!((mask)&COLORMASK_RED), !!((mask)&COLORMASK_GREEN), !!((mask)&COLORMASK_BLUE), !!((mask)&COLORMASK_ALPHA)) + +typedef void (APIENTRYP _PFNSWAPINTERVAL) (int); + +extern int s_frameskipping; + +static u32 g_SaveFrameNum = 0; +BOOL g_bMakeSnapshot = 0; +string strSnapshot; + +int GPU_TEXWIDTH = 512; +float g_fiGPU_TEXWIDTH = 1/512.0f; + +int g_MaxTexWidth = 4096, g_MaxTexHeight = 4096; +CGprogram g_vsprog = 0, g_psprog = 0; +// AVI Capture +static int s_aviinit = 0; +static int s_avicapturing = 0; + +inline u32 FtoDW(float f) { return (*((u32*)&f)); } + +float g_fBlockMult = 1; +static int s_nFullscreen = 0; +int g_nDepthUpdateCount = 0; +int g_nDepthBias = 0; + +// local alpha blending settings +static GLenum s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha; // set by zgsBlendFuncSeparateEXT +static GLenum s_rgbeq, s_alphaeq; // set by zgsBlendEquationSeparateEXT +static u32 s_stencilfunc, s_stencilref, s_stencilmask; +static GLenum s_drawbuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT }; + +#ifdef _WIN32 +extern HINSTANCE hInst; + +void (__stdcall *zgsBlendEquationSeparateEXT)(GLenum, GLenum) = NULL; +void (__stdcall *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum) = NULL; +#else +void (APIENTRY *zgsBlendEquationSeparateEXT)(GLenum, GLenum) = NULL; +void (APIENTRY *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum) = NULL; +#endif + +GLenum g_internalFloatFmt = GL_ALPHA_FLOAT32_ATI; +GLenum g_internalRGBAFloatFmt = GL_RGBA_FLOAT32_ATI; +GLenum g_internalRGBAFloat16Fmt = GL_RGBA_FLOAT16_ATI; + +// Consts +static const GLenum primtype[8] = { GL_POINTS, GL_LINES, GL_LINES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, 0xffffffff }; +static const u32 blendalpha[3] = { GL_SRC_ALPHA, GL_DST_ALPHA, GL_CONSTANT_COLOR_EXT }; +static const u32 blendinvalpha[3] = { GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_CONSTANT_COLOR_EXT }; + +static const int PRIMMASK = 0x0e; // for now ignore 0x10 (AA) + +static const u32 g_dwAlphaCmp[] = { GL_NEVER, GL_ALWAYS, GL_LESS, GL_LEQUAL, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL }; + +// used for afail case +static const u32 g_dwReverseAlphaCmp[] = { GL_ALWAYS, GL_NEVER, GL_GEQUAL, GL_GREATER, GL_NOTEQUAL, GL_LESS, GL_LEQUAL, GL_EQUAL }; + +static const u32 g_dwZCmp[] = { GL_NEVER, GL_ALWAYS, GL_GEQUAL, GL_GREATER }; + +PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL; +PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL; +PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL; +PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL; +PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL; +PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL; +PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL; +PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL; +PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL; +PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL; +PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL; +PFNGLDRAWBUFFERSPROC glDrawBuffers = NULL; + +///////////////////// +// graphics resources +static map mapGLExtensions; +RasterFont* font_p = NULL; +CGprofile cgvProf, cgfProf; +static CGprogram pvs[16] = {NULL}; +static FRAGMENTSHADER ppsRegular[4], ppsTexture[NUM_SHADERS]; +static FRAGMENTSHADER ppsCRTC[2], ppsCRTC24[2], ppsCRTCTarg[2]; +CGparameter g_vparamPosXY[2] = {0}, g_fparamFogColor = 0; + +int g_nPixelShaderVer = 0; // default + +static u8* s_lpShaderResources = NULL; +static map mapShaderResources; + +u32 s_uFramebuffer = 0; +u32 s_ptexCurSet[2] = {0}; + +#define s_bForceTexFlush 1 +static u32 s_ptexNextSet[2] = {0}; + +u32 ptexBlocks = 0, ptexConv16to32 = 0; // holds information on block tiling +u32 ptexBilinearBlocks = 0; +u32 ptexConv32to16 = 0; +static u32 s_ptexInterlace = 0; // holds interlace fields +static int s_nInterlaceTexWidth = 0; // width of texture +static vector s_vecTempTextures; // temporary textures, released at the end of every frame + +static BOOL s_bTexFlush = FALSE; +static u32 ptexLogo = 0; +static int nLogoWidth, nLogoHeight; +static BOOL s_bWriteDepth = FALSE; +static BOOL s_bDestAlphaTest = FALSE; +static int s_nLastResolveReset = 0; +static int s_nResolveCounts[30] = {0}; // resolve counts for last 30 frames +static int s_nCurResolveIndex = 0; +int s_nResolved = 0; // number of targets resolved this frame +int g_nDepthUsed = 0; // ffx2 pal movies +static int s_nWriteDepthCount = 0; +static int s_nWireframeCount = 0; +static int s_nWriteDestAlphaTest = 0; + +//////////////////// +// State parameters +static float fiRendWidth, fiRendHeight; + +static Vector vAlphaBlendColor; // used for GPU_COLOR + +static u8 bNeedBlendFactorInAlpha; // set if the output source alpha is different from the real source alpha (only when blend factor > 0x80) +static u32 s_dwColorWrite = 0xf; // the color write mask of the current target + +BOOL g_bDisplayFPS = FALSE; + +union { + struct { + u8 _bNeedAlphaColor; // set if vAlphaBlendColor needs to be set + u8 _b2XAlphaTest; // Only valid when bNeedAlphaColor is set. if 1st bit set set, double all alpha testing values + // otherwise alpha testing needs to be done separately. + u8 _bDestAlphaColor; // set to 1 if blending with dest color (process only one tri at a time). If 2, dest alpha is always 1. + u8 _bAlphaClamping; // if first bit is set, do min; if second bit, do max + }; + u32 _bAlphaState; +} g_vars; + +//#define bNeedAlphaColor g_vars._bNeedAlphaColor +#define b2XAlphaTest g_vars._b2XAlphaTest +#define bDestAlphaColor g_vars._bDestAlphaColor +#define bAlphaClamping g_vars._bAlphaClamping + +int g_PrevBitwiseTexX = -1, g_PrevBitwiseTexY = -1; // textures stored in SAMP_BITWISEANDX and SAMP_BITWISEANDY + +// stores the buffers for the last RenderCRTC +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +static alphaInfo s_alphaInfo; + +CGcontext g_cgcontext; +static int nBackbufferWidth, nBackbufferHeight; + +u8* g_pbyGSMemory = NULL; // 4Mb GS system mem +u8* g_pbyGSClut = NULL; + +namespace ZeroGS +{ + VB vb[2]; + float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + + GLuint vboRect = 0; + vector g_vboBuffers; // VBOs for all drawing commands + int g_nCurVBOIndex = 0; + + u8 s_AAx = 0, s_AAy = 0; // if AAy is set, then AAx has to be set + RenderFormatType g_RenderFormatType = RFT_float16; + int icurctx = -1; + + Vector g_vdepth = Vector(256.0f*65536.0f, 65536.0f, 256.0f, 65536.0f*65536.0f); + + VERTEXSHADER pvsBitBlt; + FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; + FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; + + extern CRangeManager s_RangeMngr; // manages overwritten memory + void FlushTransferRanges(const tex0Info* ptex); + + RenderFormatType GetRenderFormat() { return g_RenderFormatType; } + GLenum GetRenderTargetFormat() { return GetRenderFormat()==RFT_byte8?4:g_internalRGBAFloat16Fmt; } + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + bool LoadEffects(); + bool LoadExtraEffects(); + FRAGMENTSHADER* LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed); + + static int s_nNewWidth = -1, s_nNewHeight = -1; + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + + void ProcessMessages(); + void RenderCustom(float fAlpha); // intro anim + + struct MESSAGE + { + MESSAGE() {} + MESSAGE(const char* p, u32 dw) { strcpy(str, p); dwTimeStamp = dw; } + char str[255]; + u32 dwTimeStamp; + }; + + static list listMsgs; + + /////////////////////// + // Method Prototypes // + /////////////////////// + + void AdjustTransToAspect(Vector& v, int dispwidth, int dispheight); + + void KickPoint(); + void KickLine(); + void KickTriangle(); + void KickTriangleFan(); + void KickSprite(); + void KickDummy(); + + __forceinline void SetContextTarget(int context); + + // use to update the state + void SetTexVariables(int context, FRAGMENTSHADER* pfragment, int settexint); + void SetAlphaVariables(const alphaInfo& ainfo); + void ResetAlphaVariables(); + + __forceinline void SetAlphaTestInt(pixTest curtest); + + __forceinline void RenderAlphaTest(const VB& curvb, CGparameter sOneColor); + __forceinline void RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting); + __forceinline void ProcessStencil(const VB& curvb); + __forceinline void RenderFBA(const VB& curvb, CGparameter sOneColor); + __forceinline void ProcessFBA(const VB& curvb, CGparameter sOneColor); + + void ResolveInRange(int start, int end); + + void ExtWrite(); + + __forceinline u32 CreateInterlaceTex(int width) { + if( width == s_nInterlaceTexWidth && s_ptexInterlace != 0 ) return s_ptexInterlace; + + SAFE_RELEASE_TEX(s_ptexInterlace); + s_nInterlaceTexWidth = width; + + vector data(width); + for(int i = 0; i < width; ++i) data[i] = (i&1) ? 0xffffffff : 0; + + glGenTextures(1, &s_ptexInterlace); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, s_ptexInterlace); + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, width, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + GL_REPORT_ERRORD(); + return s_ptexInterlace; + } + + void ResetRenderTarget(int index) { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+index, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); + } + + DrawFn drawfn[8] = { KickDummy, KickDummy, KickDummy, KickDummy, + KickDummy, KickDummy, KickDummy, KickDummy }; + +}; // end namespace + +/////////////////// +// Context State // +/////////////////// +ZeroGS::VB::VB() +{ + memset(this, 0, SIZEOF_VB); + tex0.tw = 1; + tex0.th = 1; +} + +ZeroGS::VB::~VB() +{ + Destroy(); +} + +void ZeroGS::VB::Destroy() +{ + _aligned_free(pBufferData); pBufferData = NULL; nNumVertices = 0; + + prndr = NULL; + pdepth = NULL; +} + +bool ZeroGS::VB::CheckPrim() +{ + if( (PRIMMASK & prim->_val) != (PRIMMASK & curprim._val) || primtype[prim->prim] != primtype[curprim.prim] ) + return nCount > 0; + + return false; +} + +// upper bound on max possible height +#define GET_MAXHEIGHT(fbp, fbw, psm) ((((0x00100000-64*(fbp))/(fbw))&~0x1f)<<((psm&2)?1:0)) + +#include +static int maxmin = 608; +//static set s_setFBP[2]; // previous frame/zbuf pointers for the last 2 frames +//static int s_nCurFBPSet = 0; +//static map s_mapFrameHeights[2]; +//static int s_nCurFrameMap = 0; + +// a lot of times, target is too big and overwrites the texture using, if tbp != 0, use it to bound +void ZeroGS::VB::CheckFrame(int tbp) +{ + static int bChanged; + if( bNeedZCheck ) { + PRIM_LOG("zbuf_%d: zbp=0x%x psm=0x%x, zmsk=%d\n", ictx, zbuf.zbp, zbuf.psm, zbuf.zmsk); + //zbuf = *zb; + } + + bChanged = 0; + + if( bNeedFrameCheck ) { + + int maxpos = 0x00100000; + + // important to set before calling GetTarg + bNeedFrameCheck = 0; + bNeedZCheck = 0; + + // add constraints of other targets + if( gsfb.fbw > 0 ) { + maxpos = 0x00100000-64*gsfb.fbp; + + // make sure texture is far away from tbp + if( gsfb.fbp < tbp && gsfb.fbp + 0x2000 < tbp) { + maxpos = min(64*(tbp-gsfb.fbp), maxpos); + } + if( prndr != NULL ) { + // offroad uses 0x80 fbp which messes up targets + if( gsfb.fbp + 0x80 < frame.fbp ) { + // special case when double buffering (hamsterball) + maxpos = min(64*(frame.fbp-gsfb.fbp), maxpos); + } + } + if( zbuf.zbp < tbp && !zbuf.zmsk ) { + maxpos = min((tbp-zbuf.zbp)*((zbuf.psm&2)?128:64), maxpos); + } + + // old caching method + if( gsfb.fbp < zbuf.zbp && !zbuf.zmsk ) { // zmsk necessary for KH movie + int temp = 64*(zbuf.zbp-gsfb.fbp);//min( (0x00100000-64*zbuf.zbp) , 64*(zbuf.zbp-gsfb.fbp) ); + maxpos = min(temp, maxpos); + } + + maxpos /= gsfb.fbw; + if( gsfb.psm & 2 ) maxpos *= 2;; + + maxpos = min(gsfb.fbh, maxpos); + maxpos = min(maxmin, maxpos); + //? atelier iris crashes without it + if( maxpos > 256 ) maxpos &= ~0x1f; + } + else { + ERROR_LOG("render target null, ignoring\n"); + //prndr = NULL; + //pdepth = NULL; + return; + } + + gsfb.psm &= 0xf; // shadow tower + + if( prndr != NULL ) { + + // render target + if( prndr->psm != gsfb.psm ) { + // behavior for dest alpha varies + ResetAlphaVariables(); + } + } + + int fbh = (scissor.y1>>MINMAX_SHIFT)+1; + if( fbh > 2 && (fbh&1) ) fbh -= 1; + + if( !(gsfb.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + fbh = min(fbh, maxpos); + } + + frame = gsfb; +// if (frame.fbw > 1024) frame.fbw = 1024; + +// if( fbh > 256 && (fbh % m_Blocks[gsfb.psm].height) <= 2 ) { +// // dragon ball z +// fbh -= fbh%m_Blocks[gsfb.psm].height; +// } + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) + frame.fbh = fbh; + + if( !(frame.psm&2) ) {//|| !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbh >= 512 ) { + // neopets hack + maxmin = min(maxmin, frame.fbh); + frame.fbh = maxmin; + } + } + + // mgs3 hack to get proper resolution, targets after 0x2000 are usually feedback + /*if( g_MaxRenderedHeight >= 0xe0 && frame.fbp >= 0x2000 ) { + int considerheight = (g_MaxRenderedHeight/8+31)&~31; + if( frame.fbh > considerheight ) + frame.fbh = considerheight; + else if( frame.fbh <= 32 ) + frame.fbh = considerheight; + + if( frame.fbh == considerheight ) { + // stops bad resolves (mgs3) + if( !curprim.abe && (!test.ate || test.atst == 0) ) + s_nResolved |= 0x100; + } + }*/ + + // ffxii hack to stop resolving + if( !(frame.psm&2) || !(g_GameSettings&GAME_FULL16BITRES) ) { + if( frame.fbp >= 0x3000 && fbh >= 0x1a0 ) { + int endfbp = frame.fbp + frame.fbw*fbh/((gsfb.psm&2)?128:64); + + // see if there is a previous render target in the way, reduce + for(CRenderTargetMngr::MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) { + if( itnew->second->fbp > frame.fbp && endfbp > itnew->second->fbp ) { + endfbp = itnew->second->fbp; + } + } + + frame.fbh = (endfbp-frame.fbp)*((gsfb.psm&2)?128:64)/frame.fbw; + } + } + + CRenderTarget* pprevrndr = prndr; + CDepthTarget* pprevdepth = pdepth; + + // reset so that Resolve doesn't call Flush + prndr = NULL; + pdepth = NULL; + + CRenderTarget* pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + + // pnewtarg->fbh >= 0x1c0 needed for ffx + if( pnewtarg->fbh >= 0x1c0 && pnewtarg->fbh > frame.fbh && zbuf.zbp < tbp && !zbuf.zmsk ) { + // check if zbuf is in the way of the texture (suikoden5) + int maxallowedfbh = (tbp-zbuf.zbp)*((zbuf.psm&2)?128:64) / gsfb.fbw; + if( gsfb.psm & 2 ) + maxallowedfbh *= 2; + + if( pnewtarg->fbh > maxallowedfbh+32 ) { // +32 needed for ffx2 + // destroy and recreate + s_RTs.DestroyAllTargs(0, 0x100, pnewtarg->fbw); + pnewtarg = s_RTs.GetTarg(frame, 0, maxmin); + assert( pnewtarg != NULL ); + } + } + + PRIM_LOG("frame_%d: fbp=0x%x fbw=%d fbh=%d(%d) psm=0x%x fbm=0x%x\n", ictx, gsfb.fbp, gsfb.fbw, gsfb.fbh, pnewtarg->fbh, gsfb.psm, gsfb.fbm); + + if( (pprevrndr != pnewtarg) || (prndr != NULL && (prndr->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 1; + + prndr = pnewtarg; + + // update z + frameInfo tempfb; + tempfb.fbw = prndr->fbw; + tempfb.fbp = zbuf.zbp; + tempfb.psm = zbuf.psm; + tempfb.fbh = prndr->fbh; + if( zbuf.psm == 0x31 ) + tempfb.fbm = 0xff000000; + else + tempfb.fbm = 0; + + // check if there is a target that exactly aligns with zbuf (zbuf can be cleared this way, gunbird 2) + //u32 key = zbuf.zbp|(frame.fbw<<16); + //CRenderTargetMngr::MAPTARGETS::iterator it = s_RTs.mapTargets.find(key); +// if( it != s_RTs.mapTargets.end() ) { +//#ifdef _DEBUG +// DEBUG_LOG("zbuf resolve\n"); +//#endif +// if( it->second->status & CRenderTarget::TS_Resolved ) +// it->second->Resolve(); +// } + + GL_REPORT_ERRORD(); + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(tempfb, CRenderTargetMngr::TO_DepthBuffer | + CRenderTargetMngr::TO_StrictHeight|(zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), + GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->fbh ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged |= 2; + + pdepth = pnewdepth; + + if( prndr->status & CRenderTarget::TS_NeedConvert32) { + if( pdepth->pdepth != 0 ) + pdepth->SetDepthStencilSurface(); + prndr->fbh *= 2; + prndr->ConvertTo32(); + prndr->status &= ~CRenderTarget::TS_NeedConvert32; + } + else if( prndr->status & CRenderTarget::TS_NeedConvert16 ) { + if( pdepth->pdepth != 0 ) + pdepth->SetDepthStencilSurface(); + prndr->fbh /= 2; + prndr->ConvertTo16(); + prndr->status &= ~CRenderTarget::TS_NeedConvert16; + } + } + else if( bNeedZCheck ) { + + bNeedZCheck = 0; + CDepthTarget* pprevdepth = pdepth; + pdepth = NULL; + + if( prndr != NULL && gsfb.fbw > 0 ) { + // just z changed + frameInfo f; + f.fbp = zbuf.zbp; + f.fbw = prndr->fbw; + f.fbh = prndr->fbh; + f.psm = zbuf.psm; + + if( zbuf.psm == 0x31 ) f.fbm = 0xff000000; + else f.fbm = 0; + CDepthTarget* pnewdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(zbuf.zbp, gsfb.fbw, 0)); + + assert( pnewdepth != NULL && prndr != NULL ); + assert( pnewdepth->fbh == prndr->fbh ); + + if( (pprevdepth != pnewdepth) || (pdepth != NULL && (pdepth->status & CRenderTarget::TS_NeedUpdate)) ) + bChanged = 2; + + pdepth = pnewdepth; + } + } + + if( prndr != NULL ) SetContextTarget(ictx); +} + +void ZeroGS::VB::FlushTexData() +{ + assert( bNeedTexCheck ); + + bNeedTexCheck = 0; + + u32 psm = (uNextTex0Data[0] >> 20) & 0x3f; + if( psm == 9 ) psm = 1; // hmm..., ffx intro menu + + // don't update unless necessary + if( uCurTex0Data[0] == uNextTex0Data[0] && (uCurTex0Data[1]&0x1f) == (uNextTex0Data[1]&0x1f) ) { + + if( PSMT_ISCLUT(psm) ) { + + // have to write the CLUT again if changed + if( (uCurTex0Data[1]&0x1fffffe0) == (uNextTex0Data[1]&0x1fffffe0) ) { + + if( uNextTex0Data[1]&0xe0000000 ) { + //ZeroGS::Flush(ictx); + ZeroGS::texClutWrite(ictx); + // invalidate to make sure target didn't change! + bVarsTexSync = FALSE; + } + + return; + } + + if( (uNextTex0Data[1]&0xe0000000) == 0 ) { + + if( (uCurTex0Data[1]&0x1ff10000) != (uNextTex0Data[1]&0x1ff10000) ) + ZeroGS::Flush(ictx); + + // clut isn't going to be loaded so can ignore, but at least update CSA and CPSM! + uCurTex0Data[1] = (uCurTex0Data[1]&0xe087ffff)|(uNextTex0Data[1]&0x1f780000); + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + ZeroGS::texClutWrite(ictx); + + bVarsTexSync = FALSE; + return; + } + + // fall through + } + else { + //bVarsTexSync = FALSE; + return; + } + } + + ZeroGS::Flush(ictx); + bVarsTexSync = FALSE; + bTexConstsSync = FALSE; + + uCurTex0Data[0] = uNextTex0Data[0]; + uCurTex0Data[1] = uNextTex0Data[1]; + + tex0.tbp0 = (uNextTex0Data[0] & 0x3fff); + tex0.tbw = ((uNextTex0Data[0] >> 14) & 0x3f) * 64; + tex0.psm = psm; + tex0.tw = (uNextTex0Data[0] >> 26) & 0xf; + if (tex0.tw > 10) tex0.tw = 10; + tex0.tw = 1<> 30) & 0x3) | ((uNextTex0Data[1] & 0x3) << 2); + if (tex0.th > 10) tex0.th = 10; + tex0.th = 1<> 2) & 0x1; + tex0.tfx = (uNextTex0Data[1] >> 3) & 0x3; + + ZeroGS::fiTexWidth[ictx] = (1/16.0f)/ tex0.tw; + ZeroGS::fiTexHeight[ictx] = (1/16.0f) / tex0.th; + + if (tex0.tbw == 0) tex0.tbw = 64; + + if( PSMT_ISCLUT(psm) ) { + tex0.cbp = ((uNextTex0Data[1] >> 5) & 0x3fff); + tex0.cpsm = (uNextTex0Data[1] >> 19) & 0xe; + tex0.csm = (uNextTex0Data[1] >> 23) & 0x1; + + if( tex0.cpsm <= 1 ) tex0.csa = (uNextTex0Data[1] >> 24) & 0xf; + else tex0.csa = (uNextTex0Data[1] >> 24) & 0x1f; + + tex0.cld = (uNextTex0Data[1] >> 29) & 0x7; + + ZeroGS::texClutWrite(ictx); + } +} + +// does one time only initializing/destruction +class ZeroGSInit +{ +public: + ZeroGSInit() { + // clear + g_pbyGSMemory = (u8*)_aligned_malloc(0x00410000, 1024); // leave some room for out of range accesses (saves on the checks) + memset(g_pbyGSMemory, 0, 0x00410000); + + g_pbyGSClut = (u8*)_aligned_malloc(256*8, 1024); // need 512 alignment! + memset(g_pbyGSClut, 0, 256*8); + +#ifndef _WIN32 + memset(&GLWin, 0, sizeof(GLWin)); +#endif + } + ~ZeroGSInit() { + _aligned_free(g_pbyGSMemory); g_pbyGSMemory = NULL; + _aligned_free(g_pbyGSClut); g_pbyGSClut = NULL; + } +}; + +static ZeroGSInit s_ZeroGSInit; + +#ifdef _WIN32 +void __stdcall glBlendFuncSeparateDummy(GLenum e1, GLenum e2, GLenum e3, GLenum e4) +#else +void APIENTRY glBlendFuncSeparateDummy(GLenum e1, GLenum e2, GLenum e3, GLenum e4) +#endif +{ + glBlendFunc(e1, e2); +} + +#ifdef _WIN32 +void __stdcall glBlendEquationSeparateDummy(GLenum e1, GLenum e2) +#else +void APIENTRY glBlendEquationSeparateDummy(GLenum e1, GLenum e2) +#endif +{ + glBlendEquation(e1); +} + +void HandleCgError(CGcontext ctx, CGerror err, void* appdata) +{ + ERROR_LOG("Cg error: %s\n", cgGetErrorString(err)); + const char* listing = cgGetLastListing(g_cgcontext); + if( listing != NULL ) DEBUG_LOG(" last listing: %s\n", listing); +// int loc; +// const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB); +// if( pstr != NULL ) printf("error at: %s\n"); +// glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc); +// DEBUG_LOG("pos: %d\n", loc); +} + +#ifndef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8 +#endif + +void ZeroGS::HandleGLError() +{ + // check the error status of this framebuffer */ + GLenum error = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + // if error != GL_FRAMEBUFFER_COMPLETE_EXT, there's an error of some sort + if( error != 0 ) { + int w, h; + GLint fmt; + glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_INTERNAL_FORMAT_EXT, &fmt); + glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_WIDTH_EXT, &w); + glGetRenderbufferParameterivEXT(GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_HEIGHT_EXT, &h); + + switch(error) + { + case GL_FRAMEBUFFER_COMPLETE_EXT: + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: + ERROR_LOG("Error! missing a required image/buffer attachment!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: + ERROR_LOG("Error! has no images/buffers attached!\n"); + break; +// case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: +// ERROR_LOG("Error! has an image/buffer attached in multiple locations!\n"); +// break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: + ERROR_LOG("Error! has mismatched image/buffer dimensions!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: + ERROR_LOG("Error! colorbuffer attachments have different types!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: + ERROR_LOG("Error! trying to draw to non-attached color buffer!\n"); + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: + ERROR_LOG("Error! trying to read from a non-attached color buffer!\n"); + break; + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + ERROR_LOG("Error! format is not supported by current graphics card/driver!\n"); + break; + default: + ERROR_LOG("*UNKNOWN ERROR* reported from glCheckFramebufferStatusEXT() for %s!\n"); + break; + } + } +} + +#ifdef _WIN32 +#define GL_LOADFN(name) { \ + if( (*(void**)&name = (void*)wglGetProcAddress(#name)) == NULL ) { \ + ERROR_LOG("Failed to find %s, exiting\n", #name); \ + } \ +} +#else +// let GLEW take care of it +#define GL_LOADFN(name) +#endif + +bool ZeroGS::IsGLExt( const char* szTargetExtension ) +{ + return mapGLExtensions.find(string(szTargetExtension)) != mapGLExtensions.end(); +} + +bool ZeroGS::Create(int _width, int _height) +{ + GLenum err = GL_NO_ERROR; + bool bSuccess = true; + int i; + + Destroy(1); + GSStateReset(); + + cgSetErrorHandler(HandleCgError, NULL); + g_RenderFormatType = RFT_float16; + + nBackbufferWidth = _width; + nBackbufferHeight = _height; + fiRendWidth = 1.0f / nBackbufferWidth; + fiRendHeight = 1.0f / nBackbufferHeight; + +#ifdef _WIN32 + GLuint PixelFormat; // Holds The Results After Searching For A Match + DWORD dwExStyle; // Window Extended Style + DWORD dwStyle; // Window Style + + RECT rcdesktop; + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + if (conf.options & GSOPTION_FULLSCREEN) { + nBackbufferWidth = rcdesktop.right - rcdesktop.left; + nBackbufferHeight = rcdesktop.bottom - rcdesktop.top; + + DEVMODE dmScreenSettings; + memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); + dmScreenSettings.dmSize=sizeof(dmScreenSettings); + dmScreenSettings.dmPelsWidth = nBackbufferWidth; + dmScreenSettings.dmPelsHeight = nBackbufferHeight; + dmScreenSettings.dmBitsPerPel = 32; + dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; + + // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. + if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) + { + if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES) + conf.options &= ~GSOPTION_FULLSCREEN; + else + return false; + } + } + else { + // change to default resolution + ChangeDisplaySettings(NULL, 0); + } + + if( conf.options & GSOPTION_FULLSCREEN) { + dwExStyle=WS_EX_APPWINDOW; + dwStyle=WS_POPUP; + ShowCursor(FALSE); + } + else { + dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + dwStyle=WS_OVERLAPPEDWINDOW; + } + + RECT rc; + rc.left = 0; rc.top = 0; + rc.right = nBackbufferWidth; rc.bottom = nBackbufferHeight; + AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle); + int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2; + int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2; + + SetWindowPos(GShwnd, NULL, X, Y, rc.right-rc.left, rc.bottom-rc.top, SWP_NOREPOSITION|SWP_NOZORDER); + + PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be + { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + 32, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // 8bit Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 24, // 24Bit Z-Buffer (Depth Buffer) + 8, // 8bit Stencil Buffer + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + if (!(hDC=GetDC(GShwnd))) { + MessageBox(NULL,"(1) Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) { + MessageBox(NULL,"(2) Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if(!SetPixelFormat(hDC,PixelFormat,&pfd)) { + MessageBox(NULL,"(3) Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if (!(hRC=wglCreateContext(hDC))) { + MessageBox(NULL,"(4) Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + + if(!wglMakeCurrent(hDC,hRC)) { + MessageBox(NULL,"(5) Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); + return false; + } + +#else + XVisualInfo *vi; + Colormap cmap; + int dpyWidth, dpyHeight; + int glxMajorVersion, glxMinorVersion; + int vidModeMajorVersion, vidModeMinorVersion; + Atom wmDelete; + Window winDummy; + unsigned int borderDummy; + + // attributes for a single buffered visual in RGBA format with at least + // 8 bits per color and a 24 bit depth buffer + int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + None}; + + // attributes for a double buffered visual in RGBA format with at least + // 8 bits per color and a 24 bit depth buffer + int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + None }; + + GLWin.fs = !!(conf.options & GSOPTION_FULLSCREEN); + + /* get an appropriate visual */ + vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl); + if (vi == NULL) { + vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl); + GLWin.doubleBuffered = False; + ERROR_LOG("Only Singlebuffered Visual!\n"); + } + else { + GLWin.doubleBuffered = True; + ERROR_LOG("Got Doublebuffered Visual!\n"); + } + + glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion); + ERROR_LOG("glX-Version %d.%d\n", glxMajorVersion, glxMinorVersion); + /* create a GLX context */ + GLWin.ctx = glXCreateContext(GLWin.dpy, vi, 0, GL_TRUE); + /* create a color map */ + cmap = XCreateColormap(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), + vi->visual, AllocNone); + GLWin.attr.colormap = cmap; + GLWin.attr.border_pixel = 0; + + // get a connection + XF86VidModeQueryVersion(GLWin.dpy, &vidModeMajorVersion, &vidModeMinorVersion); + + if (GLWin.fs) { + + XF86VidModeModeInfo **modes = NULL; + int modeNum = 0; + int bestMode = 0; + + // set best mode to current + bestMode = 0; + ERROR_LOG("XF86VidModeExtension-Version %d.%d\n", vidModeMajorVersion, vidModeMinorVersion); + XF86VidModeGetAllModeLines(GLWin.dpy, GLWin.screen, &modeNum, &modes); + + if( modeNum > 0 && modes != NULL ) { + /* save desktop-resolution before switching modes */ + GLWin.deskMode = *modes[0]; + /* look for mode with requested resolution */ + for (i = 0; i < modeNum; i++) { + if ((modes[i]->hdisplay == _width) && (modes[i]->vdisplay == _height)) { + bestMode = i; + } + } + + XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, modes[bestMode]); + XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0); + dpyWidth = modes[bestMode]->hdisplay; + dpyHeight = modes[bestMode]->vdisplay; + ERROR_LOG("Resolution %dx%d\n", dpyWidth, dpyHeight); + XFree(modes); + + /* create a fullscreen window */ + GLWin.attr.override_redirect = True; + GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | + StructureNotifyMask; + GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), + 0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual, + CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, + &GLWin.attr); + XWarpPointer(GLWin.dpy, None, GLWin.win, 0, 0, 0, 0, 0, 0); + XMapRaised(GLWin.dpy, GLWin.win); + XGrabKeyboard(GLWin.dpy, GLWin.win, True, GrabModeAsync, + GrabModeAsync, CurrentTime); + XGrabPointer(GLWin.dpy, GLWin.win, True, ButtonPressMask, + GrabModeAsync, GrabModeAsync, GLWin.win, None, CurrentTime); + } + else { + ERROR_LOG("Failed to start fullscreen. If you received the \n" + "\"XFree86-VidModeExtension\" extension is missing, add\n" + "Load \"extmod\"\n" + "to your X configuration file (under the Module Section)\n"); + GLWin.fs = 0; + } + } + + + if( !GLWin.fs ) { + + //XRootWindow(dpy,screen) + //int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2; + //int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2; + + // create a window in window mode + GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | + StructureNotifyMask; + GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), + 0, 0, _width, _height, 0, vi->depth, InputOutput, vi->visual, + CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr); + // only set window title and handle wm_delete_events if in windowed mode + wmDelete = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True); + XSetWMProtocols(GLWin.dpy, GLWin.win, &wmDelete, 1); + XSetStandardProperties(GLWin.dpy, GLWin.win, "ZeroGS", + "ZeroGS", None, NULL, 0, NULL); + XMapRaised(GLWin.dpy, GLWin.win); + } + + // connect the glx-context to the window + glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx); + XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y, + &GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth); + ERROR_LOG("Depth %d\n", GLWin.depth); + if (glXIsDirect(GLWin.dpy, GLWin.ctx)) + ERROR_LOG("you have Direct Rendering!\n"); + else + ERROR_LOG("no Direct Rendering possible!\n"); + + // better for pad plugin key input (thc) + XSelectInput(GLWin.dpy, GLWin.win, ExposureMask | KeyPressMask | KeyReleaseMask | + ButtonPressMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask | + FocusChangeMask ); + +#endif + + // fill the opengl extension map + const char* ptoken = (const char*)glGetString( GL_EXTENSIONS ); + if( ptoken == NULL ) return false; + + int prevlog = conf.log; + conf.log = 1; + GS_LOG("Supported OpenGL Extensions:\n%s\n", ptoken); // write to the log file + conf.log = prevlog; + + // insert all exts into mapGLExtensions + + const char* pend = NULL; + + while(ptoken != NULL ) { + pend = strchr(ptoken, ' '); + + if( pend != NULL ) { + mapGLExtensions[string(ptoken, pend-ptoken)]; + } + else { + mapGLExtensions[string(ptoken)]; + break; + } + + ptoken = pend; + while(*ptoken == ' ') ++ptoken; + } + + s_nFullscreen = (conf.options & GSOPTION_FULLSCREEN) ? 1 : 0; + conf.mrtdepth = 0; // for now + +#ifndef _WIN32 + int const glew_ok = glewInit(); + if( glew_ok != GLEW_OK ) { + ERROR_LOG("glewInit() is not ok!\n"); + return false; + } +#endif + + if( !IsGLExt("GL_EXT_framebuffer_object") ) { + ERROR_LOG("*********\nZeroGS: ERROR: Need GL_EXT_framebufer_object for multiple render targets\nZeroGS: *********\n"); + bSuccess = false; + } + if( !IsGLExt("GL_EXT_blend_equation_separate") || glBlendEquationSeparateEXT == NULL ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_blend_equation_separate\nZeroGS: *********\n"); + zgsBlendEquationSeparateEXT = glBlendEquationSeparateDummy; + } + else { + zgsBlendEquationSeparateEXT = glBlendEquationSeparateEXT; + } + + if( !IsGLExt("GL_EXT_blend_func_separate") || glBlendFuncSeparateEXT == NULL ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_blend_func_separate\nZeroGS: *********\n"); + zgsBlendFuncSeparateEXT = glBlendFuncSeparateDummy; + } + else { + zgsBlendFuncSeparateEXT = glBlendFuncSeparateEXT; + } + + if( !IsGLExt("GL_EXT_secondary_color") ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: Need GL_EXT_secondary_color\nZeroGS: *********\n"); + bSuccess = false; + } + + if( !IsGLExt("GL_ARB_draw_buffers") && !IsGLExt("GL_ATI_draw_buffers") ) { + ERROR_LOG("*********\nZeroGS: OGL WARNING: multiple render targets not supported, some effects might look bad\nZeroGS: *********\n"); + conf.mrtdepth = 0; + } + + if( !bSuccess ) + return false; + + if( g_GameSettings & GAME_32BITTARGS ) { + g_RenderFormatType = RFT_byte8; + ERROR_LOG("Setting 32 bit render target\n"); + } + else { + if( !IsGLExt("GL_NV_float_buffer") && !IsGLExt("GL_ARB_color_buffer_float") && !IsGLExt("ATI_pixel_format_float") ) { + ERROR_LOG("******\nZeroGS: GS WARNING: Floating point render targets not supported, switching to 32bit\nZeroGS: *********\n"); + g_RenderFormatType = RFT_byte8; + } + } + g_RenderFormatType = RFT_byte8; + +#ifdef _WIN32 + if( IsGLExt("WGL_EXT_swap_control") || IsGLExt("EXT_swap_control") ) + wglSwapIntervalEXT(0); +#else + if( IsGLExt("GLX_SGI_swap_control") ) { + _PFNSWAPINTERVAL swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapInterval"); + if( !swapinterval ) + swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapIntervalSGI"); + if( !swapinterval ) + swapinterval = (_PFNSWAPINTERVAL)wglGetProcAddress("glXSwapIntervalEXT"); + + if( swapinterval ) + swapinterval(0); + else + ERROR_LOG("no support for SwapInterval (framerate clamped to monitor refresh rate)\n"); + } +#endif + + // check the max texture width and height + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &g_MaxTexWidth); + g_MaxTexHeight = g_MaxTexWidth; + GPU_TEXWIDTH = g_MaxTexWidth/8; + g_fiGPU_TEXWIDTH = 1.0f / GPU_TEXWIDTH; + +#ifdef RELEASE_TO_PUBLIC +#ifdef _WIN32 + HRSRC hShaderSrc = FindResource(hInst, MAKEINTRESOURCE(IDR_SHADERS), RT_RCDATA); + assert( hShaderSrc != NULL ); + HGLOBAL hShaderGlob = LoadResource(hInst, hShaderSrc); + assert( hShaderGlob != NULL ); + s_lpShaderResources = (u8*)LockResource(hShaderGlob); +#else + FILE* fres = fopen("ps2hw.dat", "rb"); + if( fres == NULL ) { + fres = fopen("plugins/ps2hw.dat", "rb"); + if( fres == NULL ) { + ERROR_LOG("Cannot find ps2hw.dat in working directory. Exiting\n"); + return false; + } + } + fseek(fres, 0, SEEK_END); + size_t s = ftell(fres); + s_lpShaderResources = new u8[s+1]; + fseek(fres, 0, SEEK_SET); + fread(s_lpShaderResources, s, 1, fres); + s_lpShaderResources[s] = 0; +#endif + +#else + +#ifndef _WIN32 + // test if ps2hw.fx exists + char tempstr[255]; + char curwd[255]; + getcwd(curwd, ARRAY_SIZE(curwd)); + + strcpy(tempstr, "../plugins/gs/zerogs/opengl/"); + sprintf(EFFECT_NAME, "%sps2hw.fx", tempstr); + FILE* f = fopen(EFFECT_NAME, "r"); + if( f == NULL ) { + + strcpy(tempstr, "../../plugins/gs/zerogs/opengl/"); + sprintf(EFFECT_NAME, "%sps2hw.fx", tempstr); + f = fopen(EFFECT_NAME, "r"); + + if( f == NULL ) { + ERROR_LOG("Failed to find %s, try compiling a non-devbuild\n", EFFECT_NAME); + return false; + } + } + + fclose(f); + + sprintf(EFFECT_DIR, "%s/%s", curwd, tempstr); + sprintf(EFFECT_NAME, "%sps2hw.fx", EFFECT_DIR); +#endif + +#endif // RELEASE_TO_PUBLIC + + // load the effect, find the best profiles (if any) + if( cgGLIsProfileSupported(CG_PROFILE_ARBVP1) != CG_TRUE ) { + ERROR_LOG("arbvp1 not supported\n"); + return false; + } + if( cgGLIsProfileSupported(CG_PROFILE_ARBFP1) != CG_TRUE ) { + ERROR_LOG("arbfp1 not supported\n"); + return false; + } + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + s_srcrgb = s_dstrgb = s_srcalpha = s_dstalpha = GL_ONE; + + GL_LOADFN(glIsRenderbufferEXT); + GL_LOADFN(glBindRenderbufferEXT); + GL_LOADFN(glDeleteRenderbuffersEXT); + GL_LOADFN(glGenRenderbuffersEXT); + GL_LOADFN(glRenderbufferStorageEXT); + GL_LOADFN(glGetRenderbufferParameterivEXT); + GL_LOADFN(glIsFramebufferEXT); + GL_LOADFN(glBindFramebufferEXT); + GL_LOADFN(glDeleteFramebuffersEXT); + GL_LOADFN(glGenFramebuffersEXT); + GL_LOADFN(glCheckFramebufferStatusEXT); + GL_LOADFN(glFramebufferTexture1DEXT); + GL_LOADFN(glFramebufferTexture2DEXT); + GL_LOADFN(glFramebufferTexture3DEXT); + GL_LOADFN(glFramebufferRenderbufferEXT); + GL_LOADFN(glGetFramebufferAttachmentParameterivEXT); + GL_LOADFN(glGenerateMipmapEXT); + + if( IsGLExt("GL_ARB_draw_buffers") ) + glDrawBuffers = (PFNGLDRAWBUFFERSPROC)wglGetProcAddress("glDrawBuffers"); + else if( IsGLExt("GL_ATI_draw_buffers") ) + glDrawBuffers = (PFNGLDRAWBUFFERSPROC)wglGetProcAddress("glDrawBuffersATI"); + + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + glGenFramebuffersEXT( 1, &s_uFramebuffer); + if( s_uFramebuffer == 0 ) { + ERROR_LOG("failed to create the renderbuffer\n"); + } + + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); + + if( glDrawBuffers != NULL ) + glDrawBuffers(1, s_drawbuffers); + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + font_p = new RasterFont(); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + // init draw fns + drawfn[0] = KickPoint; + drawfn[1] = KickLine; + drawfn[2] = KickLine; + drawfn[3] = KickTriangle; + drawfn[4] = KickTriangle; + drawfn[5] = KickTriangleFan; + drawfn[6] = KickSprite; + drawfn[7] = KickDummy; + + SetAA(conf.aa); + GSsetGameCRC(g_LastCRC, g_GameSettings); + GL_STENCILFUNC(GL_ALWAYS, 0, 0); + + //g_GameSettings |= 0;//GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE|GAME_FASTUPDATE; + //s_bWriteDepth = TRUE; + + GL_BLEND_ALL(GL_ONE, GL_ONE, GL_ONE, GL_ONE); + + glViewport(0,0,nBackbufferWidth,nBackbufferHeight); // Reset The Current Viewport + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glShadeModel(GL_SMOOTH); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0f); + glEnable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glDepthFunc(GL_LEQUAL); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations + + glGenTextures(1, &ptexLogo); + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexLogo); + +#ifdef _WIN32 + HRSRC hBitmapSrc = FindResource(hInst, MAKEINTRESOURCE(IDB_ZEROGSLOGO), RT_BITMAP); + assert( hBitmapSrc != NULL ); + HGLOBAL hBitmapGlob = LoadResource(hInst, hBitmapSrc); + assert( hBitmapGlob != NULL ); + PBITMAPINFO pinfo = (PBITMAPINFO)LockResource(hBitmapGlob); + + glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 4, pinfo->bmiHeader.biWidth, pinfo->bmiHeader.biHeight, 0, pinfo->bmiHeader.biBitCount==32?GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, (u8*)pinfo+pinfo->bmiHeader.biSize); + nLogoWidth = pinfo->bmiHeader.biWidth; + nLogoHeight = pinfo->bmiHeader.biHeight; + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +#else +#endif + + GL_REPORT_ERROR(); + + g_nCurVBOIndex = 0; + g_vboBuffers.resize(VB_NUMBUFFERS); + glGenBuffers((GLsizei)g_vboBuffers.size(), &g_vboBuffers[0]); + for(i = 0; i < (int)g_vboBuffers.size(); ++i) { + glBindBuffer(GL_ARRAY_BUFFER, g_vboBuffers[i]); + glBufferData(GL_ARRAY_BUFFER, 0x100*sizeof(VertexGPU), NULL, GL_STREAM_DRAW); + } + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + // create the blocks texture + g_fBlockMult = 1; + + vector vBlockData, vBilinearData; + BLOCK::FillBlocks(vBlockData, vBilinearData, 1); + + glGenTextures(1, &ptexBlocks); + glBindTexture(GL_TEXTURE_2D, ptexBlocks); + + g_internalFloatFmt = GL_ALPHA_FLOAT32_ATI; + g_internalRGBAFloatFmt = GL_RGBA_FLOAT32_ATI; + g_internalRGBAFloat16Fmt = GL_RGBA_FLOAT16_ATI; + + glTexImage2D(GL_TEXTURE_2D, 0, g_internalFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_ALPHA, GL_FLOAT, &vBlockData[0]); + + if( glGetError() != GL_NO_ERROR ) { + // try different internal format + g_internalFloatFmt = GL_FLOAT_R32_NV; + glTexImage2D(GL_TEXTURE_2D, 0, g_internalFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RED, GL_FLOAT, &vBlockData[0]); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + if( glGetError() != GL_NO_ERROR ) { + + // error, resort to 16bit + g_fBlockMult = 65535.0f*(float)g_fiGPU_TEXWIDTH; + + BLOCK::FillBlocks(vBlockData, vBilinearData, 0); + glTexImage2D(GL_TEXTURE_2D, 0, 2, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_R, GL_UNSIGNED_SHORT, &vBlockData[0]); + if( glGetError() != GL_NO_ERROR ) + return false; + } + else { + // fill in the bilinear blocks + glGenTextures(1, &ptexBilinearBlocks); + glBindTexture(GL_TEXTURE_2D, ptexBilinearBlocks); + glTexImage2D(GL_TEXTURE_2D, 0, g_internalRGBAFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RGBA, GL_FLOAT, &vBilinearData[0]); + + if( glGetError() != GL_NO_ERROR ) { + g_internalRGBAFloatFmt = GL_FLOAT_RGBA32_NV; + g_internalRGBAFloat16Fmt = GL_FLOAT_RGBA16_NV; + glTexImage2D(GL_TEXTURE_2D, 0, g_internalRGBAFloatFmt, BLOCK_TEXWIDTH, BLOCK_TEXHEIGHT, 0, GL_RGBA, GL_FLOAT, &vBilinearData[0]); + B_G(glGetError() == GL_NO_ERROR, return false); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + + float fpri = 1; + glPrioritizeTextures(1, &ptexBlocks, &fpri); + if( ptexBilinearBlocks != 0 ) + glPrioritizeTextures(1, &ptexBilinearBlocks, &fpri); + + GL_REPORT_ERROR(); + + // fill a simple rect + glGenBuffers(1, &vboRect); + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + + vector verts(4); + VertexGPU* pvert = &verts[0]; + pvert->x = -0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 0; pvert++; + pvert->x = 0x7fff; pvert->y = 0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 0; pvert++; + pvert->x = -0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 0; pvert->t = 1; pvert++; + pvert->x = 0x7fff; pvert->y = -0x7fff; pvert->z = 0; pvert->s = 1; pvert->t = 1; pvert++; + glBufferDataARB(GL_ARRAY_BUFFER, 4*sizeof(VertexGPU), &verts[0], GL_STATIC_DRAW); + + // setup the default vertex declaration + glEnableClientState(GL_VERTEX_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_SECONDARY_COLOR_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + GL_REPORT_ERROR(); + + // some cards don't support this +// glClientActiveTexture(GL_TEXTURE0); +// glEnableClientState(GL_TEXTURE_COORD_ARRAY); +// glTexCoordPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)12); + + // create the conversion textures + glGenTextures(1, &ptexConv16to32); + glBindTexture(GL_TEXTURE_2D, ptexConv16to32); + + vector conv16to32data(256*256); + for(i = 0; i < 256*256; ++i) { + u32 tempcol = RGBA16to32(i); + // have to flip r and b + conv16to32data[i] = (tempcol&0xff00ff00)|((tempcol&0xff)<<16)|((tempcol&0xff0000)>>16); + } + glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, &conv16to32data[0]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + vector conv32to16data(32*32*32); + + glGenTextures(1, &ptexConv32to16); + glBindTexture(GL_TEXTURE_3D, ptexConv32to16); + u32* dst = &conv32to16data[0]; + for(i = 0; i < 32; ++i) { + for(int j = 0; j < 32; ++j) { + for(int k = 0; k < 32; ++k) { + u32 col = (i<<10)|(j<<5)|k; + *dst++ = ((col&0xff)<<16)|(col&0xff00); + } + } + } + glTexImage3D(GL_TEXTURE_3D, 0, 4, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, &conv32to16data[0]); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP); + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + g_cgcontext = cgCreateContext(); + + cgvProf = CG_PROFILE_ARBVP1; + cgfProf = CG_PROFILE_ARBFP1; + cgGLEnableProfile(cgvProf); + cgGLEnableProfile(cgfProf); + cgGLSetOptimalOptions(cgvProf); + cgGLSetOptimalOptions(cgfProf); + + cgGLSetManageTextureParameters(g_cgcontext, CG_FALSE); + //cgSetAutoCompile(g_cgcontext, CG_COMPILE_IMMEDIATE); + + g_fparamFogColor = cgCreateParameter(g_cgcontext, CG_FLOAT4); + g_vparamPosXY[0] = cgCreateParameter(g_cgcontext, CG_FLOAT4); + g_vparamPosXY[1] = cgCreateParameter(g_cgcontext, CG_FLOAT4); + + ERROR_LOG("Creating effects\n"); + B_G(LoadEffects(), return false); + + g_bDisplayMsg = 0; + + + // create a sample shader + clampInfo temp; + memset(&temp, 0, sizeof(temp)); + temp.wms = 3; temp.wmt = 3; + + g_nPixelShaderVer = SHADER_ACCURATE; + // test + bool bFailed; + FRAGMENTSHADER* pfrag = LoadShadeEffect(0, 1, 1, 1, 1, temp, 0, &bFailed); + if( bFailed || pfrag == NULL ) { + g_nPixelShaderVer = SHADER_ACCURATE|SHADER_REDUCED; + + pfrag = LoadShadeEffect(0, 0, 1, 1, 0, temp, 0, &bFailed); + if( pfrag != NULL ) + cgGLLoadProgram(pfrag->prog); + if( bFailed || pfrag == NULL || cgGetError() != CG_NO_ERROR ) { + g_nPixelShaderVer = SHADER_REDUCED; + ERROR_LOG("Basic shader test failed\n"); + } + } + + g_bDisplayMsg = 1; + if( g_nPixelShaderVer & SHADER_REDUCED ) + conf.bilinear = 0; + + ERROR_LOG("Creating extra effects\n"); + B_G(LoadExtraEffects(), return false); + + ERROR_LOG("using %s shaders\n", g_pShaders[g_nPixelShaderVer]); + + GL_REPORT_ERROR(); + if( err != GL_NO_ERROR ) bSuccess = false; + + glDisable(GL_STENCIL_TEST); + glEnable(GL_SCISSOR_TEST); + + GL_BLEND_ALPHA(GL_ONE, GL_ZERO); + glBlendColorEXT(0, 0, 0, 0.5f); + + glDisable(GL_CULL_FACE); + + // points + // This was changed in SetAA - should we be changing it back? + glPointSize(1.0f); + g_nDepthBias = 0; + glEnable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(0, 1); + + vb[0].Init(VB_BUFFERSIZE); + vb[1].Init(VB_BUFFERSIZE); + g_bSaveFlushedFrame = 1; + + g_vsprog = g_psprog = 0; + + return glGetError() == GL_NO_ERROR && bSuccess; +} + +void ZeroGS::Destroy(BOOL bD3D) +{ + if( s_aviinit ) { + StopCapture(); + +#ifdef _WIN32 + STOP_AVI(); +#else // linux + //TODO +#endif + ERROR_LOG("zerogs.avi stopped"); + s_aviinit = 0; + } + + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + SAFE_RELEASE_TEX(s_ptexInterlace); + SAFE_RELEASE_TEX(ptexBlocks); + SAFE_RELEASE_TEX(ptexBilinearBlocks); + SAFE_RELEASE_TEX(ptexConv16to32); + SAFE_RELEASE_TEX(ptexConv32to16); + + vb[0].Destroy(); + vb[1].Destroy(); + + if( g_vboBuffers.size() > 0 ) { + glDeleteBuffers((GLsizei)g_vboBuffers.size(), &g_vboBuffers[0]); + g_vboBuffers.clear(); + } + g_nCurVBOIndex = 0; + + for(int i = 0; i < ARRAY_SIZE(pvs); ++i) { + SAFE_RELEASE_PROG(pvs[i]); + } + for(int i = 0; i < ARRAY_SIZE(ppsRegular); ++i) { + SAFE_RELEASE_PROG(ppsRegular[i].prog); + } + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + } + + SAFE_RELEASE_PROG(pvsBitBlt.prog); + SAFE_RELEASE_PROG(ppsBitBlt[0].prog); SAFE_RELEASE_PROG(ppsBitBlt[1].prog); + SAFE_RELEASE_PROG(ppsBitBltDepth.prog); + SAFE_RELEASE_PROG(ppsCRTCTarg[0].prog); SAFE_RELEASE_PROG(ppsCRTCTarg[1].prog); + SAFE_RELEASE_PROG(ppsCRTC[0].prog); SAFE_RELEASE_PROG(ppsCRTC[1].prog); + SAFE_RELEASE_PROG(ppsCRTC24[0].prog); SAFE_RELEASE_PROG(ppsCRTC24[1].prog); + SAFE_RELEASE_PROG(ppsOne.prog); + + SAFE_DELETE(font_p); + +#ifdef _WIN32 + if (hRC) // Do We Have A Rendering Context? + { + if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts? + { + MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + } + + if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC? + { + MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + } + hRC=NULL; // Set RC To NULL + } + + if (hDC && !ReleaseDC(GShwnd,hDC)) // Are We Able To Release The DC + { + MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); + hDC=NULL; // Set DC To NULL + } +#else // linux + if (GLWin.ctx) + { + if (!glXMakeCurrent(GLWin.dpy, None, NULL)) + { + ERROR_LOG("Could not release drawing context.\n"); + } + glXDestroyContext(GLWin.dpy, GLWin.ctx); + GLWin.ctx = NULL; + } + /* switch back to original desktop resolution if we were in fs */ + if( GLWin.dpy != NULL ) { + if (GLWin.fs) { + XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, &GLWin.deskMode); + XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0); + } + } +#endif + + mapGLExtensions.clear(); +} + +void ZeroGS::GSStateReset() +{ + icurctx = -1; + + for(int i = 0; i < 2; ++i) { + vb[i].Destroy(); + memset(&vb[i], 0, SIZEOF_VB); + + vb[i].tex0.tw = 1; + vb[i].tex0.th = 1; + vb[i].scissor.x1 = 639; + vb[i].scissor.y1 = 479; + vb[i].tex0.tbw = 64; + vb[i].Init(VB_BUFFERSIZE); + } + + s_RangeMngr.Clear(); + g_MemTargs.Destroy(); + s_RTs.Destroy(); + s_DepthRTs.Destroy(); + s_BitwiseTextures.Destroy(); + + vb[0].ictx = 0; + vb[1].ictx = 1; +} + +void ZeroGS::AddMessage(const char* pstr, u32 ms) +{ + listMsgs.push_back(MESSAGE(pstr, timeGetTime()+ms)); +} + +void ZeroGS::DrawText(const char* pstr, int left, int top, u32 color) +{ + cgGLDisableProfile(cgvProf); + cgGLDisableProfile(cgfProf); + + glColor3f(((color>>16)&0xff)/255.0f, ((color>>8)&0xff)/255.0f, (color&0xff)/255.0f); + + font_p->printString(pstr, left * 2.0f / (float)nBackbufferWidth - 1, 1 - top * 2.0f / (float)nBackbufferHeight,0); + cgGLEnableProfile(cgvProf); + cgGLEnableProfile(cgfProf); +} + +void ZeroGS::ChangeWindowSize(int nNewWidth, int nNewHeight) +{ + nBackbufferWidth = nNewWidth > 16 ? nNewWidth : 16; + nBackbufferHeight = nNewHeight > 16 ? nNewHeight : 16; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::SetChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + s_nNewWidth = nNewWidth; + s_nNewHeight = nNewHeight; + + if( !(conf.options & GSOPTION_FULLSCREEN) ) { + conf.width = nNewWidth; + conf.height = nNewHeight; + //SaveConfig(); + } +} + +void ZeroGS::Reset() +{ + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + vb[0].nCount = 0; + vb[1].nCount = 0; + + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + icurctx = -1; + g_vsprog = g_psprog = 0; + + GSStateReset(); + Destroy(0); + + drawfn[0] = KickDummy; + drawfn[1] = KickDummy; + drawfn[2] = KickDummy; + drawfn[3] = KickDummy; + drawfn[4] = KickDummy; + drawfn[5] = KickDummy; + drawfn[6] = KickDummy; + drawfn[7] = KickDummy; +} + +void ZeroGS::ChangeDeviceSize(int nNewWidth, int nNewHeight) +{ + int oldscreen = s_nFullscreen; + + int oldwidth = nBackbufferWidth, oldheight = nBackbufferHeight; + if( !Create(nNewWidth&~7, nNewHeight&~7) ) { + ERROR_LOG("Failed to recreate, changing to old\n"); + if( !Create(oldwidth, oldheight) ) { + SysMessage("failed to create dev, exiting...\n"); + exit(0); + } + } + + for(int i = 0; i < 2; ++i) { + vb[i].bNeedFrameCheck = vb[i].bNeedZCheck = 1; + vb[i].CheckFrame(0); + } + + if( oldscreen && !(conf.options & GSOPTION_FULLSCREEN) ) { // if transitioning from full screen + RECT rc; + rc.left = 0; rc.top = 0; + rc.right = conf.width; rc.bottom = conf.height; + +#ifdef _WIN32 + AdjustWindowRect(&rc, conf.winstyle, FALSE); + + RECT rcdesktop; + GetWindowRect(GetDesktopWindow(), &rcdesktop); + + SetWindowLong( GShwnd, GWL_STYLE, conf.winstyle ); + SetWindowPos(GShwnd, HWND_TOP, ((rcdesktop.right-rcdesktop.left)-(rc.right-rc.left))/2, + ((rcdesktop.bottom-rcdesktop.top)-(rc.bottom-rc.top))/2, + rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW); + UpdateWindow(GShwnd); +#else // linux +#endif + } + + assert( vb[0].pBufferData != NULL && vb[1].pBufferData != NULL ); +} + +void ZeroGS::SetAA(int mode) +{ + float f; + + // need to flush all targets + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + s_AAx = s_AAy = 0; // This is code for x0, x2, x4, x8 and x16 anti-aliasing. + if (mode > 0) + { + s_AAx = (mode+1) / 2; // ( 1, 0 ) ; ( 1, 1 ) ; ( 2, 1 ) ; ( 2, 2 ) -- it's used as binary shift, so x >> s_AAx, y >> s_AAy + s_AAy = mode / 2; + } + + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + + f = mode > 0 ? 2.0f : 1.0f; + glPointSize(f); +} + +#define SET_UNIFORMPARAM(var, name) { \ + p = cgGetNamedParameter(pf->prog, name); \ + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) \ + pf->var = p; \ +} \ + +void SetupFragmentProgramParameters(FRAGMENTSHADER* pf, int context, int type) +{ + // uniform parameters + CGparameter p; + + p = cgGetNamedParameter(pf->prog, "g_fFogColor"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgConnectParameter(g_fparamFogColor, p); + } + + SET_UNIFORMPARAM(sOneColor, "g_fOneColor"); + SET_UNIFORMPARAM(sBitBltZ, "g_fBitBltZ"); + SET_UNIFORMPARAM(sInvTexDims, "g_fInvTexDims"); + SET_UNIFORMPARAM(fTexAlpha2, "fTexAlpha2"); + SET_UNIFORMPARAM(fTexOffset, "g_fTexOffset"); + SET_UNIFORMPARAM(fTexDims, "g_fTexDims"); + SET_UNIFORMPARAM(fTexBlock, "g_fTexBlock"); + SET_UNIFORMPARAM(fClampExts, "g_fClampExts"); + SET_UNIFORMPARAM(fTexWrapMode, "TexWrapMode"); + SET_UNIFORMPARAM(fRealTexDims, "g_fRealTexDims"); + SET_UNIFORMPARAM(fTestBlack, "g_fTestBlack"); + SET_UNIFORMPARAM(fPageOffset, "g_fPageOffset"); + SET_UNIFORMPARAM(fTexAlpha, "fTexAlpha"); + + // textures + p = cgGetNamedParameter(pf->prog, "g_sBlocks"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexBlocks); + cgGLEnableTextureParameter(p); + } + + // cg parameter usage is wrong, so do it manually + if( type == 3 ) { + p = cgGetNamedParameter(pf->prog, "g_sConv16to32"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexConv16to32); + cgGLEnableTextureParameter(p); + } + } + else if( type == 4 ) { + p = cgGetNamedParameter(pf->prog, "g_sConv32to16"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexConv32to16); + cgGLEnableTextureParameter(p); + } + } + else { + p = cgGetNamedParameter(pf->prog, "g_sBilinearBlocks"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetTextureParameter(p, ptexBilinearBlocks); + cgGLEnableTextureParameter(p); + } + } + + p = cgGetNamedParameter(pf->prog, "g_sMemory"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sMemory = p; + } + p = cgGetNamedParameter(pf->prog, "g_sSrcFinal"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sFinal = p; + } + p = cgGetNamedParameter(pf->prog, "g_sBitwiseANDX"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sBitwiseANDX = p; + } + p = cgGetNamedParameter(pf->prog, "g_sBitwiseANDY"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sBitwiseANDY = p; + } + p = cgGetNamedParameter(pf->prog, "g_sCLUT"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sCLUT = p; + } + p = cgGetNamedParameter(pf->prog, "g_sInterlace"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + //cgGLEnableTextureParameter(p); + pf->sInterlace = p; + } + + // set global shader constants + p = cgGetNamedParameter(pf->prog, "g_fExactColor"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) { + cgGLSetParameter4fv(p, Vector(0.5f, (g_GameSettings&GAME_EXACTCOLOR)?0.9f/256.0f:0.5f/256.0f, 0,1/255.0f)); + } + + p = cgGetNamedParameter(pf->prog, "g_fBilinear"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(-0.2f, -0.65f, 0.9f, 1.0f / 32767.0f )); + + p = cgGetNamedParameter(pf->prog, "g_fZBias"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(1.0f/256.0f, 1.0004f, 1, 0.5f)); + + p = cgGetNamedParameter(pf->prog, "g_fc0"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(0,1, 0.001f, 0.5f)); + + p = cgGetNamedParameter(pf->prog, "g_fMult"); + if( p != NULL && cgIsParameterUsed(p, pf->prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(1/1024.0f, 0.2f/1024.0f, 1/128.0f, 1/512.0f)); +} + +void SetupVertexProgramParameters(CGprogram prog, int context) +{ + CGparameter p; + + p = cgGetNamedParameter(prog, "g_fPosXY"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgConnectParameter(g_vparamPosXY[context], p); + + p = cgGetNamedParameter(prog, "g_fZ"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, g_vdepth); + + Vector vnorm = Vector(g_filog32, 0, 0,0); + p = cgGetNamedParameter(prog, "g_fZNorm"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, vnorm); + + p = cgGetNamedParameter(prog, "g_fBilinear"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(-0.2f, -0.65f, 0.9f, 1.0f / 32767.0f )); + + p = cgGetNamedParameter(prog, "g_fZBias"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(1.0f/256.0f, 1.0004f, 1, 0.5f)); + + p = cgGetNamedParameter(prog, "g_fc0"); + if( p != NULL && cgIsParameterUsed(p, prog) == CG_TRUE ) + cgGLSetParameter4fv(p, Vector(0,1, 0.001f, 0.5f)); +} + +#ifdef RELEASE_TO_PUBLIC + +#define LOAD_VS(Index, prog) { \ + assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ + header = mapShaderResources[Index]; \ + assert( (header) != NULL && (header)->index == (Index) ); \ + prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgvProf, NULL, NULL); \ + if( !cgIsProgram(prog) ) { \ + ERROR_LOG("Failed to load vs %d: \n%s\n", Index, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(prog); \ + if( cgGetError() != CG_NO_ERROR ) ERROR_LOG("failed to load program %d\n", Index); \ + SetupVertexProgramParameters(prog, !!(Index&SH_CONTEXT1)); \ +} \ + +#define LOAD_PS(Index, fragment) { \ + bLoadSuccess = true; \ + assert( mapShaderResources.find(Index) != mapShaderResources.end() ); \ + header = mapShaderResources[Index]; \ + fragment.prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgfProf, NULL, NULL); \ + if( !cgIsProgram(fragment.prog) ) { \ + ERROR_LOG("Failed to load ps %d: \n%s\n", Index, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(fragment.prog); \ + if( cgGetError() != CG_NO_ERROR ) { \ + ERROR_LOG("failed to load program %d\n", Index); \ + bLoadSuccess = false; \ + } \ + SetupFragmentProgramParameters(&fragment, !!(Index&SH_CONTEXT1), 0); \ +} \ + +bool ZeroGS::LoadEffects() +{ + assert( s_lpShaderResources != NULL ); + + // process the header + u32 num = *(u32*)s_lpShaderResources; + int compressed_size = *(int*)(s_lpShaderResources+4); + int real_size = *(int*)(s_lpShaderResources+8); + int out; + + char* pbuffer = (char*)malloc(real_size); + inf((char*)s_lpShaderResources+12, &pbuffer[0], compressed_size, real_size, &out); + assert(out == real_size); + + s_lpShaderResources = (u8*)pbuffer; + SHADERHEADER* header = (SHADERHEADER*)s_lpShaderResources; + + mapShaderResources.clear(); + while(num-- > 0 ) { + mapShaderResources[header->index] = header; + ++header; + } + + // clear the textures + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + ppsTexture[i].prog = NULL; + } +#ifndef _DEBUG + memset(ppsTexture, 0, sizeof(ppsTexture)); +#endif + + return true; +} + +// called +bool ZeroGS::LoadExtraEffects() +{ + SHADERHEADER* header; + bool bLoadSuccess = true; + + const int vsshaders[4] = { SH_REGULARVS, SH_TEXTUREVS, SH_REGULARFOGVS, SH_TEXTUREFOGVS }; + + for(int i = 0; i < 4; ++i) { + LOAD_VS(vsshaders[i], pvs[2*i]); + LOAD_VS(vsshaders[i]|SH_CONTEXT1, pvs[2*i+1]); + //if( conf.mrtdepth ) { + LOAD_VS(vsshaders[i]|SH_WRITEDEPTH, pvs[2*i+8]); + LOAD_VS(vsshaders[i]|SH_WRITEDEPTH|SH_CONTEXT1, pvs[2*i+8+1]); +// } +// else { +// pvs[2*i+8] = pvs[2*i+8+1] = NULL; +// } + } + + LOAD_VS(SH_BITBLTVS, pvsBitBlt.prog); + pvsBitBlt.sBitBltPos = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltPos"); + pvsBitBlt.sBitBltTex = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTex"); + pvsBitBlt.fBitBltTrans = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTrans"); + + LOAD_PS(SH_REGULARPS, ppsRegular[0]); + LOAD_PS(SH_REGULARFOGPS, ppsRegular[1]); + + if( conf.mrtdepth ) { + LOAD_PS(SH_REGULARPS, ppsRegular[2]); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + LOAD_PS(SH_REGULARFOGPS, ppsRegular[3]); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + } + + LOAD_PS(SH_BITBLTPS, ppsBitBlt[0]); + LOAD_PS(SH_BITBLTAAPS, ppsBitBlt[1]); + if( !bLoadSuccess ) { + ERROR_LOG("Failed to load BitBltAAPS, using BitBltPS\n"); + LOAD_PS(SH_BITBLTPS, ppsBitBlt[1]); + } + LOAD_PS(SH_BITBLTDEPTHPS, ppsBitBltDepth); + LOAD_PS(SH_CRTCTARGPS, ppsCRTCTarg[0]); + LOAD_PS(SH_CRTCTARGINTERPS, ppsCRTCTarg[1]); + + g_bCRTCBilinear = TRUE; + LOAD_PS(SH_CRTCPS, ppsCRTC[0]); + if( !bLoadSuccess ) { + // switch to simpler + g_bCRTCBilinear = FALSE; + LOAD_PS(SH_CRTC_NEARESTPS, ppsCRTC[0]); + LOAD_PS(SH_CRTCINTER_NEARESTPS, ppsCRTC[0]); + } + else { + LOAD_PS(SH_CRTCINTERPS, ppsCRTC[1]); + } + + if( !bLoadSuccess ) + ERROR_LOG("Failed to create CRTC shaders\n"); + + LOAD_PS(SH_CRTC24PS, ppsCRTC24[0]); + LOAD_PS(SH_CRTC24INTERPS, ppsCRTC24[1]); + LOAD_PS(SH_ZEROPS, ppsOne); + LOAD_PS(SH_BASETEXTUREPS, ppsBaseTexture); + LOAD_PS(SH_CONVERT16TO32PS, ppsConvert16to32); + LOAD_PS(SH_CONVERT32TO16PS, ppsConvert32to16); + + return true; +} + +FRAGMENTSHADER* ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed) +{ + int texwrap; + assert( texfilter < NUM_FILTERS ); + + if(g_nPixelShaderVer&SHADER_REDUCED) + texfilter = 0; + assert(!(g_nPixelShaderVer&SHADER_REDUCED) || !exactcolor); + + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + assert( index < ARRAY_SIZE(ppsTexture) ); + FRAGMENTSHADER* pf = ppsTexture+index; + + if( pbFailed != NULL ) *pbFailed = false; + + if( pf->prog != NULL ) + return pf; + + if( (g_nPixelShaderVer & SHADER_ACCURATE) && mapShaderResources.find(index+NUM_SHADERS*SHADER_ACCURATE) != mapShaderResources.end() ) + index += NUM_SHADERS*SHADER_ACCURATE; + + assert( mapShaderResources.find(index) != mapShaderResources.end() ); + SHADERHEADER* header = mapShaderResources[index]; + if( header == NULL ) + ERROR_LOG("%d %d\n", index, g_nPixelShaderVer); + assert( header != NULL ); + + //DEBUG_LOG("shader:\n%s\n", (char*)(s_lpShaderResources + (header)->offset)); + pf->prog = cgCreateProgram(g_cgcontext, CG_OBJECT, (char*)(s_lpShaderResources + (header)->offset), cgfProf, NULL, NULL); + if( pf->prog != NULL && cgIsProgram(pf->prog) && cgGetError() == CG_NO_ERROR ) { + SetupFragmentProgramParameters(pf, context, type); + cgGLLoadProgram(pf->prog); + if( cgGetError() != CG_NO_ERROR ) { +// cgGLLoadProgram(pf->prog); +// if( cgGetError() != CG_NO_ERROR ) { + ERROR_LOG("Failed to load shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + return pf; +// } + } + return pf; + } + + ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + + return NULL; +} + +#else // not RELEASE_TO_PUBLIC + +#define LOAD_VS(name, prog, shaderver) { \ + prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, EFFECT_NAME, shaderver, name, args); \ + if( !cgIsProgram(prog) ) { \ + ERROR_LOG("Failed to load vs %s: \n%s\n", name, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(prog); \ + if( cgGetError() != CG_NO_ERROR ) ERROR_LOG("failed to load program %s\n", name); \ + SetupVertexProgramParameters(prog, args[0]==context1); \ +} \ + +#ifdef _DEBUG +#define SET_PSFILENAME(frag, name) frag.filename = name +#else +#define SET_PSFILENAME(frag, name) +#endif + +#define LOAD_PS(name, fragment, shaderver) { \ + bLoadSuccess = true; \ + fragment.prog = cgCreateProgramFromFile(g_cgcontext, CG_SOURCE, EFFECT_NAME, shaderver, name, args); \ + if( !cgIsProgram(fragment.prog) ) { \ + ERROR_LOG("Failed to load ps %s: \n%s\n", name, cgGetLastListing(g_cgcontext)); \ + return false; \ + } \ + cgGLLoadProgram(fragment.prog); \ + if( cgGetError() != CG_NO_ERROR ) { \ + ERROR_LOG("failed to load program %s\n", name); \ + bLoadSuccess = false; \ + } \ + SetupFragmentProgramParameters(&fragment, args[0]==context1, 0); \ + SET_PSFILENAME(fragment, name); \ +} \ + +bool ZeroGS::LoadEffects() +{ + // clear the textures + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + } + +#ifndef _DEBUG + memset(ppsTexture, 0, sizeof(ppsTexture)); +#endif + + return true; +} + +bool ZeroGS::LoadExtraEffects() +{ + const char* args[] = { NULL , NULL, NULL, NULL }; + char context0[255], context1[255]; + sprintf(context0, "-I%sctx0", EFFECT_DIR); + sprintf(context1, "-I%sctx1", EFFECT_DIR); + char* write_depth = "-DWRITE_DEPTH"; + bool bLoadSuccess = true; + + const char* pvsshaders[4] = { "RegularVS", "TextureVS", "RegularFogVS", "TextureFogVS" }; + + for(int i = 0; i < 4; ++i) { + args[0] = context0; + args[1] = NULL; + LOAD_VS(pvsshaders[i], pvs[2*i], cgvProf); + args[0] = context1; + LOAD_VS(pvsshaders[i], pvs[2*i+1], cgvProf); + + //if( conf.mrtdepth ) { + args[0] = context0; + args[1] = write_depth; + LOAD_VS(pvsshaders[i], pvs[2*i+8], cgvProf); + args[0] = context1; + LOAD_VS(pvsshaders[i], pvs[2*i+8+1], cgvProf); +// } +// else { +// pvs[2*i+8] = pvs[2*i+8+1] = NULL; +// } + } + + args[0] = context0; + args[1] = NULL; + LOAD_VS("BitBltVS", pvsBitBlt.prog, cgvProf); + pvsBitBlt.sBitBltPos = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltPos"); + pvsBitBlt.sBitBltTex = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTex"); + pvsBitBlt.fBitBltTrans = cgGetNamedParameter(pvsBitBlt.prog, "g_fBitBltTrans"); + + LOAD_PS("RegularPS", ppsRegular[0], cgfProf); + LOAD_PS("RegularFogPS", ppsRegular[1], cgfProf); + + if( conf.mrtdepth ) { + args[0] = context0; + args[1] = write_depth; + LOAD_PS("RegularPS", ppsRegular[2], cgfProf); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + LOAD_PS("RegularFogPS", ppsRegular[3], cgfProf); + if( !bLoadSuccess ) + conf.mrtdepth = 0; + } + + LOAD_PS("BitBltPS", ppsBitBlt[0], cgfProf); + LOAD_PS("BitBltAAPS", ppsBitBlt[1], cgfProf); + if( !bLoadSuccess ) { + ERROR_LOG("Failed to load BitBltAAPS, using BitBltPS\n"); + LOAD_PS("BitBltPS", ppsBitBlt[1], cgfProf); + } + + LOAD_PS("BitBltDepthPS", ppsBitBltDepth, cgfProf); + LOAD_PS("CRTCTargPS", ppsCRTCTarg[0], cgfProf); LOAD_PS("CRTCTargInterPS", ppsCRTCTarg[1], cgfProf); + + g_bCRTCBilinear = TRUE; + LOAD_PS("CRTCPS", ppsCRTC[0], cgfProf); + if( !bLoadSuccess ) { + // switch to simpler + g_bCRTCBilinear = FALSE; + LOAD_PS("CRTCPS_Nearest", ppsCRTC[0], cgfProf); + LOAD_PS("CRTCInterPS_Nearest", ppsCRTC[0], cgfProf); + } + else { + LOAD_PS("CRTCInterPS", ppsCRTC[1], cgfProf); + } + + if( !bLoadSuccess ) + ERROR_LOG("Failed to create CRTC shaders\n"); + + LOAD_PS("CRTC24PS", ppsCRTC24[0], cgfProf); LOAD_PS("CRTC24InterPS", ppsCRTC24[1], cgfProf); + LOAD_PS("ZeroPS", ppsOne, cgfProf); + LOAD_PS("BaseTexturePS", ppsBaseTexture, cgfProf); + LOAD_PS("Convert16to32PS", ppsConvert16to32, cgfProf); + LOAD_PS("Convert32to16PS", ppsConvert32to16, cgfProf); + +// if( !conf.mrtdepth ) { +// ERROR_LOG("Disabling MRT depth writing\n"); +// s_bWriteDepth = FALSE; +// } + + return true; +} + +FRAGMENTSHADER* ZeroGS::LoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed) +{ + int texwrap; + + assert( texfilter < NUM_FILTERS ); + //assert( g_nPixelShaderVer == SHADER_30 ); + if( clamp.wms == clamp.wmt ) { + switch( clamp.wms ) { + case 0: texwrap = TEXWRAP_REPEAT; break; + case 1: texwrap = TEXWRAP_CLAMP; break; + case 2: texwrap = TEXWRAP_CLAMP; break; + default: + texwrap = TEXWRAP_REGION_REPEAT; break; + } + } + else if( clamp.wms==3||clamp.wmt==3) + texwrap = TEXWRAP_REGION_REPEAT; + else + texwrap = TEXWRAP_REPEAT_CLAMP; + + int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); + + if( pbFailed != NULL ) *pbFailed = false; + + FRAGMENTSHADER* pf = ppsTexture+index; + + if( pf->prog != NULL ) + return pf; + + pf->prog = LoadShaderFromType(EFFECT_DIR, EFFECT_NAME, type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, g_nPixelShaderVer, context); + + if( pf->prog != NULL ) { +#ifdef _DEBUG + char str[255]; + sprintf(str, "Texture%s%d_%sPS", fog?"Fog":"", texfilter, g_pTexTypes[type]); + pf->filename = str; +#endif + SetupFragmentProgramParameters(pf, context, type); + cgGLLoadProgram(pf->prog); + if( cgGetError() != CG_NO_ERROR ) { + // try again +// cgGLLoadProgram(pf->prog); +// if( cgGetError() != CG_NO_ERROR ) { + ERROR_LOG("Failed to load shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + //assert(0); + // NULL makes things crash + return pf; +// } + } + return pf; + } + + ERROR_LOG("Failed to create shader %d,%d,%d,%d\n", type, fog, texfilter, 4*clamp.wms+clamp.wmt); + if( pbFailed != NULL ) *pbFailed = true; + + return NULL; +} + +#endif // RELEASE_TO_PUBLIC + +void ZeroGS::Prim() +{ + if( g_bIsLost ) + return; + + VB& curvb = vb[prim->ctxt]; + if( curvb.CheckPrim() ) + Flush(prim->ctxt); + curvb.curprim._val = prim->_val; + + // flush the other pipe if sharing the same buffer +// if( vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp && vb[!prim->ctxt].nCount > 0 ) +// { +// assert( vb[prim->ctxt].nCount == 0 ); +// Flush(!prim->ctxt); +// } + + curvb.curprim.prim = prim->prim; +} + +int GetTexFilter(const tex1Info& tex1) +{ + // always force + if( conf.bilinear == 2 ) + return 1; + + int texfilter = 0; + if( conf.bilinear && ptexBilinearBlocks != 0 ) { + if( tex1.mmin <= 1 ) + texfilter = tex1.mmin|tex1.mmag; + else + texfilter = tex1.mmag ? ((tex1.mmin+2)&5) : tex1.mmin; + + texfilter = texfilter == 1 || texfilter == 4 || texfilter == 5; + } + return texfilter; +} + +void ZeroGS::ReloadEffects() +{ +#ifndef RELEASE_TO_PUBLIC + for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + SAFE_RELEASE_PROG(ppsTexture[i].prog); + } + memset(ppsTexture, 0, sizeof(ppsTexture)); + LoadExtraEffects(); +#endif +} + +static int s_ClutResolve = 0; +void ZeroGS::Flush(int context) +{ + GL_REPORT_ERRORD(); + assert( context >= 0 && context <= 1 ); + +#ifndef RELEASE_TO_PUBLIC + if( g_bUpdateEffect ) { + ReloadEffects(); + g_bUpdateEffect = 0; + } +#endif + + VB& curvb = vb[context]; + const pixTest curtest = curvb.test; + if( curvb.nCount == 0 || (curtest.zte && curtest.ztst == 0) || g_bIsLost ) { + curvb.nCount = 0; + return; + } + + if( s_RangeMngr.ranges.size() > 0 ) { + + // don't want infinite loop + u32 prevcount = curvb.nCount; + curvb.nCount = 0; + FlushTransferRanges(curvb.curprim.tme ? &curvb.tex0 : NULL); + + curvb.nCount = prevcount; + //if( curvb.nCount == 0 ) + // return; + } + + if( curvb.bNeedTexCheck ) { + curvb.FlushTexData(); + + if( curvb.nCount == 0 ) + return; + } + + DVProfileFunc _pf("Flush"); + + GL_REPORT_ERRORD(); + if( curvb.bNeedFrameCheck || curvb.bNeedZCheck ) { + curvb.CheckFrame(curvb.curprim.tme ? curvb.tex0.tbp0 : 0); + } + + if( curvb.prndr == NULL || curvb.pdepth == NULL ) { + WARN_LOG("Current render target NULL (ctx: %d)", context); + curvb.nCount = 0; + return; + } + +#if defined(PRIM_LOG) && defined(_DEBUG) + static const char* patst[8] = { "NEVER", "ALWAYS", "LESS", "LEQUAL", "EQUAL", "GEQUAL", "GREATER", "NOTEQUAL"}; + static const char* pztst[4] = { "NEVER", "ALWAYS", "GEQUAL", "GREATER" }; + static const char* pafail[4] = { "KEEP", "FB_ONLY", "ZB_ONLY", "RGB_ONLY" }; + PRIM_LOG("**Drawing ctx %d, num %d, fbp: 0x%x, zbp: 0x%x, fpsm: %d, zpsm: %d, fbw: %d\n", context, vb[context].nCount, curvb.prndr->fbp, curvb.zbuf.zbp, curvb.prndr->psm, curvb.zbuf.psm, curvb.prndr->fbw); + PRIM_LOG("prim: prim=%x iip=%x tme=%x fge=%x abe=%x aa1=%x fst=%x ctxt=%x fix=%x\n", + curvb.curprim.prim, curvb.curprim.iip, curvb.curprim.tme, curvb.curprim.fge, curvb.curprim.abe, curvb.curprim.aa1, curvb.curprim.fst, curvb.curprim.ctxt, curvb.curprim.fix); + PRIM_LOG("test: ate:%d, atst: %s, aref: %d, afail: %s, date: %d, datm: %d, zte: %d, ztst: %s, fba: %d\n", + curvb.test.ate, patst[curvb.test.atst], curvb.test.aref, pafail[curvb.test.afail], curvb.test.date, curvb.test.datm, curvb.test.zte, pztst[curvb.test.ztst], curvb.fba.fba); + PRIM_LOG("alpha: A%d B%d C%d D%d FIX:%d pabe: %d; aem: %d, ta0: %d, ta1: %d\n", curvb.alpha.a, curvb.alpha.b, curvb.alpha.c, curvb.alpha.d, curvb.alpha.fix, gs.pabe, gs.texa.aem, gs.texa.ta[0], gs.texa.ta[1]); + PRIM_LOG("tex0: tbp0=0x%x, tbw=%d, psm=0x%x, tw=%d, th=%d, tcc=%d, tfx=%d, cbp=0x%x, cpsm=0x%x, csm=%d, csa=%d, cld=%d\n", + curvb.tex0.tbp0, curvb.tex0.tbw, curvb.tex0.psm, curvb.tex0.tw, + curvb.tex0.th, curvb.tex0.tcc, curvb.tex0.tfx, curvb.tex0.cbp, + curvb.tex0.cpsm, curvb.tex0.csm, curvb.tex0.csa, curvb.tex0.cld); + PRIM_LOG("frame: %d\n\n", g_SaveFrameNum); +#endif + + GL_REPORT_ERRORD(); + CRenderTarget* ptextarg = NULL; + + if( curtest.date || gs.pabe ) + SetDestAlphaTest(); + + // set the correct pixel shaders + if( curvb.curprim.tme ) { + + // if texture is part of a previous target, use that instead + int tbw = curvb.tex0.tbw; + int tbp0 = curvb.tex0.tbp0; + int tpsm = curvb.tex0.psm; + + if( curvb.bNeedTexCheck ) { + // not yet initied, but still need to get correct target! (xeno3 ingame) + tbp0 = (curvb.uNextTex0Data[0] & 0x3fff); + tbw = ((curvb.uNextTex0Data[0] >> 14) & 0x3f) * 64; + tpsm = (curvb.uNextTex0Data[0] >> 20) & 0x3f; + } + ptextarg = s_RTs.GetTarg(tbp0, tbw); + + if( (tpsm&0x30)==0x30 && ptextarg == NULL ) { + // try depth + ptextarg = s_DepthRTs.GetTarg(tbp0, tbw); + } + + if( ptextarg == NULL && (g_GameSettings&GAME_TEXTURETARGS) ) { + // check if any part of the texture intersects the current target + if( !PSMT_ISCLUT(tpsm) && curvb.tex0.tbp0 >= curvb.frame.fbp && (curvb.tex0.tbp0 << 8) < curvb.prndr->end) { + ptextarg = curvb.prndr; + } + } + + if( ptextarg != NULL && !(ptextarg->status&CRenderTarget::TS_NeedUpdate) ) { + if( PSMT_ISCLUT(tpsm) && tpsm != PSMT8H ) { // handle 8h cluts + // don't support clut targets, read from mem + // 4hl - kh2 check - from dx version -- arcum42 + if( tpsm != PSMT4HL && tpsm != PSMT4HH && s_ClutResolve <= 1 ) + { // xenosaga requires 2 resolves + u32 prevcount = curvb.nCount; + curvb.nCount = 0; + ptextarg->Resolve(); + s_ClutResolve++; + curvb.nCount = prevcount; + } + ptextarg = NULL; + } + else { + if( ptextarg == curvb.prndr ) { + // need feedback + curvb.prndr->CreateFeedback(); + + if(s_bWriteDepth && curvb.pdepth != NULL) + curvb.pdepth->SetRenderTarget(1); + else + ResetRenderTarget(1); + } + } + } + else ptextarg = NULL; + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0x80000000 ) { + char str[255]; + sprintf(str, "rndr.tga", g_SaveFrameNum); + SaveRenderTarget(str, curvb.prndr->fbw, curvb.prndr->fbh, 0); + } +#endif + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + } + + if( !curvb.bVarsSetTarg ) + SetContextTarget(context); + else { + assert( curvb.pdepth != NULL ); + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + if( (curvb.pdepth->status & CRenderTarget::TS_NeedUpdate) || (curvb.prndr->status & CRenderTarget::TS_NeedUpdate) ) + SetContextTarget(context); + } + + icurctx = context; + + DVProfileFunc _pf5("Flush:after texvars"); + + glBindBuffer(GL_ARRAY_BUFFER, g_vboBuffers[g_nCurVBOIndex]); + g_nCurVBOIndex = (g_nCurVBOIndex+1)%g_vboBuffers.size(); + glBufferData(GL_ARRAY_BUFFER, curvb.nCount * sizeof(VertexGPU), curvb.pBufferData, GL_STREAM_DRAW); +// void* pdata = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); +// memcpy_amd(pdata, curvb.pBufferData, curvb.nCount * sizeof(VertexGPU)); +// glUnmapBuffer(GL_ARRAY_BUFFER); + SET_STREAM(); + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + curvb.prndr->status = 0; + + if( curvb.pdepth != NULL ) { + assert( !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); + if( !curvb.zbuf.zmsk ) { + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + curvb.pdepth->status = 0; + } + } + +#ifdef _DEBUG + //curvb.prndr->SetRenderTarget(0); + //curvb.pdepth->SetDepthStencilSurface(); + //glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_NV, 0, 0 ); + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + assert( glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT ); +#endif + s_dwColorWrite = (curvb.prndr->psm&0xf) == 1 ? (COLORMASK_BLUE|COLORMASK_GREEN|COLORMASK_RED) : 0xf; + + if( ((curvb.frame.fbm)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_RED; + if( ((curvb.frame.fbm>>8)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_GREEN; + if( ((curvb.frame.fbm>>16)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_BLUE; + if( ((curvb.frame.fbm>>24)&0xff) == 0xff) s_dwColorWrite &= ~COLORMASK_ALPHA; + + GL_COLORMASK(s_dwColorWrite); + + Rect& scissor = curvb.prndr->scissorrect; + glScissor(scissor.x, scissor.y, scissor.w, scissor.h); + + u32 dwUsingSpecialTesting = 0; + u32 dwFilterOpts = 0; + + FRAGMENTSHADER* pfragment = NULL; + + // need exact if equal or notequal + int exactcolor = 0; + if( !(g_nPixelShaderVer&SHADER_REDUCED) ) + // ffx2 breaks when ==7 + exactcolor = (curtest.ate && curtest.aref <= 128) && (curtest.atst==4);//||curtest.atst==7); + + int shadertype = 0; + + // set the correct pixel shaders + u32 ptexclut = 0; + if( curvb.curprim.tme ) { + + if( ptextarg != NULL ) { + + if( ptextarg->IsDepth() ) + SetWriteDepth(); + + Vector vpageoffset; + vpageoffset.w = 0; + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + shadertype = 1; + if( curvb.tex0.psm == PSMT8H && !(g_GameSettings&GAME_NOTARGETCLUT) ) { + // load the clut to memory + glGenTextures(1, &ptexclut); + glBindTexture(GL_TEXTURE_2D, ptexclut); + vector data((curvb.tex0.cpsm&2) ? 512 : 1024); + + if( ptexclut != 0 ) { + + // fill the buffer by decoding the clut + int nClutOffset = 0, clutsize; + int entries = (curvb.tex0.psm&3)==3 ? 256 : 16; + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + nClutOffset = 64 * curvb.tex0.csa; + clutsize = min(entries, 256-curvb.tex0.csa*16)*4; + } + else { + nClutOffset = 64 * (curvb.tex0.csa&15) + (curvb.tex0.csa>=16?2:0); + clutsize = min(entries, 512-curvb.tex0.csa*16)*2; + } + + if( curvb.tex0.cpsm <= 1 ) { // 32 bit + memcpy_amd(&data[0], g_pbyGSClut+nClutOffset, clutsize); + } + else { + u16* pClutBuffer = (u16*)(g_pbyGSClut + nClutOffset); + u16* pclut = (u16*)&data[0]; + int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset&0x3ff)/2)+clutsize-512; + if( left > 0 ) clutsize -= left; + + while(clutsize > 0) { + pclut[0] = pClutBuffer[0]; + pclut++; + pClutBuffer+=2; + clutsize -= 2; + } + + if( left > 0) { + pClutBuffer = (u16*)(g_pbyGSClut + 2); + while(left > 0) { + pclut[0] = pClutBuffer[0]; + left -= 2; + pClutBuffer += 2; + pclut++; + } + } + } + + glTexImage2D(GL_TEXTURE_2D, 0, 4, 256, 1, 0, GL_RGBA, (curvb.tex0.cpsm&2)?GL_UNSIGNED_SHORT_5_5_5_1:GL_UNSIGNED_BYTE, &data[0]); + s_vecTempTextures.push_back(ptexclut); + + if( g_bSaveTex ) + SaveTexture("clut.tga", GL_TEXTURE_2D, ptexclut, 256, 1); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + + if( !(g_nPixelShaderVer&SHADER_REDUCED) && (ptextarg->psm & 2) ) { + shadertype = 4; + } + else + shadertype = 2; + } + else { + if( PSMT_ISCLUT(curvb.tex0.psm) ) + WARN_LOG("Using render target with CLUTs %d!\n", curvb.tex0.psm); + else { + if( (curvb.tex0.psm&2) != (ptextarg->psm&2) && (!(g_nPixelShaderVer&SHADER_REDUCED) || !curvb.curprim.fge) ) { + if( curvb.tex0.psm & 2 ) { + // converting from 32->16 + shadertype = 3; + } + else { + // converting from 16->32 + WARN_LOG("ZeroGS: converting from 16 to 32bit RTs\n"); + //shadetype = 4; + } + } + } + } + + pfragment = LoadShadeEffect(shadertype, 0, curvb.curprim.fge, curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context, NULL); + + if( shadertype == 3 ) { + Vector v; + v.x = 16.0f / (float)curvb.tex0.tw; + v.y = 16.0f / (float)curvb.tex0.th; + v.z = 0.5f * v.x; + v.w = 0.5f * v.y; + cgGLSetParameter4fv(pfragment->fTexOffset, v); + + vpageoffset.x = -0.1f / 256.0f; + vpageoffset.y = -0.001f / 256.0f; + vpageoffset.z = -0.1f / ptextarg->fbh; + vpageoffset.w = ((ptextarg->psm&0x30)==0x30)?-1.0f:0.0f; + } + else if( shadertype == 4 ) { + Vector v; + v.x = 16.0f / (float)ptextarg->fbw; + v.y = 16.0f / (float)ptextarg->fbh; + v.z = -1; + v.w = 8.0f / (float)ptextarg->fbh; + cgGLSetParameter4fv(pfragment->fTexOffset, v); + + vpageoffset.x = 2; + vpageoffset.y = 1; + vpageoffset.z = 0; + vpageoffset.w = 0.0001f; + } + + u32 ptexset = ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex; + s_ptexCurSet[context] = ptexset; + + if( !curvb.tex1.mmag ) { + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexset); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + dwFilterOpts |= 1; + } + + if( !curvb.tex1.mmin ) { + if( curvb.tex1.mmag ) + glBindTexture(GL_TEXTURE_RECTANGLE_NV, ptexset); + glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + dwFilterOpts |= 2; + } + + Vector vTexDims; + vTexDims.x = curvb.tex0.tw; + vTexDims.y = curvb.tex0.th; + + // look at the offset of tbp0 from fbp + if( curvb.tex0.tbp0 <= ptextarg->fbp ) { + vTexDims.z = 0;//-0.5f/(float)ptextarg->fbw; + vTexDims.w = 0;//0.2f/(float)ptextarg->fbh; + } + else { + u32 tbp0 = curvb.tex0.tbp0 >> 5; // align to a page + int blockheight = (ptextarg->psm&2) ? 64 : 32; + int ycoord = ((curvb.tex0.tbp0-ptextarg->fbp)/(32*(ptextarg->fbw>>6))) * blockheight; + int xcoord = (((curvb.tex0.tbp0-ptextarg->fbp)%(32*(ptextarg->fbw>>6)))) * 2; + vTexDims.z = (float)xcoord; + vTexDims.w = (float)ycoord; + } + + if( shadertype == 4 ) { + vTexDims.z += 8.0f; + } + + cgGLSetParameter4fv(pfragment->fTexDims, vTexDims); + + // zoe2 + if( (ptextarg->psm&0x30) == 0x30 ) {//&& (psm&2) == (ptextarg->psm&2) ) { + // target of zbuf has +1 added to it, don't do 16bit + vpageoffset.w = -1; +// Vector valpha2; +// valpha2.x = 1; valpha2.y = 0; +// valpha2.z = -1; valpha2.w = 0; +// SETCONSTF(GPU_TEXALPHA20+context, &valpha2); + } + cgGLSetParameter4fv(pfragment->fPageOffset, vpageoffset); + + if( g_bSaveTex ) + SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_NV, + ptextarg == curvb.prndr ? ptextarg->ptexFeedback : ptextarg->ptex, ptextarg->fbw<fbh<ValidateClut(curvb.tex0) ); +#endif + +//#ifdef ZEROGS_CACHEDCLEAR +// if( !curvb.pmemtarg->ValidateTex(curvb.tex0, true) ) { +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 1); +// SetTexVariablesInt(context, GetTexFilter(curvb.tex1), curvb.tex0, pmemtarg, s_bForceTexFlush); +// vb[context].bVarsTexSync = TRUE; +// } +//#endif + + if( g_bSaveTex ) { + if( g_bSaveTex == 1 ) { + SaveTex(&curvb.tex0, 1); +// CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(curvb.tex0, 0); +// int texheight = (pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult; +// int texwidth = GPU_TEXWIDTH*pmemtarg->widthmult*pmemtarg->channels; +// SaveTexture("real.tga", GL_TEXTURE_RECTANGLE_NV, pmemtarg->ptex->tex, texwidth, texheight); + } + else SaveTex(&curvb.tex0, 0); + } + + int psm = curvb.tex0.psm; + if( PSMT_ISCLUT(curvb.tex0.psm) ) psm = curvb.tex0.cpsm; + + pfragment = LoadShadeEffect(0, GetTexFilter(curvb.tex1), curvb.curprim.fge, + curvb.tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S), + exactcolor, curvb.clamp, context, NULL); + } + + if( pfragment->prog != g_psprog ) { + // programs changed, so reset the texture variables + vb[context].bTexConstsSync = 0; + vb[context].bVarsTexSync = 0; + } + + SetTexVariables(context, pfragment, ptextarg == NULL); + } + else { + pfragment = &ppsRegular[curvb.curprim.fge+2*s_bWriteDepth]; + } + + assert(pfragment != 0 ); + if( curvb.curprim.tme ) { + // have to enable the texture parameters + if( curvb.ptexClamp[0] != 0 ) { + cgGLSetTextureParameter(pfragment->sBitwiseANDX, curvb.ptexClamp[0]); + cgGLEnableTextureParameter(pfragment->sBitwiseANDX); + } + if( curvb.ptexClamp[1] != 0 ) { + cgGLSetTextureParameter(pfragment->sBitwiseANDY, curvb.ptexClamp[1]); + cgGLEnableTextureParameter(pfragment->sBitwiseANDY); + } + if( pfragment->sMemory != NULL && s_ptexCurSet[context] != 0) { + cgGLSetTextureParameter(pfragment->sMemory, s_ptexCurSet[context]); + cgGLEnableTextureParameter(pfragment->sMemory); + } + if( pfragment->sCLUT != NULL && ptexclut != 0 ) { + cgGLSetTextureParameter(pfragment->sCLUT, ptexclut); + cgGLEnableTextureParameter(pfragment->sCLUT); + } + } + + DVProfileFunc _pf4("Flush:before bind"); + GL_REPORT_ERRORD(); + + // set the shaders + SETVERTEXSHADER(pvs[2*((curvb.curprim._val>>1)&3)+8*s_bWriteDepth+context]); + + if( pfragment->prog != g_psprog ) { + cgGLBindProgram(pfragment->prog); + g_psprog = pfragment->prog; + } + + GL_REPORT_ERRORD(); + + DVProfileFunc _pf1("Flush:after bind"); + + BOOL bCanRenderStencil = g_bUpdateStencil && (curvb.prndr->psm&0xf) != 1 && !(curvb.frame.fbm&0x80000000); + if( g_GameSettings & GAME_NOSTENCIL ) + bCanRenderStencil = 0; + + if( s_bDestAlphaTest && bCanRenderStencil) { + glEnable(GL_STENCIL_TEST); + GL_STENCILFUNC(GL_ALWAYS, 0, 0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + } + else glDisable(GL_STENCIL_TEST); + + glDepthMask(!curvb.zbuf.zmsk); + GL_ZTEST(curtest.zte); + if( curtest.zte ) { + if( curtest.ztst > 1 ) g_nDepthUsed = 2; + if( (curtest.ztst == 2) ^ (g_nDepthBias != 0) ) { + g_nDepthBias = curtest.ztst == 2; + //SETRS(D3DRS_DEPTHBIAS, g_nDepthBias?FtoDW(0.0003f):FtoDW(0.000015f)); + } + + glDepthFunc(g_dwZCmp[curtest.ztst]); + +// if( curtest.ztst == 3 ) { +// // gequal +// if( s_vznorm.y == 0 ) { +// s_vznorm.y = 0.00001f; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } +// else { +// if( s_vznorm.y > 0 ) { +// s_vznorm.y = 0; +// SETCONSTF(GPU_ZNORM, s_vznorm); +// } +// } + } + + GL_ALPHATEST(curtest.ate&&USEALPHATESTING); + if( curtest.ate ) { + glAlphaFunc(g_dwAlphaCmp[curtest.atst], b2XAlphaTest ? min(1.0f,(float)curtest.aref * (1/ 127.5f)) : curtest.aref*(1/255.0f)); + } + + if( s_bWriteDepth ) { + if(!curvb.zbuf.zmsk) + curvb.pdepth->SetRenderTarget(1); + else + ResetRenderTarget(1); + } + + if( curvb.curprim.abe ) + SetAlphaVariables(curvb.alpha); + else + glDisable(GL_BLEND); + + // needs to be before RenderAlphaTest + if( curvb.fba.fba || s_bDestAlphaTest ) { + if( gs.pabe || (curvb.fba.fba || bCanRenderStencil) && !(curvb.frame.fbm&0x80000000) ) { + RenderFBA(curvb, pfragment->sOneColor); + } + } + + u32 oldabe = curvb.curprim.abe; + if( gs.pabe ) { + //WARN_LOG("PBE!\n"); + curvb.curprim.abe = 1; + glEnable(GL_BLEND); + } + + if( curvb.curprim.abe ) { + + if( //bCanRenderStencil && + (bNeedBlendFactorInAlpha || ((curtest.ate && curtest.atst>1) && (curtest.aref > 0x80))) ) { + // need special stencil processing for the alpha + RenderAlphaTest(curvb, pfragment->sOneColor); + dwUsingSpecialTesting = 1; + } + + // harvest fishing + Vector v = vAlphaBlendColor;// + Vector(0,0,0,(curvb.test.atst==4 && curvb.test.aref>=128)?-0.004f:0); + if( exactcolor ) { v.y *= 255; v.w *= 255; } + cgGLSetParameter4fv(pfragment->sOneColor, v); + } + else { + // not using blending so set to defaults + Vector v = exactcolor ? Vector(1, 510*255.0f/256.0f, 0, 0) : Vector(1,2*255.0f/256.0f,0,0); + cgGLSetParameter4fv(pfragment->sOneColor, v); + } + + if( s_bDestAlphaTest && bCanRenderStencil ) { + // if not 24bit and can write to high alpha bit + RenderStencil(curvb, dwUsingSpecialTesting); + } + else { + s_stencilref = STENCIL_SPECIAL; + s_stencilmask = STENCIL_SPECIAL; + + // setup the stencil to only accept the test pixels + if( dwUsingSpecialTesting ) { + glEnable(GL_STENCIL_TEST); + glStencilMask(STENCIL_PIXELWRITE); + GL_STENCILFUNC(GL_EQUAL, STENCIL_SPECIAL|STENCIL_PIXELWRITE, STENCIL_SPECIAL); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + } + } + +#ifdef _DEBUG + if( bDestAlphaColor == 1 ) { + WARN_LOG("dest alpha blending! manipulate alpha here\n"); + } +#endif + + if( bCanRenderStencil && gs.pabe ) { + // only render the pixels with alpha values >= 0x80 + GL_STENCILFUNC(GL_EQUAL, s_stencilref|STENCIL_FBA, s_stencilmask|STENCIL_FBA); + } + +// curvb.prndr->SetViewport(); +// pd3dDevice->SetScissorRect(&curvb.prndr->scissorrect); +// glEnable(GL_SCISSOR_TEST); + + GL_REPORT_ERRORD(); + if( !curvb.test.ate || curvb.test.atst > 0 ) { + DRAW(); + } + GL_REPORT_ERRORD(); + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + glDisable(GL_BLEND); + GL_STENCILFUNC_SET(); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + cgGLSetParameter4fv(pfragment->sOneColor, v); + + DRAW(); + + // reset + if( !s_stencilmask ) s_stencilfunc = GL_ALWAYS; + GL_STENCILFUNC_SET(); + } + + GL_REPORT_ERRORD(); + + // more work on alpha failure case + if( curtest.ate && curtest.atst != 1 && curtest.afail > 0 ) { + + // need to reverse the test and disable some targets + glAlphaFunc(g_dwReverseAlphaCmp[curtest.atst], b2XAlphaTest ? min(1.0f,(float)curtest.aref * (1/ 127.5f)) : curtest.aref*(1/255.0f)); + + if( curtest.afail & 1 ) { // front buffer update only + + if( curtest.afail == 3 ) // disable alpha + glColorMask(1,1,1,0); + + glDepthMask(0); + + if( s_bWriteDepth ) + ResetRenderTarget(1); + } + else { + // zbuffer update only + glColorMask(0,0,0,0); + } + + if( gs.pabe && bCanRenderStencil ) { + // only render the pixels with alpha values >= 0x80 + Vector v = vAlphaBlendColor; + if( exactcolor ) { v.y *= 255; v.w *= 255; } + cgGLSetParameter4fv(pfragment->sOneColor, v); + glEnable(GL_BLEND); + GL_STENCILFUNC(GL_EQUAL, s_stencilref|STENCIL_FBA, s_stencilmask|STENCIL_FBA); + } + +// IDirect3DQuery9* pOcclusionQuery; +// u32 numberOfPixelsDrawn; +// +// pd3dDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery); +// +// // Add an end marker to the command buffer queue. +// pOcclusionQuery->Issue(D3DISSUE_BEGIN); + + DRAW(); + GL_REPORT_ERRORD(); + +// pOcclusionQuery->Issue(D3DISSUE_END); + // Force the driver to execute the commands from the command buffer. + // Empty the command buffer and wait until the GPU is idle. +// while(S_FALSE == pOcclusionQuery->GetData( &numberOfPixelsDrawn, sizeof(u32), D3DGETDATA_FLUSH )); +// SAFE_RELEASE(pOcclusionQuery); + + if( gs.pabe ) { + // only render the pixels with alpha values < 0x80 + glDisable(GL_BLEND); + GL_STENCILFUNC_SET(); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + if( exactcolor ) v.y *= 255; + cgGLSetParameter4fv(pfragment->sOneColor, v); + + DRAW(); + + // reset + if( oldabe ) glEnable(GL_BLEND); + + if( !s_stencilmask ) s_stencilfunc = GL_ALWAYS; + GL_STENCILFUNC_SET(); + } + + // restore + + if( (curtest.afail & 1) && !curvb.zbuf.zmsk ) { + glDepthMask(1); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL); + curvb.pdepth->SetRenderTarget(1); + } + } + + GL_COLORMASK(s_dwColorWrite); + + // not needed anymore since rest of ops concentrate on image processing + } + + GL_REPORT_ERRORD(); + + if( dwUsingSpecialTesting ) { + // render the real alpha + glDisable(GL_ALPHA_TEST); + glColorMask(0,0,0,1); + + if( s_bWriteDepth ) { + ResetRenderTarget(1); + } + + glDepthMask(0); + + glStencilFunc(GL_EQUAL, STENCIL_SPECIAL|STENCIL_PIXELWRITE, STENCIL_SPECIAL|STENCIL_PIXELWRITE); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + Vector v = Vector(0,exactcolor ? 510.0f : 2.0f,0,0); + cgGLSetParameter4fv(pfragment->sOneColor, v); + DRAW(); + + // don't need to restore + } + + GL_REPORT_ERRORD(); + + if( s_bDestAlphaTest ) { + if( (s_dwColorWrite&COLORMASK_ALPHA) ) { + if( curvb.fba.fba ) + ProcessFBA(curvb, pfragment->sOneColor); + else if( bCanRenderStencil ) + // finally make sure all entries are 1 when the dest alpha >= 0x80 (if fba is 1, this is already the case) + ProcessStencil(curvb); + } + } + else if( (s_dwColorWrite&COLORMASK_ALPHA) && curvb.fba.fba ) + ProcessFBA(curvb, pfragment->sOneColor); + + if( bDestAlphaColor == 1 ) { + // need to reset the dest colors to their original counter parts + //WARN_LOG("Need to reset dest alpha color\n"); + } + +#ifdef _DEBUG + if( g_bSaveFlushedFrame & 0xf ) { +#ifdef _WIN32 + CreateDirectory("frames", NULL); +#else + mkdir("frames", 0755); +#endif + char str[255]; + sprintf(str, "frames/frame%.4d.tga", g_SaveFrameNum++); + if( (g_bSaveFlushedFrame & 2) ) { + //glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer + //glFlush(); + //SaveTexture("tex.jpg", GL_TEXTURE_RECTANGLE_NV, curvb.prndr->ptex, curvb.prndr->fbw<fbh<fbw<fbh<SetRenderTarget(1); + } + } + + if( curvb.test.ate && USEALPHATESTING ) + glEnable(GL_ALPHA_TEST); + + GL_ZTEST(curtest.zte); + } + + if( dwFilterOpts ) { + // undo filter changes (binding didn't change) + if( dwFilterOpts & 1 ) glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if( dwFilterOpts & 2 ) glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + +//#ifndef RELEASE_TO_PUBLIC + ppf += curvb.nCount+0x100000; +//#endif + + curvb.nCount = 0; + curvb.curprim.abe = oldabe; + //if( oldabe ) glEnable(GL_BLEND); + + if( conf.options & GSOPTION_WIREFRAME ) { + // always render first few geometry as solid + if( s_nWireframeCount > 0 ) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + --s_nWireframeCount; + } + } + + GL_REPORT_ERRORD(); +} + +void ZeroGS::ProcessMessages() +{ + if( listMsgs.size() > 0 ) { + int left = 25, top = 15; + list::iterator it = listMsgs.begin(); + + while( it != listMsgs.end() ) { + DrawText(it->str, left+1, top+1, 0xff000000); + DrawText(it->str, left, top, 0xffffff30); + top += 15; + + if( (int)(it->dwTimeStamp - timeGetTime()) < 0 ) + it = listMsgs.erase(it); + else ++it; + } + } +} + +void ZeroGS::RenderCustom(float fAlpha) +{ + GLenum err = GL_NO_ERROR; + + GL_REPORT_ERROR(); + + fAlpha = 1; + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer + + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(1,1,1,1); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glDisable(GL_SCISSOR_TEST); + glViewport(0, 0, nBackbufferWidth, nBackbufferHeight); + + // play custom animation + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); + + // tex coords + Vector v = Vector(1/32767.0f, 1/32767.0f, 0, 0); + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + v.x = (float)nLogoWidth; + v.y = (float)nLogoHeight; + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + v.x = v.y = v.z = v.w = fAlpha; + cgGLSetParameter4fv(ppsBaseTexture.sOneColor, v); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + // inside vb[0]'s target area, so render that region only + cgGLSetTextureParameter(ppsBaseTexture.sFinal, ptexLogo); + cgGLEnableTextureParameter(ppsBaseTexture.sFinal); + + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + SET_STREAM(); + + SETVERTEXSHADER(pvsBitBlt.prog); + SETPIXELSHADER(ppsBaseTexture.prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // restore + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + ProcessMessages(); + +#ifdef _WIN32 + SwapBuffers(hDC); +#else + glXSwapBuffers(GLWin.dpy, GLWin.win); +#endif + + glEnable(GL_SCISSOR_TEST); + glEnable(GL_STENCIL_TEST); + + vb[0].bSyncVars = 0; + vb[1].bSyncVars = 0; + + GL_REPORT_ERROR(); + GLint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + assert( status == GL_FRAMEBUFFER_COMPLETE_EXT || status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT ); +} + +// adjusts trans to preserve aspect ratio +void ZeroGS::AdjustTransToAspect(Vector& v, int dispwidth, int dispheight) +{ + double temp; + float f; + if( dispwidth * nBackbufferHeight > dispheight * nBackbufferWidth) { + // limited by width + + // change in ratio + f = ((float)nBackbufferWidth / (float)dispwidth) / ((float)nBackbufferHeight / (float)dispheight); + v.y *= f; + v.w *= f; + + // scanlines mess up when not aligned right + v.y += (1-(float)modf(v.y*(float)nBackbufferHeight*0.5f+0.05f, &temp))*2.0f/(float)nBackbufferHeight; + v.w += (1-(float)modf(v.w*(float)nBackbufferHeight*0.5f+0.05f, &temp))*2.0f/(float)nBackbufferHeight; + } + else { + // limited by height + f = ((float)nBackbufferHeight / (float)dispheight) / ((float)nBackbufferWidth / (float)dispwidth); + f -= (float)modf(f*nBackbufferWidth, &temp)/(float)nBackbufferWidth; + v.x *= f; + v.z *= f; + } + +// v.y *= -1; +// v.w *= -1; + v *= 1/32767.0f; +} + +void ZeroGS::Restore() +{ + if( !g_bIsLost ) + return; + + //if( SUCCEEDED(pd3dDevice->Reset(&d3dpp)) ) { + g_bIsLost = 0; + // handle lost states + ZeroGS::ChangeDeviceSize(nBackbufferWidth, nBackbufferHeight); + //} +} + +void ZeroGS::RenderCRTC(int interlace) +{ + if( g_bIsLost ) return; + +// Crashes Final Fantasy X at startup if uncommented. --arcum42 +//#ifdef RELEASE_TO_PUBLIC +// if(g_nRealFrame < 80 ) { +// RenderCustom( min(1.0f, 2.0f - (float)g_nRealFrame / 40.0f) ); +// +// if( g_nRealFrame == 79 ) +// SAFE_RELEASE_TEX(ptexLogo); +// return; +// } +//#endif + + if( conf.mrtdepth && pvs[8] == NULL ) { + conf.mrtdepth = 0; + s_bWriteDepth = FALSE; + ERROR_LOG("Disabling MRT depth writing\n"); + } + + Flush(0); + Flush(1); + GL_REPORT_ERRORD(); + + DVProfileFunc _pf("RenderCRTC"); + + // frame skipping + if( g_nFrameRender > 0 ) { + + if( g_nFrameRender < 8 ) { + g_nFrameRender++; + if( g_nFrameRender <= 3 ) { + g_nFramesSkipped++; + return; + } + } + } + else { + if( g_nFrameRender < -1 ) { + g_nFramesSkipped++; + return; + } + g_nFrameRender--; + } + + if( g_bSaveFrame ) { + if( vb[0].prndr != NULL ) { + SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, vb[0].prndr->ptex, vb[0].prndr->fbw<fbh<ptex, vb[1].prndr->fbw<fbh< 0 ) + FlushTransferRanges(NULL); + + //g_GameSettings |= GAME_VSSHACK|GAME_FULL16BITRES|GAME_NODEPTHRESOLVE; + //s_bWriteDepth = TRUE; + g_SaveFrameNum = 0; + g_bSaveFlushedFrame = 1; + + // reset fba after every frame + vb[0].fba.fba = 0; + vb[1].fba.fba = 0; + +// static int counter = 0; +// counter++; + u32 bInterlace = SMODE2->INT && SMODE2->FFMD && (conf.interlace<2); + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer + glViewport(0, 0, nBackbufferWidth, nBackbufferHeight); + + // if interlace, only clear every other vsync + if(!bInterlace ) { + u32 color = COLOR_ARGB(0, BGCOLOR->R, BGCOLOR->G, BGCOLOR->B); + glClear(GL_COLOR_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); + } + + SETVERTEXSHADER(pvsBitBlt.prog); + glBindBuffer(GL_ARRAY_BUFFER, vboRect); + SET_STREAM(); + GL_REPORT_ERRORD(); + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(1,1,1,1); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); + + GL_REPORT_ERRORD(); + + BOOL bUsingStencil = 0; + + if( bInterlace ) g_PrevBitwiseTexX = -1; // reset since will be using + + tex0Info dispinfo[2]; + + for(int i = 0; i < 2; ++i) { + + if( !(*(u32*)(PMODE) & (1<MAGH+1; + int magv = pd->MAGV+1; + + dispinfo[i].tbp0 = pfb->FBP << 5; + dispinfo[i].tbw = pfb->FBW << 6; + dispinfo[i].tw = (pd->DW + 1) / magh; + dispinfo[i].th = (pd->DH + 1) / magv; + dispinfo[i].psm = pfb->PSM; + + // hack!! + // 2 * dispinfo[i].tw / dispinfo[i].th <= 1, metal slug 4 + if( bInterlace && 2 * dispinfo[i].tw / dispinfo[i].th <= 1 && !(g_GameSettings&GAME_INTERLACE2X) ) { + dispinfo[i].th >>= 1; + } + } + + //int dispwidth = max(dispinfo[0].tw, dispinfo[1].tw), dispheight = max(dispinfo[0].th, dispinfo[1].th); + + // hack!, CMOD != 3, gradius +// if( SMODE2->INT && SMODE2->FFMD && SMODE1->CMOD == 3 && dispwidth <= 320) +// dispwidth *= 2; + + // hack! makai + //if( !bInterlace && dispheight * 2 < dispwidth ) dispheight *= 2; + + // start from the last circuit + for(int i = !PMODE->SLBG; i >= 0; --i) { + + tex0Info& texframe = dispinfo[i]; + if( texframe.th <= 1 ) + continue; + + GSRegDISPFB* pfb = i ? DISPFB2 : DISPFB1; + GSRegDISPLAY* pd = i ? DISPLAY2 : DISPLAY1; + + Vector v, valpha; + u32 interlacetex = 0; + + if( bInterlace ) { + + texframe.th >>= 1; + + // interlace mode + interlacetex = CreateInterlaceTex(2*texframe.th); + + if( interlace == (conf.interlace&1) ) { + // pass if odd + valpha.z = 1.0f; + valpha.w = -0.4999f; + } + else { + // pass if even + valpha.z = -1.0f; + valpha.w = 0.5001f; + } + } + else { + + if( SMODE2->INT && SMODE2->FFMD ) { + texframe.th >>= 1; + } + + // always pass interlace test + valpha.z = 0; + valpha.w = 1; + } + + int bpp = 4; + if( texframe.psm == 0x12 ) bpp = 3; + else if( texframe.psm & 2 ) bpp = 2; + + // get the start and end addresses of the buffer + int start, end; + GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); + + if( i == 0 ) { + // setup right blending + glEnable(GL_BLEND); + zgsBlendEquationSeparateEXT(GL_FUNC_ADD, GL_FUNC_ADD); + + if( PMODE->MMOD ) { + glBlendColorEXT(PMODE->ALP*(1/255.0f), PMODE->ALP*(1/255.0f), PMODE->ALP*(1/255.0f), 0.5f); + s_srcrgb = GL_CONSTANT_COLOR_EXT; + s_dstrgb = GL_ONE_MINUS_CONSTANT_COLOR_EXT; + } + else { + s_srcrgb = GL_SRC_ALPHA; + s_dstrgb = GL_ONE_MINUS_SRC_ALPHA; + } + + s_srcalpha = PMODE->AMOD ? GL_ZERO : GL_ONE; + s_dstalpha = PMODE->AMOD? GL_ONE : GL_ZERO; + zgsBlendFuncSeparateEXT(s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha); + } + + if( bUsingStencil ) { + glStencilMask(1< listTargs; + + s_RTs.GetTargs(start, end, listTargs); + + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ) { + + CRenderTarget* ptarg = *it; + + if( ptarg->fbw == texframe.tbw && !(ptarg->status&CRenderTarget::TS_NeedUpdate) && ((256/bpp)*(texframe.tbp0-ptarg->fbp))%texframe.tbw == 0 ) { + + if( ptarg->fbp != texframe.tbp0 ) { + // look for a better target (metal slug 5) + list::iterator itbetter; + for(itbetter = listTargs.begin(); itbetter != listTargs.end(); ++itbetter ) { + if( (*itbetter)->fbp == texframe.tbp0 ) + break; + } + + if( itbetter != listTargs.end() ) { + it = listTargs.erase(it); + continue; + } + } + + if( g_bSaveFinalFrame ) + SaveTexture("frame1.tga", GL_TEXTURE_RECTANGLE_NV, ptarg->ptex, ptarg->fbw<fbh<DBY; + int movy = 0; + + // determine the rectangle to render + if( ptarg->fbp < texframe.tbp0 ) { + dby += (256/bpp)*(texframe.tbp0-ptarg->fbp)/texframe.tbw; + } + else if( ptarg->fbp > texframe.tbp0 ) { + dby -= (256/bpp)*(ptarg->fbp-texframe.tbp0)/texframe.tbw; + + if( dby < 0 ) { + movy = -dby; + dby = 0; + } + } + + int dh = min(ptarg->fbh - dby, texframe.th-movy); + + if( dh >= 64 ) { + + if( ptarg->fbh - dby < texframe.th-movy && !bUsingStencil ) { + + if( !bUsingStencil ) { + glClear(GL_STENCIL_BUFFER_BIT); + } + bUsingStencil = 1; + glEnable(GL_STENCIL_TEST); + GL_STENCILFUNC(GL_NOTEQUAL, 3, 1<fbh; + + // tex coords + v = Vector((float)(texframe.tw << s_AAx), (float)(dh << s_AAy), (float)(pfb->DBX << s_AAx), (float)(dby< 0 ) + v.w -= movy/(float)texframe.th; + + if (bInterlace && interlace == (conf.interlace&1) ) { + // move down by 1 pixel + v.w += 1.0f / (float)dh; + } + + AdjustTransToAspect(v, 640, 480); + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + cgGLSetParameter4fv(pvsBitBlt.fBitBltTrans, Vector(fih * 0.5f, fih * -0.5f, fih * 0.5f, fih * 0.5f)); + + // use g_fInvTexDims to store inverse texture dims + if( ppsCRTCTarg[bInterlace].sInvTexDims ) { + v.x = fiw; + v.y = fih; + v.z = 0; + cgGLSetParameter4fv(ppsCRTCTarg[bInterlace].sInvTexDims, v); + } + + cgGLSetParameter4fv(ppsCRTCTarg[bInterlace].sOneColor, valpha); + + // inside vb[0]'s target area, so render that region only + cgGLSetTextureParameter(ppsCRTCTarg[bInterlace].sFinal, ptarg->ptex); + cgGLEnableTextureParameter(ppsCRTCTarg[bInterlace].sFinal); + if( interlacetex != 0 ) { + cgGLSetTextureParameter(ppsCRTCTarg[bInterlace].sInterlace, interlacetex); + cgGLEnableTextureParameter(ppsCRTCTarg[bInterlace].sInterlace); + } + + SETPIXELSHADER(ppsCRTCTarg[bInterlace].prog); + GL_REPORT_ERRORD(); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + //SaveRenderTarget("temp.tga", nBackbufferWidth, nBackbufferHeight, 0); + + if( abs(dh - (int)texframe.th) <= 1 ) { + bSkip = 1; + break; + } + if( abs(dh - (int)ptarg->fbh) <= 1 ) { + it = listTargs.erase(it); + continue; + } + } + } + + ++it; + } + + if( !bSkip ) { + for(list::iterator it = listTargs.begin(); it != listTargs.end(); ++it) + (*it)->Resolve(); + + // context has to be 0 + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(texframe, 1); + SetTexVariablesInt(0, g_bCRTCBilinear?2:0, texframe, pmemtarg, &ppsCRTC[bInterlace], 1); + cgGLSetTextureParameter(ppsCRTC[bInterlace].sMemory, pmemtarg->ptex->tex); + cgGLEnableTextureParameter(ppsCRTC[bInterlace].sMemory); + + if( g_bSaveFinalFrame ) + SaveTex(&texframe, g_bSaveFinalFrame-1>0); + + // finally render from the memory (note that the stencil buffer will keep previous regions) + v = Vector(1,1,0,0); + + if (bInterlace && interlace == (conf.interlace)) { + // move down by 1 pixel + v.w += 1.0f / (float)texframe.th; + } + + cgGLSetParameter4fv(ppsCRTC[bInterlace].sOneColor, valpha); + + AdjustTransToAspect(v, 640, 480); + cgGLSetParameter4fv(pvsBitBlt.sBitBltPos, v); + + float fih = 1.0f / (float)texframe.th; + if( g_bCRTCBilinear ) + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, Vector(texframe.tw,texframe.th,-0.5f,-0.5f)); + else + cgGLSetParameter4fv(pvsBitBlt.sBitBltTex, Vector(1,1,-0.5f/(float)texframe.tw,-0.5f/(float)texframe.th)); + + cgGLSetParameter4fv(pvsBitBlt.fBitBltTrans, Vector(fih * 0.5f, fih * -0.5f, fih * 0.5f, fih * 0.5f)); + + // use g_fInvTexDims to store inverse texture dims + if( ppsCRTC[bInterlace].sInvTexDims ) { + v.x = 1.0f / (float)texframe.tw; + v.y = fih; + v.z = 0;//-0.5f * v.x; + v.w = -0.5f * fih; + cgGLSetParameter4fv(ppsCRTC[bInterlace].sInvTexDims, v); + } + + if( interlacetex != 0 ) { + cgGLSetTextureParameter(ppsCRTC[bInterlace].sInterlace, interlacetex); + cgGLEnableTextureParameter(ppsCRTC[bInterlace].sInterlace); + } + + SETPIXELSHADER(ppsCRTC[bInterlace].prog); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + } + + GL_REPORT_ERRORD(); + if(1) {// || !bInterlace) { + glDisable(GL_BLEND); + ProcessMessages(); + + if( g_bMakeSnapshot ) { + char str[64]; + int left = 200, top = 15; + sprintf(str, "ZeroGS %d.%d.%d - %.1f fps %s", zgsrevision, zgsbuild, zgsminor, fFPS, s_frameskipping?" - frameskipping":""); + + DrawText(str, left+1, top+1, 0xff000000); + DrawText(str, left, top, 0xffc0ffff); + } + + if( g_bDisplayFPS ) { + char str[64]; + int left = 10, top = 15; + sprintf(str, "%.1f fps", fFPS); + + DrawText(str, left+1, top+1, 0xff000000); + DrawText(str, left, top, 0xffc0ffff); + } + + if (glGetError() != GL_NO_ERROR) DEBUG_LOG("glerror before swap!\n"); + + +#ifdef _WIN32 + static u32 lastswaptime = 0; + //if( timeGetTime() - lastswaptime > 14 ) { + SwapBuffers(hDC); + lastswaptime = timeGetTime(); + //} +#else + glXSwapBuffers(GLWin.dpy, GLWin.win); +#endif + +// if( glGetError() != GL_NO_ERROR) { +// // device is lost, need to recreate +// ERROR_LOG("device lost\n"); +// g_bIsLost = TRUE; +// Reset(); +// return; +// } + + if( conf.options & GSOPTION_WIREFRAME ) { + // clear all targets + s_nWireframeCount = 1; + } + + if( g_bMakeSnapshot ) { + + if( SaveRenderTarget(strSnapshot != ""?strSnapshot.c_str():"temp.jpg", nBackbufferWidth, -nBackbufferHeight, 0)) {//(conf.options&GSOPTION_TGASNAP)?0:1) ) { + char str[255]; + sprintf(str, "saved %s\n", strSnapshot.c_str()); + AddMessage(str, 500); + } + + g_bMakeSnapshot = 0; + } + + if( s_avicapturing ) { + CaptureFrame(); + } + + if( s_nNewWidth >= 0 && s_nNewHeight >= 0 && !g_bIsLost ) { + Reset(); + ChangeDeviceSize(s_nNewWidth, s_nNewHeight); + s_nNewWidth = s_nNewHeight = -1; + } + + // switch the fbp lists +// s_nCurFBPSet ^= 1; +// s_setFBP[s_nCurFBPSet].clear(); + //s_nCurFrameMap ^= 1; + //s_mapFrameHeights[s_nCurFrameMap].clear(); + } + + // switch back to rendering to textures + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); + + g_MemTargs.DestroyCleared(); + + if( s_vecTempTextures.size() > 0 ) + glDeleteTextures((GLsizei)s_vecTempTextures.size(), &s_vecTempTextures[0]); + s_vecTempTextures.clear(); + + if( EXTWRITE->WRITE&1 ) { + WARN_LOG("EXTWRITE\n"); + ExtWrite(); + EXTWRITE->WRITE = 0; + } + + if( conf.options & GSOPTION_WIREFRAME ) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glEnable(GL_SCISSOR_TEST); + + if( icurctx >= 0 ) { + vb[icurctx].bVarsSetTarg = FALSE; + vb[icurctx].bVarsTexSync = FALSE; + vb[0].bVarsTexSync = FALSE; + } + + // statistics + if( s_nWriteDepthCount > 0 ) { + assert( conf.mrtdepth ); + if( --s_nWriteDepthCount <= 0 ) { + s_bWriteDepth = FALSE; + } + } + + if( s_nWriteDestAlphaTest > 0 ) { + if( --s_nWriteDestAlphaTest <= 0 ) { + s_bDestAlphaTest = FALSE; + } + } + + if( g_GameSettings & GAME_AUTORESET ) { + s_nResolveCounts[s_nCurResolveIndex] = s_nResolved; + s_nCurResolveIndex = (s_nCurResolveIndex+1)%ARRAY_SIZE(s_nResolveCounts); + + int total = 0; + for(int i = 0; i < ARRAY_SIZE(s_nResolveCounts); ++i) total += s_nResolveCounts[i]; + + if( total / ARRAY_SIZE(s_nResolveCounts) > 3 ) { + if( s_nLastResolveReset > (int)(fFPS * 8) ) { + // reset + ERROR_LOG("video mem reset\n"); + s_nLastResolveReset = 0; + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + + s_RTs.ResolveAll(); + s_RTs.Destroy(); + s_DepthRTs.ResolveAll(); + s_DepthRTs.Destroy(); + + vb[0].prndr = NULL; vb[0].pdepth = NULL; vb[0].bNeedFrameCheck = 1; vb[0].bNeedZCheck = 1; + vb[1].prndr = NULL; vb[1].pdepth = NULL; vb[1].bNeedFrameCheck = 1; vb[1].bNeedZCheck = 1; + } + } + + s_nLastResolveReset++; + } + + if( s_nResolved > 8 ) s_nResolved = 2; + else if( s_nResolved > 0 ) --s_nResolved; + + if( g_nDepthUsed > 0 ) --g_nDepthUsed; + + s_ClutResolve = 0; + g_nDepthUpdateCount = 0; + + maxmin = 608; +} + +////////////////////////// +// Internal Definitions // +////////////////////////// + + +__forceinline void MOVZ(VertexGPU *p, u32 gsz, const VB& curvb) +{ + p->z = curvb.zprimmask==0xffff?min((u32)0xffff, gsz):gsz; +} + +__forceinline void MOVFOG(VertexGPU *p, Vertex gsf) +{ + p->f = ((s16)(gsf).f<<7)|0x7f; +} + +__forceinline void SET_VERTEX(VertexGPU *p, int Index, const VB& curvb) +{ + int index = Index; + + p->x = (((int)gs.gsvertex[index].x - curvb.offset.x)>>1)&0xffff; + p->y = (((int)gs.gsvertex[index].y - curvb.offset.y)>>1)&0xffff; + + /*x = ((int)gs.gsvertex[index].x - curvb.offset.x); + y = ((int)gs.gsvertex[index].y - curvb.offset.y); + p.x = (x&0x7fff) | (x < 0 ? 0x8000 : 0); + p.y = (y&0x7fff) | (y < 0 ? 0x8000 : 0);*/ + + p->f = ((s16)gs.gsvertex[index].f<<7)|0x7f; + MOVZ(p, gs.gsvertex[index].z, curvb); + p->rgba = prim->iip ? gs.gsvertex[index].rgba : gs.rgba; + + if ((g_GameSettings & GAME_TEXAHACK) && !(p->rgba&0xffffff)) + p->rgba = 0; + if (prim->tme ) + { + if( prim->fst ) + { + p->s = (float)gs.gsvertex[index].u * fiTexWidth[prim->ctxt]; + p->t = (float)gs.gsvertex[index].v * fiTexHeight[prim->ctxt]; + p->q = 1; + } + else + { + p->s = gs.gsvertex[index].s; + p->t = gs.gsvertex[index].t; + p->q = gs.gsvertex[index].q; + } + } +} + +#define OUTPUT_VERT(fn, vert, id) { \ + fn("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)\n", id==0?'*':' ', id, prim->prim, vert.x/8, vert.y/8, vert.z, vert.f/128, \ + vert.rgba, Clamp(vert.s, -10, 10), Clamp(vert.t, -10, 10), Clamp(vert.q, -10, 10)); \ +} \ + +void ZeroGS::KickPoint() +{ + assert( gs.primC >= 1 ); + + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(1); + + int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(&p[0], last, curvb); + curvb.nCount++; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); +#endif +} + +void ZeroGS::KickLine() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + if( curvb.bNeedTexCheck ) + curvb.FlushTexData(); + + if( vb[!prim->ctxt].nCount > 0 && vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp ) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(2); + + int next = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(&p[0], next, curvb); + SET_VERTEX(&p[1], last, curvb); + + curvb.nCount += 2; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickTriangle() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(3); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(&p[0], 0, curvb); + SET_VERTEX(&p[1], 1, curvb); + SET_VERTEX(&p[2], 2, curvb); + + curvb.nCount += 3; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +void ZeroGS::KickTriangleFan() +{ + assert( gs.primC >= 3 ); + VB& curvb = vb[prim->ctxt]; + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(3); + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + SET_VERTEX(&p[0], 0, curvb); + SET_VERTEX(&p[1], 1, curvb); + SET_VERTEX(&p[2], 2, curvb); + + curvb.nCount += 3; + + // add 1 to skip the first vertex + if (gs.primIndex == gs.nTriFanVert) + gs.primIndex = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); + OUTPUT_VERT(PRIM_LOG, p[2], 2); +#endif +} + +__forceinline void SetKickVertex(VertexGPU *p, Vertex v, int next, const VB& curvb) +{ + SET_VERTEX(p, next, curvb); + MOVZ(p, v.z, curvb); + MOVFOG(p, v); +} + +void ZeroGS::KickSprite() +{ + assert( gs.primC >= 2 ); + VB& curvb = vb[prim->ctxt]; + + if (curvb.bNeedTexCheck) curvb.FlushTexData(); + + if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) + { + assert( vb[prim->ctxt].nCount == 0 ); + Flush(!prim->ctxt); + } + + curvb.NotifyWrite(6); + + int next = (gs.primIndex+1)%ARRAY_SIZE(gs.gsvertex); + int last = (gs.primIndex+2)%ARRAY_SIZE(gs.gsvertex); + + // sprite is too small and AA shows lines (tek4) + if ( s_AAx ) + { + gs.gsvertex[last].x += 4; + if( s_AAy ) gs.gsvertex[last].y += 4; + } + + // might be bad sprite (KH dialog text) + //if( gs.gsvertex[next].x == gs.gsvertex[last].x || gs.gsvertex[next].y == gs.gsvertex[last].y ) + //return; + + VertexGPU* p = curvb.pBufferData+curvb.nCount; + + SetKickVertex(&p[0], gs.gsvertex[last], next, curvb); + SetKickVertex(&p[3], gs.gsvertex[last], next, curvb); + SetKickVertex(&p[1], gs.gsvertex[last], last, curvb); + SetKickVertex(&p[4], gs.gsvertex[last], last, curvb); + SetKickVertex(&p[2], gs.gsvertex[last], next, curvb); + + p[2].s = p[1].s; + p[2].x = p[1].x; + + SetKickVertex(&p[5], gs.gsvertex[last], last, curvb); + p[5].s = p[0].s; + p[5].x = p[0].x; + + curvb.nCount += 6; + +#ifdef PRIM_LOG + OUTPUT_VERT(PRIM_LOG, p[0], 0); + OUTPUT_VERT(PRIM_LOG, p[1], 1); +#endif +} + +void ZeroGS::KickDummy() +{ + //GREG_LOG("Kicking bad primitive: %.8x\n", *(u32*)prim); +} + +__forceinline void ZeroGS::RenderFBA(const VB& curvb, CGparameter sOneColor) +{ + // add fba to all pixels + GL_STENCILFUNC(GL_ALWAYS, STENCIL_FBA, 0xff); + glStencilMask(STENCIL_CLEAR); + glStencilOp(GL_ZERO, GL_KEEP, GL_REPLACE); + + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(0,0,0,0); + + if( s_bWriteDepth ) ResetRenderTarget(1); + + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GEQUAL, 1); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + cgGLSetParameter4fv(sOneColor, v); + + DRAW(); + + if( !curvb.test.ate ) + glDisable(GL_ALPHA_TEST); + else + glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], b2XAlphaTest ? min(1.0f,curvb.test.aref*(1/127.5f)) : curvb.test.aref*(1/255.0f)); + + // reset (not necessary) + GL_COLORMASK(s_dwColorWrite); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + if( !curvb.zbuf.zmsk ) + { + glDepthMask(1); + + assert( curvb.pdepth != NULL ); + if( s_bWriteDepth ) curvb.pdepth->SetRenderTarget(1); + } + GL_ZTEST(curvb.test.zte); +} + +__forceinline void ZeroGS::RenderAlphaTest(const VB& curvb, CGparameter sOneColor) +{ + if( !g_bUpdateStencil ) return; + + if( curvb.test.ate ) + if( curvb.test.afail == 1 ) glDisable(GL_ALPHA_TEST); + + glDepthMask(0); + glColorMask(0,0,0,0); + + Vector v; + v.x = 1; v.y = 2; v.z = 0; v.w = 0; + cgGLSetParameter4fv(sOneColor, v); + + if (s_bWriteDepth) ResetRenderTarget(1); + + // or a 1 to the stencil buffer wherever alpha passes + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + s_stencilfunc = GL_ALWAYS; + + glEnable(GL_STENCIL_TEST); + + if( !s_bDestAlphaTest ) + { + // clear everything + s_stencilref = 0; + glStencilMask(STENCIL_CLEAR); + glDisable(GL_ALPHA_TEST); + GL_STENCILFUNC_SET(); + DRAW(); + + if( curvb.test.ate && curvb.test.afail != 1 && USEALPHATESTING ) + glEnable(GL_ALPHA_TEST); + } + + if( curvb.test.ate && curvb.test.atst>1 && curvb.test.aref > 0x80) + { + v.x = 1; v.y = 1; v.z = 0; v.w = 0; + cgGLSetParameter4fv(sOneColor, v); + glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], curvb.test.aref*(1/255.0f)); + } + + s_stencilref = STENCIL_SPECIAL; + glStencilMask(STENCIL_SPECIAL); + GL_STENCILFUNC_SET(); + glDisable(GL_DEPTH_TEST); + + DRAW(); + + if( curvb.test.zte ) + glEnable(GL_DEPTH_TEST); + GL_ALPHATEST(0); + GL_COLORMASK(s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) + { + glDepthMask(1); + + // set rt next level + if (s_bWriteDepth) curvb.pdepth->SetRenderTarget(1); + } +} + +__forceinline void ZeroGS::RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting) +{ + //NOTE: This stencil hack for dest alpha testing ONLY works when + // the geometry in one DrawPrimitive call does not overlap + + // mark the stencil buffer for the new data's bits (mark 4 if alpha is >= 0xff) + // mark 4 if a pixel was written (so that the stencil buf can be changed with new values) + glStencilMask(STENCIL_PIXELWRITE); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + s_stencilmask = (curvb.test.date?STENCIL_ALPHABIT:0)|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + s_stencilfunc = s_stencilmask ? GL_EQUAL : GL_ALWAYS; + s_stencilref = curvb.test.date*curvb.test.datm|STENCIL_PIXELWRITE|(dwUsingSpecialTesting?STENCIL_SPECIAL:0); + GL_STENCILFUNC_SET(); +} + +__forceinline void ZeroGS::ProcessStencil(const VB& curvb) +{ + assert( !curvb.fba.fba ); + + // set new alpha bit + glStencilMask(STENCIL_ALPHABIT); + GL_STENCILFUNC(GL_EQUAL, STENCIL_PIXELWRITE, STENCIL_PIXELWRITE|STENCIL_FBA); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(0,0,0,0); + + if (s_bWriteDepth) ResetRenderTarget(1); + + GL_ALPHATEST(0); + + SETPIXELSHADER(ppsOne.prog); + DRAW(); + + // process when alpha >= 0xff + GL_STENCILFUNC(GL_EQUAL, STENCIL_PIXELWRITE|STENCIL_FBA|STENCIL_ALPHABIT, STENCIL_PIXELWRITE|STENCIL_FBA); + DRAW(); + + // clear STENCIL_PIXELWRITE bit + glStencilMask(STENCIL_CLEAR); + GL_STENCILFUNC(GL_ALWAYS, 0, STENCIL_PIXELWRITE|STENCIL_FBA); + + DRAW(); + + // restore state + GL_COLORMASK(s_dwColorWrite); + + if( curvb.test.ate && USEALPHATESTING) + glEnable(GL_ALPHA_TEST); + + if( !curvb.zbuf.zmsk ) { + glDepthMask(1); + + if( s_bWriteDepth ) { + assert( curvb.pdepth != NULL ); + curvb.pdepth->SetRenderTarget(1); + } + } + + GL_ZTEST(curvb.test.zte); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); +} + +__forceinline void ZeroGS::ProcessFBA(const VB& curvb, CGparameter sOneColor) +{ + if( (curvb.frame.fbm&0x80000000) ) return; + + // add fba to all pixels that were written and alpha was less than 0xff + glStencilMask(STENCIL_ALPHABIT); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + GL_STENCILFUNC(GL_EQUAL, STENCIL_FBA|STENCIL_PIXELWRITE|STENCIL_ALPHABIT, STENCIL_PIXELWRITE|STENCIL_FBA); + + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glColorMask(0,0,0,1); + + if( s_bWriteDepth ) { + ResetRenderTarget(1); + } + + // processes the pixels with ALPHA < 0x80*2 + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_LEQUAL, 1); + + // add 1 to dest + GL_BLEND_ALPHA(GL_ONE, GL_ONE); + GL_BLENDEQ_ALPHA(GL_FUNC_ADD); + + float f = 1; + cgGLSetParameter4fv(sOneColor, &f); + SETPIXELSHADER(ppsOne.prog); + + DRAW(); + + glDisable(GL_ALPHA_TEST); + + // reset bits + glStencilMask(STENCIL_CLEAR); + GL_STENCILFUNC(GL_GREATER, 0, STENCIL_PIXELWRITE|STENCIL_FBA); + glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + + DRAW(); + + if( curvb.test.atst && USEALPHATESTING) { + glEnable(GL_ALPHA_TEST); + glAlphaFunc(g_dwAlphaCmp[curvb.test.atst], b2XAlphaTest ? min(1.0f,curvb.test.aref*(1/127.5f)) : curvb.test.aref*(1/255.0f)); + } + + // restore (SetAlphaVariables) + GL_BLEND_ALPHA(GL_ONE, GL_ZERO); + if(vAlphaBlendColor.y<0) GL_BLENDEQ_ALPHA(GL_FUNC_REVERSE_SUBTRACT); + + // reset (not necessary) + GL_COLORMASK(s_dwColorWrite); + + if( !curvb.zbuf.zmsk ) { + glDepthMask(1); + + if (s_bWriteDepth) curvb.pdepth->SetRenderTarget(1); + } + GL_ZTEST(curvb.test.zte); +} + +inline void ZeroGS::SetContextTarget(int context) +{ + VB& curvb = vb[context]; + GL_REPORT_ERRORD(); + + if( curvb.prndr == NULL ) + curvb.prndr = s_RTs.GetTarg(curvb.frame, 0, GET_MAXHEIGHT(curvb.gsfb.fbp, curvb.gsfb.fbw, curvb.gsfb.psm)); + + // make sure targets are valid + if( curvb.pdepth == NULL ) { + frameInfo f; + f.fbp = curvb.zbuf.zbp; + f.fbw = curvb.frame.fbw; + f.fbh = curvb.prndr->fbh; + f.psm = curvb.zbuf.psm; + f.fbm = 0; + curvb.pdepth = (CDepthTarget*)s_DepthRTs.GetTarg(f, CRenderTargetMngr::TO_DepthBuffer|CRenderTargetMngr::TO_StrictHeight| + (curvb.zbuf.zmsk?CRenderTargetMngr::TO_Virtual:0), GET_MAXHEIGHT(curvb.zbuf.zbp, curvb.gsfb.fbw, 0)); + } + + assert( curvb.prndr != NULL && curvb.pdepth != NULL ); + assert( curvb.pdepth->fbh == curvb.prndr->fbh ); + + if( curvb.pdepth->status & CRenderTarget::TS_Virtual) { + + if( !curvb.zbuf.zmsk ) { + CRenderTarget* ptemp = s_DepthRTs.Promote(curvb.pdepth->fbp|(curvb.pdepth->fbw<<16)); + assert( ptemp == curvb.pdepth ); + } + else + curvb.pdepth->status &= ~CRenderTarget::TS_NeedUpdate; + } + + BOOL bSetTarg = 1; + if( curvb.pdepth->status & CRenderTarget::TS_NeedUpdate ) { + + assert( !(curvb.pdepth->status & CRenderTarget::TS_Virtual) ); + + // don't update if virtual + curvb.pdepth->Update(context, curvb.prndr); + bSetTarg = 0; + } + + GL_REPORT_ERRORD(); + if( curvb.prndr->status & CRenderTarget::TS_NeedUpdate ) { + +// if(bSetTarg s_bWriteDepth ) { +// if( s_bWriteDepth ) { +// curvb.pdepth->SetRenderTarget(1); +// curvb.pdepth->SetDepthStencilSurface(); +// } +// else curvb.pdepth->SetDepthStencilSurface(); +// } + + curvb.prndr->Update(context, curvb.pdepth); + } + else { + + //if( (vb[0].prndr != vb[1].prndr && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg ) + curvb.prndr->SetRenderTarget(0); + //if( bSetTarg && ((vb[0].pdepth != vb[1].pdepth && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg) ) + curvb.pdepth->SetDepthStencilSurface(); + + if (conf.mrtdepth && ZeroGS::IsWriteDepth()) curvb.pdepth->SetRenderTarget(1); + + if (s_ptexCurSet[0] == curvb.prndr->ptex) s_ptexCurSet[0] = 0; + if (s_ptexCurSet[1] == curvb.prndr->ptex) s_ptexCurSet[1] = 0; + + curvb.prndr->SetViewport(); + } + + curvb.prndr->SetTarget(curvb.frame.fbp, curvb.scissor, context); + + if( (curvb.zbuf.zbp-curvb.pdepth->fbp) != (curvb.frame.fbp - curvb.prndr->fbp) && curvb.test.zte ) + WARN_LOG("frame and zbuf not aligned\n"); + + curvb.bVarsSetTarg = TRUE; + if( vb[!context].prndr != curvb.prndr ) vb[!context].bVarsSetTarg = FALSE; + + assert( !(curvb.prndr->status&CRenderTarget::TS_NeedUpdate) ); + assert( curvb.pdepth == NULL || !(curvb.pdepth->status&CRenderTarget::TS_NeedUpdate) ); + GL_REPORT_ERRORD(); +} + +void ZeroGS::SetTexVariables(int context, FRAGMENTSHADER* pfragment, int settexint) +{ + if (!vb[context].curprim.tme) return; + + DVProfileFunc _pf("SetTexVariables"); + + assert( !vb[context].bNeedTexCheck ); + + Vector v, v2; + tex0Info& tex0 = vb[context].tex0; + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + if( !vb[context].bTexConstsSync ) { + // alpha and texture highlighting + Vector valpha, valpha2; + + // if clut, use the frame format + int psm = tex0.psm; + if( PSMT_ISCLUT(tex0.psm) ) psm = tex0.cpsm; + + int nNeedAlpha = (psm == 1 || psm == 2 || psm == 10); + + Vector vblack; + vblack.x = vblack.y = vblack.z = vblack.w = 10; + + switch(tex0.tfx) { + case 0: + valpha.z = 0; valpha.w = 0; + valpha2.x = 0; valpha2.y = 0; + valpha2.z = 2; valpha2.w = 1; + + break; + case 1: + valpha.z = 0; valpha.w = 1; + valpha2.x = 1; valpha2.y = 0; + valpha2.z = 0; valpha2.w = 0; + + break; + case 2: + valpha.z = 1; valpha.w = 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + + case 3: + valpha.z = 1; valpha.w = tex0.tcc ? 0.0f : 1.0f; + valpha2.x = 0; valpha2.y = tex0.tcc ? 1.0f : 0.0f; + valpha2.z = 2; valpha2.w = 0; + + break; + } + + if( tex0.tcc ) { + + if( tex0.tfx == 1 ) { + //mode.x = 10; + valpha.z = 0; valpha.w = 0; + valpha2.x = 1; valpha2.y = 1; + valpha2.z = 0; valpha2.w = 0; + } + + if( nNeedAlpha ) { + + if( tex0.tfx == 0 ) { + // make sure alpha is mult by two when the output is Cv = Ct*Cf + valpha.x = 2*gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = 2*gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + else { + valpha.x = gs.texa.fta[0]; + // if 24bit, always choose ta[0] + valpha.y = gs.texa.fta[psm != 1]; + valpha.y -= valpha.x; + } + + // need black detection + if( gs.texa.aem && psm == PSMCT24 ) + vblack.w = 0; + } + else { + if( tex0.tfx == 0 ) { + valpha.x = 0; + valpha.y = 2; + } + else { + valpha.x = 0; + valpha.y = 1; + } + } + } + else { + + // reset alpha to color + valpha.x = valpha.y = 0; + valpha.w = 1; + } + + cgGLSetParameter4fv(pfragment->fTexAlpha, valpha); + cgGLSetParameter4fv(pfragment->fTexAlpha2, valpha2); + if( tex0.tcc && gs.texa.aem && (psm == PSMCT24 || psm == PSMCT16 || psm == PSMCT16S) ) + cgGLSetParameter4fv(pfragment->fTestBlack, vblack); + + // clamp relies on texture width + { + clampInfo* pclamp = &ZeroGS::vb[context].clamp; + Vector v, v2; + v.x = v.y = 0; + u32* ptex = ZeroGS::vb[context].ptexClamp; + ptex[0] = ptex[1] = 0; + + float fw = ZeroGS::vb[context].tex0.tw; + float fh = ZeroGS::vb[context].tex0.th; + + switch(pclamp->wms) { + case 0: + v2.x = -1e10; v2.z = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.x = 0; v2.z = 1-0.5f/fw; + break; + case 2: // reg pclamp + v2.x = (pclamp->minu+0.5f)/fw; v2.z = (pclamp->maxu-0.5f)/fw; + break; + + case 3: // region rep x + v.x = 0.9999f; + v.z = fw / (float)GPU_TEXMASKWIDTH; + v2.x = (float)GPU_TEXMASKWIDTH / fw; + v2.z = pclamp->maxu / fw; + + if( pclamp->minu != g_PrevBitwiseTexX ) { + g_PrevBitwiseTexX = pclamp->minu; + ptex[0] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minu, 0); + } + break; + } + + switch(pclamp->wmt) { + case 0: + v2.y = -1e10; v2.w = 1e10; + break; + case 1: // pclamp + // suikoden5 movie text + v2.y = 0; v2.w = 1-0.5f/fh; + break; + case 2: // reg pclamp + v2.y = (pclamp->minv+0.5f)/fh; v2.w = (pclamp->maxv-0.5f)/fh; + break; + + case 3: // region rep y + v.y = 0.9999f; + v.w = fh / (float)GPU_TEXMASKWIDTH; + v2.y = (float)GPU_TEXMASKWIDTH / fh; + v2.w = pclamp->maxv / fh; + + if( pclamp->minv != g_PrevBitwiseTexY ) { + g_PrevBitwiseTexY = pclamp->minv; + ptex[1] = ZeroGS::s_BitwiseTextures.GetTex(pclamp->minv, ptex[0]); + } + break; + } + + if( pfragment->fTexWrapMode != 0 ) + cgGLSetParameter4fv(pfragment->fTexWrapMode, v); + if( pfragment->fClampExts != 0 ) + cgGLSetParameter4fv(pfragment->fClampExts, v2); + } + + vb[context].bTexConstsSync = TRUE; + } + + if(s_bTexFlush ) { + if( PSMT_ISCLUT(tex0.psm) ) + texClutWrite(context); + else + s_bTexFlush = FALSE; + } + + if( settexint ) { + CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(tex0, 1); + + if( vb[context].bVarsTexSync ) { + if( vb[context].pmemtarg != pmemtarg ) { + SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, pmemtarg, pfragment, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + } + } + else { + SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, pmemtarg, pfragment, s_bForceTexFlush); + vb[context].bVarsTexSync = TRUE; + + INC_TEXVARS(); + } + } + else { + vb[context].bVarsTexSync = FALSE; + } +} + +void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, CMemoryTarget* pmemtarg, FRAGMENTSHADER* pfragment, int force) +{ + DVProfileFunc _pf("SetTexVariablesInt"); + + Vector v; + assert( pmemtarg != NULL && pfragment != NULL); + + float fw = (float)tex0.tw; + float fh = (float)tex0.th; + + bool bUseBilinear = bilinear > 1 || (bilinear && conf.bilinear); + if( bUseBilinear ) { + v.x = (float)fw; + v.y = (float)fh; + v.z = 1.0f / (float)fw; + v.w = 1.0f / (float)fh; + if (pfragment->fRealTexDims) + cgGLSetParameter4fv(pfragment->fRealTexDims, v); + else + cgGLSetParameter4fv(cgGetNamedParameter(pfragment->prog,"g_fRealTexDims"),v); + } + + if( m_Blocks[tex0.psm].bpp == 0 ) { + ERROR_LOG("Undefined tex psm 0x%x!\n", tex0.psm); + return; + } + + const BLOCK& b = m_Blocks[tex0.psm]; + + float fbw = (float)tex0.tbw; + + Vector vTexDims; + vTexDims.x = b.vTexDims.x * fw; + vTexDims.y = b.vTexDims.y * fh; + vTexDims.z = (float)BLOCK_TEXWIDTH*(0.002f / 64.0f + 0.01f/128.0f); + vTexDims.w = (float)BLOCK_TEXHEIGHT*0.2f/512.0f; + + if( bUseBilinear ) { + vTexDims.x *= 1/128.0f; + vTexDims.y *= 1/512.0f; + vTexDims.z *= 1/128.0f; + vTexDims.w *= 1/512.0f; + } + + float g_fitexwidth = g_fiGPU_TEXWIDTH/(float)pmemtarg->widthmult; + float g_texwidth = GPU_TEXWIDTH*(float)pmemtarg->widthmult; + + float fpage = tex0.tbp0*(64.0f*g_fitexwidth) + 0.05f * g_fitexwidth; + float fpageint = floorf(fpage); + int starttbp = (int)fpage; + + // 2048 is number of words to span one page + float fblockstride = (2048.0f /(float)(g_texwidth*BLOCK_TEXWIDTH)) * b.vTexDims.x * fbw; + assert( fblockstride >= 1.0f ); + + v.x = (float)(2048 * g_fitexwidth); + v.y = fblockstride; + v.z = g_fBlockMult/(float)pmemtarg->widthmult; + v.w = fpage-fpageint; + + if( g_fBlockMult > 1 ) { + // make sure to divide by mult (since the G16R16 texture loses info) + v.z *= b.bpp * (1/32.0f); + } + + cgGLSetParameter4fv(pfragment->fTexDims, vTexDims); + cgGLSetParameter4fv(pfragment->fTexBlock, &b.vTexBlock.x); + cgGLSetParameter4fv(pfragment->fTexOffset, v); + + // get hardware texture dims + int texheight = (pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult; + int texwidth = GPU_TEXWIDTH*pmemtarg->widthmult*pmemtarg->channels; + + v.y = 1;//(float)1.0f / (float)((pmemtarg->realheight+pmemtarg->widthmult-1)/pmemtarg->widthmult); + v.x = (fpageint-(float)pmemtarg->realy/(float)pmemtarg->widthmult+0.5f);//*v.y; + +// v.x *= (float)texheight; +// v.y *= (float)texheight; + v.z = (float)texwidth; + if( !(g_nPixelShaderVer & SHADER_ACCURATE) || bUseBilinear ) + v.w = 0.25f; + else + v.w = 0.5f; + + cgGLSetParameter4fv(pfragment->fPageOffset, v); + + if( force ) s_ptexCurSet[context] = pmemtarg->ptex->tex; + else s_ptexNextSet[context] = pmemtarg->ptex->tex; + vb[context].pmemtarg = pmemtarg; + + vb[context].bVarsTexSync = FALSE; +} +#define SET_ALPHA_COLOR_FACTOR(sign) \ +{ \ + switch(a.c) \ + { \ + case 0: \ + vAlphaBlendColor.y = (sign) ? 2.0f*255.0f/256.0f : -2.0f*255.0f/256.0f; \ + s_srcalpha = GL_ONE; \ + s_alphaeq = (sign) ? GL_FUNC_ADD : GL_FUNC_REVERSE_SUBTRACT; \ + break; \ + \ + case 1: \ + /* if in 24 bit mode, dest alpha should be one */ \ + switch(vb[icurctx].prndr->psm&0xf) \ + { \ + case 0: \ + bDestAlphaColor = (a.d!=2)&&((a.a==a.d)||(a.b==a.d)); \ + break; \ + \ + case 1: \ + /* dest alpha should be one */ \ + bDestAlphaColor = 2; \ + break; \ + /* default: 16bit surface, so returned alpha is ok */ \ + } \ + break; \ + \ + case 2: \ + bNeedBlendFactorInAlpha = 1; /* should disable alpha channel writing */ \ + vAlphaBlendColor.y = 0; \ + vAlphaBlendColor.w = (sign) ? (float)a.fix * (2.0f/255.0f) : (float)a.fix * (-2.0f/255.0f); \ + usec = 0; /* change so that alpha comes from source*/ \ + break; \ + } \ +} \ + +//if( a.fix <= 0x80 ) { \ +// dwTemp = (a.fix*2)>255?255:(a.fix*2); \ +// dwTemp = dwTemp|(dwTemp<<8)|(dwTemp<<16)|0x80000000; \ +// printf("bfactor: %8.8x\n", dwTemp); \ +// glBlendColorEXT(dwTemp); \ +// } \ +// else { \ + +void ZeroGS::ResetAlphaVariables() +{ +} + +void ZeroGS::SetAlphaVariables(const alphaInfo& a) +{ + bool alphaenable = true; + + // TODO: negative color when not clamping turns to positive??? + g_vars._bAlphaState = 0; // set all to zero + bNeedBlendFactorInAlpha = 0; + b2XAlphaTest = 1; + u32 dwTemp = 0xffffffff; + + // default + s_srcalpha = GL_ONE; + s_dstalpha = GL_ZERO; + s_alphaeq = GL_FUNC_ADD; + + s_alphaInfo = a; + + vAlphaBlendColor = Vector(1,2*255.0f/256.0f,0,0); + u32 usec = a.c; + + if( a.a == a.b ) + { // just d remains + if( a.d == 0 ) + { + alphaenable = false; + } + else + { + s_dstrgb = a.d == 1 ? GL_ONE : GL_ZERO; + s_srcrgb = GL_ZERO; + s_rgbeq = GL_FUNC_ADD; + } + + goto EndSetAlpha; + } + else if( a.d == 2 ) + { // zero + if( a.a == 2 ) + { + // zero all color + s_srcrgb = GL_ZERO; + s_dstrgb = GL_ZERO; + goto EndSetAlpha; + } + else if( a.b == 2 ) + { + //b2XAlphaTest = 1; + + SET_ALPHA_COLOR_FACTOR(1); + + if( bDestAlphaColor == 2 ) + { + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = a.a == 0 ? GL_ONE : GL_ZERO; + s_dstrgb = a.a == 0 ? GL_ZERO : GL_ONE; + } + else + { + bAlphaClamping = 2; + + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = a.a == 0 ? blendalpha[usec] : GL_ZERO; + s_dstrgb = a.a == 0 ? GL_ZERO : blendalpha[usec]; + } + + goto EndSetAlpha; + } + + // nothing is zero, so must do some real blending + //b2XAlphaTest = 1; + bAlphaClamping = 3; + + SET_ALPHA_COLOR_FACTOR(1); + + s_rgbeq = a.a == 0 ? GL_FUNC_SUBTRACT : GL_FUNC_REVERSE_SUBTRACT; + s_srcrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec]; + s_dstrgb = bDestAlphaColor == 2 ? GL_ONE : blendalpha[usec]; + } + else if( a.a == 2 ) + { // zero + + //b2XAlphaTest = 1; + bAlphaClamping = 1; // min testing + + SET_ALPHA_COLOR_FACTOR(1); + + if( a.b == a.d ) + { + // can get away with 1-A + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendinvalpha[usec] : GL_ZERO; + s_dstrgb = (a.b == 0 || bDestAlphaColor == 2) ? GL_ZERO : blendinvalpha[usec]; + } + else + { + s_rgbeq = a.b==0 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_SUBTRACT; + s_srcrgb = (a.b == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE; + s_dstrgb = (a.b == 0 || bDestAlphaColor == 2 ) ? GL_ONE : blendalpha[usec]; + } + } + else if( a.b == 2 ) + { + bAlphaClamping = 2; // max testing + + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) + { + // can get away with 1+A, but need to set alpha to negative + s_rgbeq = GL_FUNC_ADD; + + if( bDestAlphaColor == 2 ) + { + assert(usec==1); + + // all ones + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + + s_srcrgb = (a.a == 0) ? GL_ONE_MINUS_SRC_ALPHA : GL_ZERO; + s_dstrgb = (a.a == 0) ? GL_ZERO : GL_ONE_MINUS_SRC_ALPHA; + } + else + { + s_srcrgb = a.a == 0 ? blendinvalpha[usec] : GL_ZERO; + s_dstrgb = a.a == 0 ? GL_ZERO : blendinvalpha[usec]; + } + } + else + { + //b2XAlphaTest = 1; + s_rgbeq = GL_FUNC_ADD; + s_srcrgb = (a.a == 0 && bDestAlphaColor != 2) ? blendalpha[usec] : GL_ONE; + s_dstrgb = (a.a == 0 || bDestAlphaColor == 2) ? GL_ONE : blendalpha[usec]; + } + } + else + { + // all 3 components are valid! + bAlphaClamping = 3; // all testing + SET_ALPHA_COLOR_FACTOR(a.a!=a.d); + + if( a.a == a.d ) + { + // can get away with 1+A, but need to set alpha to negative + s_rgbeq = GL_FUNC_ADD; + + if( bDestAlphaColor == 2 ) + { + assert(usec==1); + + // all ones + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = -1; + s_srcrgb = a.a == 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA; + s_dstrgb = a.a == 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA; + } + else + { + s_srcrgb = a.a == 0 ? blendinvalpha[usec] : blendalpha[usec]; + s_dstrgb = a.a == 0 ? blendalpha[usec] : blendinvalpha[usec]; + } + } + else + { + assert(a.b == a.d); + s_rgbeq = GL_FUNC_ADD; + + if( bDestAlphaColor == 2 ) + { + assert(usec==1); + + // all ones + bNeedBlendFactorInAlpha = 1; + vAlphaBlendColor.y = 0; + vAlphaBlendColor.w = 1; + s_srcrgb = a.a != 0 ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA; + s_dstrgb = a.a != 0 ? GL_SRC_ALPHA : GL_ONE_MINUS_SRC_ALPHA; + } + else + { + //b2XAlphaTest = 1; + s_srcrgb = a.a != 0 ? blendinvalpha[usec] : blendalpha[usec]; + s_dstrgb = a.a != 0 ? blendalpha[usec] : blendinvalpha[usec]; + } + } + } + + EndSetAlpha: + + GL_BLEND_SET(); + zgsBlendEquationSeparateEXT(s_rgbeq, s_alphaeq); + + if( alphaenable ) + glEnable(GL_BLEND); // always set + else + glDisable(GL_BLEND); + + INC_ALPHAVARS(); +} + +void ZeroGS::SetWriteDepth() +{ + if( conf.mrtdepth ) { + s_bWriteDepth = TRUE; + s_nWriteDepthCount = 4; + } +} + +BOOL ZeroGS::IsWriteDepth() +{ + return s_bWriteDepth; +} + +BOOL ZeroGS::IsWriteDestAlphaTest() +{ + return s_bWriteDepth; +} + +void ZeroGS::SetDestAlphaTest() +{ + s_bDestAlphaTest = TRUE; + s_nWriteDestAlphaTest = 4; +} + +void ZeroGS::SetFogColor(u32 fog) +{ + if( 1||gs.fogcol != fog ) { + gs.fogcol = fog; + + ZeroGS::Flush(0); + ZeroGS::Flush(1); + + if( !g_bIsLost ) { + Vector v; + + // set it immediately + v.x = (gs.fogcol&0xff)/255.0f; + v.y = ((gs.fogcol>>8)&0xff)/255.0f; + v.z = ((gs.fogcol>>16)&0xff)/255.0f; + cgGLSetParameter4fv(g_fparamFogColor, v); + } + } +} + +void ZeroGS::ExtWrite() +{ + WARN_LOG("ExtWrite\n"); + + // use local DISPFB, EXTDATA, EXTBUF, and PMODE +// int bpp, start, end; +// tex0Info texframe; + +// bpp = 4; +// if( texframe.psm == 0x12 ) bpp = 3; +// else if( texframe.psm & 2 ) bpp = 2; +// +// // get the start and end addresses of the buffer +// GetRectMemAddress(start, end, texframe.psm, 0, 0, texframe.tw, texframe.th, texframe.tbp0, texframe.tbw); +} + +//////////// +// Caches // +//////////// +#ifdef __x86_64__ +extern "C" void TestClutChangeMMX(void* src, void* dst, int entries, void* pret); +#endif + +bool ZeroGS::CheckChangeInClut(u32 highdword, u32 psm) +{ + int cld = (highdword >> 29) & 0x7; + int cbp = ((highdword >> 5) & 0x3fff); + + // processing the CLUT after tex0/2 are written + switch(cld) { + case 0: return false; + case 1: break; // Seems to rarely not be 1. + // note sure about changing cbp[0,1] + case 4: return gs.cbp[0] != cbp; + case 5: return gs.cbp[1] != cbp; + + // default: load + default: break; + } + + int cpsm = (highdword >> 19) & 0xe; + int csm = (highdword >> 23) & 0x1; + + if( cpsm > 1 || csm ) + // don't support 16bit for now + return true; + + int csa = (highdword >> 24) & 0x1f; + + int entries = (psm&3)==3 ? 256 : 16; + + u64* src = (u64*)(g_pbyGSMemory + cbp*256); + u64* dst = (u64*)(g_pbyGSClut+64*csa); + + bool bRet = false; + + // do a fast test with MMX +#ifdef _MSC_VER + +#ifdef __x86_64__ + TestClutChangeMMX(dst, src, entries, &bRet); +#else + int storeebx; + __asm { + mov storeebx, ebx + mov edx, dst + mov ecx, src + mov ebx, entries + +Start: + movq mm0, [edx] + movq mm1, [edx+8] + pcmpeqd mm0, [ecx] + pcmpeqd mm1, [ecx+16] + + movq mm2, [edx+16] + movq mm3, [edx+24] + pcmpeqd mm2, [ecx+32] + pcmpeqd mm3, [ecx+48] + + pand mm0, mm1 + pand mm2, mm3 + movq mm4, [edx+32] + movq mm5, [edx+40] + pcmpeqd mm4, [ecx+8] + pcmpeqd mm5, [ecx+24] + + pand mm0, mm2 + pand mm4, mm5 + movq mm6, [edx+48] + movq mm7, [edx+56] + pcmpeqd mm6, [ecx+40] + pcmpeqd mm7, [ecx+56] + + pand mm0, mm4 + pand mm6, mm7 + pand mm0, mm6 + + pmovmskb eax, mm0 + cmp eax, 0xff + je Continue + mov bRet, 1 + jmp Return + +Continue: + cmp ebx, 16 + jle Return + + test ebx, 0x10 + jz AddEcx + sub ecx, 448 // go back and down one column, +AddEcx: + add ecx, 256 // go to the right block + + + jne Continue1 + add ecx, 256 // skip whole block +Continue1: + add edx, 64 + sub ebx, 16 + jmp Start + +Return: + emms + mov ebx, storeebx + } +#endif // __x86_64__ + +#else // linux + +#ifdef __x86_64__ + __asm__( + ".intel_syntax\n" +"Start:\n" + "movq %%mm0, [%%rcx]\n" + "movq %%mm1, [%%rcx+8]\n" + "pcmpeqd %%mm0, [%%rdx]\n" + "pcmpeqd %%mm1, [%%rdx+16]\n" + "movq %%mm2, [%%rcx+16]\n" + "movq %%mm3, [%%rcx+24]\n" + "pcmpeqd %%mm2, [%%rdx+32]\n" + "pcmpeqd %%mm3, [%%rdx+48]\n" + "pand %%mm0, %%mm1\n" + "pand %%mm2, %%mm3\n" + "movq %%mm4, [%%rcx+32]\n" + "movq %%mm5, [%%rcx+40]\n" + "pcmpeqd %%mm4, [%%rdx+8]\n" + "pcmpeqd %%mm5, [%%rdx+24]\n" + "pand %%mm0, %%mm2\n" + "pand %%mm4, %%mm5\n" + "movq %%mm6, [%%rcx+48]\n" + "movq %%mm7, [%%rcx+56]\n" + "pcmpeqd %%mm6, [%%rdx+40]\n" + "pcmpeqd %%mm7, [%%rdx+56]\n" + "pand %%mm0, %%mm4\n" + "pand %%mm6, %%mm7\n" + "pand %%mm0, %%mm6\n" + "pmovmskb %%eax, %%mm0\n" + "cmp %%eax, 0xff\n" + "je Continue\n" + ".att_syntax\n" + "movb $1, %0\n" + ".intel_syntax\n" + "jmp Return\n" +"Continue:\n" + "cmp %%rbx, 16\n" + "jle Return\n" + "test %%rbx, 0x10\n" + "jz AddRcx\n" + "sub %%rdx, 448\n" // go back and down one column +"AddRcx:\n" + "add %%rdx, 256\n" // go to the right block + "cmp %%rbx, 0x90\n" + "jne Continue1\n" + "add %%rdx, 256\n" // skip whole block +"Continue1:\n" + "add %%rcx, 64\n" + "sub %%rbx, 16\n" + "jmp Start\n" +"Return:\n" + "emms\n" + ".att_syntax\n" : "=m"(bRet) : "c"(dst), "d"(src), "b"(entries) : "rax", "memory"); +#else + // do a fast test with MMX + __asm__( + ".intel_syntax\n" +"Start:\n" + "movq %%mm0, [%%ecx]\n" + "movq %%mm1, [%%ecx+8]\n" + "pcmpeqd %%mm0, [%%edx]\n" + "pcmpeqd %%mm1, [%%edx+16]\n" + "movq %%mm2, [%%ecx+16]\n" + "movq %%mm3, [%%ecx+24]\n" + "pcmpeqd %%mm2, [%%edx+32]\n" + "pcmpeqd %%mm3, [%%edx+48]\n" + "pand %%mm0, %%mm1\n" + "pand %%mm2, %%mm3\n" + "movq %%mm4, [%%ecx+32]\n" + "movq %%mm5, [%%ecx+40]\n" + "pcmpeqd %%mm4, [%%edx+8]\n" + "pcmpeqd %%mm5, [%%edx+24]\n" + "pand %%mm0, %%mm2\n" + "pand %%mm4, %%mm5\n" + "movq %%mm6, [%%ecx+48]\n" + "movq %%mm7, [%%ecx+56]\n" + "pcmpeqd %%mm6, [%%edx+40]\n" + "pcmpeqd %%mm7, [%%edx+56]\n" + "pand %%mm0, %%mm4\n" + "pand %%mm6, %%mm7\n" + "pand %%mm0, %%mm6\n" + "pmovmskb %%eax, %%mm0\n" + "cmp %%eax, 0xff\n" + "je Continue\n" + ".att_syntax\n" + "movb $1, %0\n" + ".intel_syntax\n" + "jmp Return\n" +"Continue:\n" + "cmp %%ebx, 16\n" + "jle Return\n" + "test %%ebx, 0x10\n" + "jz AddEcx\n" + "sub %%edx, 448\n" // go back and down one column +"AddEcx:\n" + "add %%edx, 256\n" // go to the right block + "cmp %%ebx, 0x90\n" + "jne Continue1\n" + "add %%edx, 256\n" // skip whole block +"Continue1:\n" + "add %%ecx, 64\n" + "sub %%ebx, 16\n" + "jmp Start\n" +"Return:\n" + "emms\n" + ".att_syntax\n" : "=m"(bRet) : "c"(dst), "d"(src), "b"(entries) : "eax", "memory"); +#endif // __x86_64__ + +#endif // _WIN32 + + return bRet; +} + +void ZeroGS::texClutWrite(int ctx) +{ + s_bTexFlush = 0; + if( g_bIsLost ) + return; + + tex0Info& tex0 = vb[ctx].tex0; + assert( PSMT_ISCLUT(tex0.psm) ); + // processing the CLUT after tex0/2 are written + switch(tex0.cld) { + case 0: return; + case 1: break; // tex0.cld is usually 1. + case 2: gs.cbp[0] = tex0.cbp; break; + case 3: gs.cbp[1] = tex0.cbp; break; + // not sure about changing cbp[0,1] + case 4: + if( gs.cbp[0] == tex0.cbp ) + return; + gs.cbp[0] = tex0.cbp; + break; + case 5: + if( gs.cbp[1] == tex0.cbp ) + return; + gs.cbp[1] = tex0.cbp; + break; + default: //DEBUG_LOG("cld isn't 0-5!"); + break; + } + + Flush(!ctx); + + int entries = (tex0.psm & 3)==3 ? 256 : 16; + + if (tex0.csm) + { + switch (tex0.cpsm) + { + // 16bit psm + // eggomania uses non16bit textures for csm2 + case PSMCT16: + { + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for (int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress16_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + + // check for wrapping + if (((u32)(uptr)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); + } + break; + } + + case PSMCT16S: + { + u16* src = (u16*)g_pbyGSMemory + tex0.cbp*128; + u16 *dst = (u16*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0)); + + for (int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress16S_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + + // check for wrapping + if (((u32)(uptr)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut+2); + } + break; + } + + case PSMCT32: + case PSMCT24: + { + u32* src = (u32*)g_pbyGSMemory + tex0.cbp*64; + u32 *dst = (u32*)(g_pbyGSClut+64*tex0.csa); + + // check if address exceeds src + if( src+getPixelAddress32_0(gs.clut.cou+entries-1, gs.clut.cov, gs.clut.cbw) >= (u32*)g_pbyGSMemory + 0x00100000 ) + ERROR_LOG("texClutWrite out of bounds\n"); + else + for(int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress32_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst++; + } + break; + } + + default: + { +#ifndef RELEASE_TO_PUBLIC + //DEBUG_LOG("unknown cpsm: %x (%x)\n", tex0.cpsm, tex0.psm); +#endif + break; + } + } + } + else + { + switch (tex0.cpsm) + { + case PSMCT24: + case PSMCT32: + if( entries == 16 ) + WriteCLUT_T32_I4_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + else + WriteCLUT_T32_I8_CSM1((u32*)(g_pbyGSMemory + tex0.cbp*256), (u32*)(g_pbyGSClut+64*tex0.csa)); + break; + + default: + if( entries == 16 ) + WriteCLUT_T16_I4_CSM1((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + else // sse2 for 256 is more complicated, so use regular + WriteCLUT_T16_I8_CSM1_c((u32*)(g_pbyGSMemory + 256 * tex0.cbp), (u32*)(g_pbyGSClut+32*(tex0.csa&15)+(tex0.csa>=16?2:0))); + break; + + } + } +} + +void ZeroGS::SetTexFlush() +{ + s_bTexFlush = TRUE; + +// if( PSMT_ISCLUT(vb[0].tex0.psm) ) +// texClutWrite(0); +// if( PSMT_ISCLUT(vb[1].tex0.psm) ) +// texClutWrite(1); + + if( !s_bForceTexFlush ) + { + if (s_ptexCurSet[0] != s_ptexNextSet[0]) s_ptexCurSet[0] = s_ptexNextSet[0]; + if (s_ptexCurSet[1] != s_ptexNextSet[1]) s_ptexCurSet[1] = s_ptexNextSet[1]; + } +} + +int ZeroGS::Save(char* pbydata) +{ + if( pbydata == NULL ) + return 40 + 0x00400000 + sizeof(gs) + 2*VBSAVELIMIT + 2*sizeof(frameInfo) + 4 + 256*4; + + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + strcpy(pbydata, libraryName); + *(u32*)(pbydata+16) = ZEROGS_SAVEVER; + pbydata += 32; + + *(int*)pbydata = icurctx; pbydata += 4; + *(int*)pbydata = VBSAVELIMIT; pbydata += 4; + + memcpy(pbydata, g_pbyGSMemory, 0x00400000); + pbydata += 0x00400000; + + memcpy(pbydata, g_pbyGSClut, 256*4); + pbydata += 256*4; + + *(int*)pbydata = sizeof(gs); + pbydata += 4; + memcpy(pbydata, &gs, sizeof(gs)); + pbydata += sizeof(gs); + + for(int i = 0; i < 2; ++i) { + memcpy(pbydata, &vb[i], VBSAVELIMIT); + pbydata += VBSAVELIMIT; + } + + return 0; +} + +extern u32 s_uTex1Data[2][2], s_uClampData[2]; +extern char *libraryName; +bool ZeroGS::Load(char* pbydata) +{ + memset(s_uTex1Data, 0, sizeof(s_uTex1Data)); + memset(s_uClampData, 0, sizeof(s_uClampData)); + + g_nCurVBOIndex = 0; + + // first 32 bytes are the id + u32 savever = *(u32*)(pbydata+16); + + if( strncmp(pbydata, libraryName, 6) == 0 && (savever == ZEROGS_SAVEVER || savever == 0xaa000004) ) { + + g_MemTargs.Destroy(); + + GSStateReset(); + pbydata += 32; + + int context = *(int*)pbydata; pbydata += 4; + u32 savelimit = VBSAVELIMIT; + + savelimit = *(u32*)pbydata; pbydata += 4; + + memcpy(g_pbyGSMemory, pbydata, 0x00400000); + pbydata += 0x00400000; + + memcpy(g_pbyGSClut, pbydata, 256*4); + pbydata += 256*4; + + memset(&gs, 0, sizeof(gs)); + + int savedgssize; + if( savever == 0xaa000004 ) + savedgssize = 0x1d0; + else { + savedgssize = *(int*)pbydata; + pbydata += 4; + } + + memcpy(&gs, pbydata, savedgssize); + pbydata += savedgssize; + prim = &gs._prim[gs.prac]; + + vb[0].Destroy(); + memcpy(&vb[0], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[0].pBufferData = NULL; + + vb[1].Destroy(); + memcpy(&vb[1], pbydata, min(savelimit, VBSAVELIMIT)); + pbydata += savelimit; + vb[1].pBufferData = NULL; + + for(int i = 0; i < 2; ++i) { + vb[i].Init(VB_BUFFERSIZE); + vb[i].bNeedZCheck = vb[i].bNeedFrameCheck = 1; + + vb[i].bSyncVars = 0; vb[i].bNeedTexCheck = 1; + memset(vb[i].uCurTex0Data, 0, sizeof(vb[i].uCurTex0Data)); + } + + icurctx = -1; + + glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, s_uFramebuffer ); // switch to the backbuffer + SetFogColor(gs.fogcol); + + GL_REPORT_ERRORD(); + return true; + } + + return false; +} + +void ZeroGS::SaveSnapshot(const char* filename) +{ + g_bMakeSnapshot = 1; + strSnapshot = filename; +} + +bool ZeroGS::SaveRenderTarget(const char* filename, int width, int height, int jpeg) +{ + bool bflip = height < 0; + height = abs(height); + vector data(width*height); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + if( glGetError() != GL_NO_ERROR ) + return false; + + if( bflip ) { + // swap scanlines + vector scanline(width); + for(int i = 0; i < height/2; ++i) { + memcpy(&scanline[0], &data[i*width], width*4); + memcpy(&data[i*width], &data[(height-i-1)*width], width*4); + memcpy(&data[(height-i-1)*width], &scanline[0], width*4); + } + } + + if( jpeg ) return SaveJPEG(filename, width, height, &data[0], 70); + + return SaveTGA(filename, width, height, &data[0]); +} + +bool ZeroGS::SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height) +{ + vector data(width*height); + glBindTexture(textarget, tex); + glGetTexImage(textarget, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + if( glGetError() != GL_NO_ERROR ) { + return false; + } + + return SaveTGA(filename, width, height, &data[0]);//SaveJPEG(filename, width, height, &data[0], 70); +} + +extern "C" { +#ifdef _WIN32 +#define XMD_H +#undef FAR +#define HAVE_BOOLEAN +#endif + +#include "jpeglib.h" +} + +bool ZeroGS::SaveJPEG(const char* filename, int image_width, int image_height, const void* pdata, int quality) +{ + u8* image_buffer = new u8[image_width * image_height * 3]; + u8* psrc = (u8*)pdata; + + // input data is rgba format, so convert to rgb + u8* p = image_buffer; + for(int i = 0; i < image_height; ++i) { + for(int j = 0; j < image_width; ++j) { + p[0] = psrc[0]; + p[1] = psrc[1]; + p[2] = psrc[2]; + p += 3; + psrc += 4; + } + } + + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + struct jpeg_compress_struct cinfo; + /* 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 */ + FILE * outfile; /* target file */ + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + + /* Step 1: allocate and initialize JPEG compression 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 compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + if ((outfile = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_dest(&cinfo, outfile); + + /* Step 3: set parameters for compression */ + + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + /* Step 4: Start compressor */ + + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + /* jpeg_write_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could pass + * more than one scanline at a time if that's more convenient. + */ + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + fclose(outfile); + + /* Step 7: release JPEG compression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + delete image_buffer; + /* And we're done! */ + return true; +} + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +struct TGA_HEADER +{ + u8 identsize; // size of ID field that follows 18 u8 header (0 usually) + u8 colourmaptype; // type of colour map 0=none, 1=has palette + u8 imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed + + s16 colourmapstart; // first colour map entry in palette + s16 colourmaplength; // number of colours in palette + u8 colourmapbits; // number of bits per palette entry 15,16,24,32 + + s16 xstart; // image x origin + s16 ystart; // image y origin + s16 width; // image width in pixels + s16 height; // image height in pixels + u8 bits; // image bits per pixel 8,16,24,32 + u8 descriptor; // image descriptor bits (vh flip bits) + + // pixel data follows header + +#if defined(_MSC_VER) +}; +#pragma pack(pop) +#else +} __attribute__((packed)); +#endif + +bool ZeroGS::SaveTGA(const char* filename, int width, int height, void* pdata) +{ + TGA_HEADER hdr; + FILE* f = fopen(filename, "wb"); + if( f == NULL ) + return false; + + assert( sizeof(TGA_HEADER) == 18 && sizeof(hdr) == 18 ); + + memset(&hdr, 0, sizeof(hdr)); + hdr.imagetype = 2; + hdr.bits = 32; + hdr.width = width; + hdr.height = height; + hdr.descriptor |= 8|(1<<5); // 8bit alpha, flip vertical + + fwrite(&hdr, sizeof(hdr), 1, f); + fwrite(pdata, width*height*4, 1, f); + fclose(f); + return true; +} + +// AVI capture stuff +void ZeroGS::StartCapture() +{ + if( !s_aviinit ) { + +#ifdef _WIN32 + START_AVI("zerogs.avi"); +#else // linux + //TODO +#endif + s_aviinit = 1; + } + else { + ERROR_LOG("Continuing from previous capture"); + } + + s_avicapturing = 1; +} + +void ZeroGS::StopCapture() +{ + s_avicapturing = 0; +} + +void ZeroGS::CaptureFrame() +{ + assert( s_avicapturing && s_aviinit ); + + //vector mem(nBackbufferWidth*nBackbufferHeight); + vector data(nBackbufferWidth*nBackbufferHeight); + glReadPixels(0, 0, nBackbufferWidth, nBackbufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + if( glGetError() != GL_NO_ERROR ) + return; + +// u8* pend = (u8*)&data[0] + (nBackbufferHeight-1)*nBackbufferWidth*4; +// for(int i = 0; i < conf.height; ++i) { +// memcpy_amd(&mem[nBackbufferWidth*4*i], pend - nBackbufferWidth*4*i, nBackbufferWidth * 4); +// } + + int fps = SMODE1->CMOD == 3 ? 50 : 60; + +#ifdef _WIN32 + bool bSuccess = ADD_FRAME_FROM_DIB_TO_AVI("AAAA", fps, nBackbufferWidth, nBackbufferHeight, 32, &data[0]); + + if( !bSuccess ) { + s_avicapturing = 0; + STOP_AVI(); + ZeroGS::AddMessage("Failed to create avi"); + return; + } +#else // linux + //TODO +#endif +} + diff --git a/plugins/zerogs/opengl/zerogs.h b/plugins/zerogs/opengl/zerogs.h new file mode 100644 index 0000000000..53496da968 --- /dev/null +++ b/plugins/zerogs/opengl/zerogs.h @@ -0,0 +1,555 @@ +/* ZeroGS KOSMOS + * Copyright (C) 2005-2006 zerofrog@gmail.com + * + * 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 __ZEROGS__H +#define __ZEROGS__H + +#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union + +#ifndef _WIN32 +// adding glew support instead of glXGetProcAddress (thanks to scaught) +#include +#endif + +#include +#include + +#ifndef _WIN32 +#include +inline void* wglGetProcAddress(const char* x) { + return (void*)glXGetProcAddress((const GLubyte*)x); +} +#else +#include "glprocs.h" +#endif + +#include +#include + +#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils +#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 + +#include + +#include +#include +#include +#include +#include +using namespace std; + +#ifndef SAFE_DELETE +#define SAFE_DELETE(x) if( (x) != NULL ) { delete (x); (x) = NULL; } +#endif +#ifndef SAFE_DELETE_ARRAY +#define SAFE_DELETE_ARRAY(x) if( (x) != NULL ) { delete[] (x); (x) = NULL; } +#endif +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(x) if( (x) != NULL ) { (x)->Release(); (x) = NULL; } +#endif + +#define SAFE_RELEASE_PROG(x) { if( (x) != NULL ) { cgDestroyProgram(x); x = NULL; } } +#define SAFE_RELEASE_TEX(x) { if( (x) != 0 ) { glDeleteTextures(1, &(x)); x = 0; } } + +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); ++(it)) + +// sends a message to output window if assert fails +#define BMSG(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); } } +#define BMSG_RETURN(x, str) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return; } } +#define BMSG_RETURNX(x, str, rtype) { if( !(x) ) { GS_LOG(str); GS_LOG(str); return (##rtype); } } +#define B(x) { if( !(x) ) { GS_LOG(_#x"\n"); GS_LOG(#x"\n"); } } +#define B_RETURN(x) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); return; } } +#define B_RETURNX(x, rtype) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); return (##rtype); } } +#define B_G(x, action) { if( !(x) ) { ERROR_LOG("%s:%d: %s\n", __FILE__, (u32)__LINE__, #x); action; } } + +#define GL_REPORT_ERROR() { err = glGetError(); if( err != GL_NO_ERROR ) { ERROR_LOG("%s:%d: gl error 0x%x\n", __FILE__, (int)__LINE__, err); ZeroGS::HandleGLError(); } } + +#ifdef _DEBUG +#define GL_REPORT_ERRORD() { GLenum err = glGetError(); if( err != GL_NO_ERROR ) { ERROR_LOG("%s:%d: gl error 0x%x\n", __FILE__, (int)__LINE__, err); ZeroGS::HandleGLError(); } } +#else +#define GL_REPORT_ERRORD() +#endif + +// sets the data stream +#define SET_STREAM() { \ + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)8); \ + glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)12); \ + glTexCoordPointer(3, GL_FLOAT, sizeof(VertexGPU), (void*)16); \ + glVertexPointer(4, GL_SHORT, sizeof(VertexGPU), (void*)0); \ +} + +#define SETVERTEXSHADER(prog) { \ + if( (prog) != g_vsprog ) { \ + cgGLBindProgram(prog); \ + g_vsprog = prog; \ + } \ +} \ + +#define SETPIXELSHADER(prog) { \ + if( (prog) != g_psprog ) { \ + cgGLBindProgram(prog); \ + g_psprog = prog; \ + } \ +} \ + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// all textures have this width +//#define GPU_TEXWIDTH 512 +extern int GPU_TEXWIDTH; +extern float g_fiGPU_TEXWIDTH; +#define GPU_TEXMASKWIDTH 1024 // bitwise mask width for region repeat mode + +extern CGprogram g_vsprog, g_psprog; + +struct FRAGMENTSHADER +{ + FRAGMENTSHADER() : prog(0), sMemory(0), sFinal(0), sBitwiseANDX(0), sBitwiseANDY(0), sInterlace(0), sCLUT(0), sOneColor(0), sBitBltZ(0), + fTexAlpha2(0), fTexOffset(0), fTexDims(0), fTexBlock(0), fClampExts(0), fTexWrapMode(0), + fRealTexDims(0), fTestBlack(0), fPageOffset(0), fTexAlpha(0) {} + + CGprogram prog; + CGparameter sMemory, sFinal, sBitwiseANDX, sBitwiseANDY, sCLUT, sInterlace; + CGparameter sOneColor, sBitBltZ, sInvTexDims; + CGparameter fTexAlpha2, fTexOffset, fTexDims, fTexBlock, fClampExts, fTexWrapMode, fRealTexDims, fTestBlack, fPageOffset, fTexAlpha; + +#ifdef _DEBUG + string filename; +#endif +}; + +struct VERTEXSHADER +{ + VERTEXSHADER() : prog(0), sBitBltPos(0), sBitBltTex(0) {} + CGprogram prog; + CGparameter sBitBltPos, sBitBltTex, fBitBltTrans; // vertex shader constants +}; + +// don't change these values! +#define GAME_TEXTURETARGS 0x01 +#define GAME_AUTORESET 0x02 +#define GAME_INTERLACE2X 0x04 +#define GAME_TEXAHACK 0x08 // apply texa to non textured polys +#define GAME_NOTARGETRESOLVE 0x10 +#define GAME_EXACTCOLOR 0x20 +#define GAME_NOCOLORCLAMP 0x40 +#define GAME_FFXHACK 0x80 +#define GAME_NODEPTHUPDATE 0x0200 +#define GAME_QUICKRESOLVE1 0x0400 +#define GAME_NOQUICKRESOLVE 0x0800 +#define GAME_NOTARGETCLUT 0x1000 // full 16 bit resolution +#define GAME_NOSTENCIL 0x2000 +#define GAME_VSSHACKOFF 0x4000 // vertical stripe syndrome +#define GAME_NODEPTHRESOLVE 0x8000 +#define GAME_FULL16BITRES 0x00010000 +#define GAME_RESOLVEPROMOTED 0x00020000 +#define GAME_FASTUPDATE 0x00040000 +#define GAME_NOALPHATEST 0x00080000 +#define GAME_DISABLEMRTDEPTH 0x00100000 +#define GAME_32BITTARGS 0x00200000 +#define GAME_PATH3HACK 0x00400000 +#define GAME_DOPARALLELCTX 0x00800000 // tries to parallelize both contexts so that render calls are reduced (xenosaga) + // makes the game faster, but can be buggy +#define GAME_XENOSPECHACK 0x01000000 // xenosaga specularity hack (ignore any zmask=1 draws) +#define GAME_PARTIALPOINTERS 0x02000000 // whenver the texture or render target are small, tries to look for bigger ones to read from +#define GAME_PARTIALDEPTH 0x04000000 // tries to save depth targets as much as possible across height changes + +#define USEALPHATESTING (!(g_GameSettings&GAME_NOALPHATEST)) + +extern u8* g_pbyGSMemory; +extern u8* g_pbyGSClut; // the temporary clut buffer +extern CGparameter g_vparamPosXY[2], g_fparamFogColor; + +namespace ZeroGS { + + typedef void (*DrawFn)(); + + enum RenderFormatType + { + RFT_byte8 = 0, // A8R8G8B8 + RFT_float16 = 1, // A32R32B32G32 + }; + + // managers render-to-texture targets + class CRenderTarget + { + public: + CRenderTarget(); + virtual ~CRenderTarget(); + + virtual bool Create(const frameInfo& frame); + virtual void Destroy(); + + // set the GPU_POSXY variable, scissor rect, and current render target + void SetTarget(int fbplocal, const Rect2& scissor, int context); + void SetViewport(); + + // copies/creates the feedback contents + inline void CreateFeedback() { + if( ptexFeedback == 0 || !(status&TS_FeedbackReady) ) + _CreateFeedback(); + } + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* pdepth); + virtual void ConvertTo32(); // converts a psm==2 target, to a psm==0 + virtual void ConvertTo16(); // converts a psm==0 target, to a psm==2 + + virtual bool IsDepth() { return false; } + void SetRenderTarget(int targ); + + void* psys; // system data used for comparison + u32 ptex; + + int fbp, fbw, fbh; // if fbp is negative, virtual target (not mapped to any real addr) + int start, end; // in bytes + u32 lastused; // time stamp since last used + Vector vposxy; + + u32 fbm; + u16 status; + u8 psm; + u8 resv0; + Rect scissorrect; + + //int startresolve, endresolve; + u32 nUpdateTarg; // use this target to update the texture if non 0 (one time only) + + // this is optionally used when feedback effects are used (render target is used as a texture when rendering to itself) + u32 ptexFeedback; + + enum TargetStatus { + TS_Resolved = 1, + TS_NeedUpdate = 2, + TS_Virtual = 4, // currently not mapped to memory + TS_FeedbackReady = 8, // feedback effect is ready and doesn't need to be updated + TS_NeedConvert32 = 16, + TS_NeedConvert16 = 32, + }; + + private: + void _CreateFeedback(); + }; + + // manages zbuffers + class CDepthTarget : public CRenderTarget + { + public: + CDepthTarget(); + virtual ~CDepthTarget(); + + virtual bool Create(const frameInfo& frame); + virtual void Destroy(); + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* prndr); + + virtual bool IsDepth() { return true; } + + void SetDepthStencilSurface(); + + u32 pdepth; // 24 bit, will contain the stencil buffer if possible + u32 pstencil; // if not 0, contains the stencil buffer + int icount; // internal counter + }; + + // manages contiguous chunks of memory (width is always 1024) + class CMemoryTarget + { + public: + struct TEXTURE + { + inline TEXTURE() : tex(0), memptr(NULL), ref(0) {} + inline ~TEXTURE() { glDeleteTextures(1, &tex); _aligned_free(memptr); } + u32 tex; + int ref; + u8* memptr; // GPU memory used for comparison + }; + + inline CMemoryTarget() : ptex(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), channels(0),cpsm(0), clearminy(0), clearmaxy(0), validatecount(0) {} + + inline CMemoryTarget(const CMemoryTarget& r) { + ptex = r.ptex; + if( ptex != NULL ) ptex->ref++; + starty = r.starty; + height = r.height; + realy = r.realy; + realheight = r.realheight; + usedstamp = r.usedstamp; + psm = r.psm; + cpsm = r.cpsm; + clut = r.clut; + clearminy = r.clearminy; + clearmaxy = r.clearmaxy; + widthmult = r.widthmult; + channels = r.channels; + validatecount = r.validatecount; + fmt = r.fmt; + } + + ~CMemoryTarget() { Destroy(); } + + inline void Destroy() { + if( ptex != NULL && ptex->ref > 0 ) { + if( --ptex->ref <= 0 ) + delete ptex; + } + + ptex = NULL; + } + + // returns true if clut data is synced + bool ValidateClut(const tex0Info& tex0); + // returns true if tex data is synced + bool ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex); + + int clearminy, clearmaxy; // when maxy > 0, need to check for clearing + + // realy is offset in pixels from start of valid region + // so texture in memory is [realy,starty+height] + // valid texture is [starty,starty+height] + // offset in mem [starty-realy, height] + int starty, height; // assert(starty >= realy) + int realy, realheight; // this is never touched once allocated + u32 usedstamp; + TEXTURE* ptex; // can be 16bit + u32 fmt; + + int widthmult; + int channels; + + int validatecount; // count how many times has been validated, if too many, destroy + + vector clut; // if nonzero, texture uses CLUT + u8 psm, cpsm; // texture and clut format. For psm, only 16bit/32bit differentiation matters + }; + + + struct VB + { + VB(); + ~VB(); + + void Destroy(); + + __forceinline bool CheckPrim(); + void CheckFrame(int tbp); + + // context specific state + Point offset; + Rect2 scissor; + tex0Info tex0; + tex1Info tex1; + miptbpInfo miptbp0; + miptbpInfo miptbp1; + alphaInfo alpha; + fbaInfo fba; + clampInfo clamp; + pixTest test; + u32 ptexClamp[2]; // textures for x and y dir region clamping + + public: + void FlushTexData(); + + // notify VB that nVerts need to be written to pbuf + inline void NotifyWrite(int nVerts) { + assert( pBufferData != NULL && nCount <= nNumVertices && nVerts > 0 ); + + if( nCount + nVerts > nNumVertices ) { + // recreate except with a bigger count + VertexGPU* ptemp = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU)*nNumVertices*2, 256); + memcpy_amd(ptemp, pBufferData, sizeof(VertexGPU) * nCount); + nNumVertices *= 2; + assert( nCount + nVerts <= nNumVertices ); + _aligned_free(pBufferData); + pBufferData = ptemp; + } + } + + void Init(int nVerts) { + if( pBufferData == NULL && nVerts > 0 ) { + pBufferData = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU)*nVerts, 256); + nNumVertices = nVerts; + } + + nCount = 0; + } + + u8 bNeedFrameCheck; + u8 bNeedZCheck; + u8 bNeedTexCheck; + u8 dummy0; + + union { + struct { + u8 bTexConstsSync; // only pixel shader constants that context owns + u8 bVarsTexSync; // texture info + u8 bVarsSetTarg; + u8 dummy1; + }; + u32 bSyncVars; + }; + + int ictx; + VertexGPU* pBufferData; // current allocated data + + int nNumVertices; // size of pBufferData in terms of VertexGPU objects + int nCount; + primInfo curprim; // the previous prim the current buffers are set to + + zbufInfo zbuf; + frameInfo gsfb; // the real info set by FRAME cmd + frameInfo frame; + int zprimmask; // zmask for incoming points + + u32 uCurTex0Data[2]; // current tex0 data + u32 uNextTex0Data[2]; // tex0 data that has to be applied if bNeedTexCheck is 1 + + //int nFrameHeights[8]; // frame heights for the past frame changes + int nNextFrameHeight; + + CMemoryTarget* pmemtarg; // the current mem target set + CRenderTarget* prndr; + CDepthTarget* pdepth; + }; + + // visible members + extern DrawFn drawfn[8]; + extern VB vb[2]; + extern float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + + void AddMessage(const char* pstr, u32 ms = 5000); + void DrawText(const char* pstr, int left, int top, u32 color); + void ChangeWindowSize(int nNewWidth, int nNewHeight); + void SetChangeDeviceSize(int nNewWidth, int nNewHeight); + void ChangeDeviceSize(int nNewWidth, int nNewHeight); + void SetAA(int mode); + void SetCRC(int crc); + + void ReloadEffects(); + + // Methods // + bool IsGLExt( const char* szTargetExtension ); ///< returns true if the the opengl extension is supported + bool Create(int width, int height); + void Destroy(BOOL bD3D); + + void Restore(); // call to restore device + void Reset(); // call to destroy video resources + + void GSStateReset(); + void HandleGLError(); + + // called on a primitive switch + void Prim(); + + void SetTexFlush(); + // flush current vertices, call before setting new registers (the main render method) + void Flush(int context); + + void ExtWrite(); + + void SetWriteDepth(); + BOOL IsWriteDepth(); + + void SetDestAlphaTest(); + BOOL IsWriteDestAlphaTest(); + + void SetFogColor(u32 fog); + void SaveTex(tex0Info* ptex, int usevid); + + // called when trxdir is accessed. If host is involved, transfers memory to temp buffer byTransferBuf. + // Otherwise performs the transfer. TODO: Perhaps divide the transfers into chunks? + void InitTransferHostLocal(); + void TransferHostLocal(const void* pbyMem, u32 nQWordSize); + + void InitTransferLocalHost(); + void TransferLocalHost(void* pbyMem, u32 nQWordSize); + inline void TerminateLocalHost() {} + + void TransferLocalLocal(); + + // switches the render target to the real target, flushes the current render targets and renders the real image + void RenderCRTC(int interlace); + void ResetRenderTarget(int index); + + bool CheckChangeInClut(u32 highdword, u32 psm); // returns true if clut will change after this tex0 op + + // call to load CLUT data (depending on CLD) + void texClutWrite(int ctx); + RenderFormatType GetRenderFormat(); + GLenum GetRenderTargetFormat(); + + int Save(char* pbydata); + bool Load(char* pbydata); + + void SaveSnapshot(const char* filename); + bool SaveRenderTarget(const char* filename, int width, int height, int jpeg); + bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height); + bool SaveJPEG(const char* filename, int width, int height, const void* pdata, int quality); + bool SaveTGA(const char* filename, int width, int height, void* pdata); + + // private methods + void FlushSysMem(const RECT* prc); + void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm); + + // returns the first and last addresses aligned to a page that cover + void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); + + // inits the smallest rectangle in ptexMem that covers this region in ptexMem + // returns the offset that needs to be added to the locked rect to get the beginning of the buffer + //void GetMemRect(RECT& rc, int psm, int x, int y, int w, int h, int bp, int bw); + + // only sets a limited amount of state (for Update) + void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, ZeroGS::CMemoryTarget* pmemtarg, FRAGMENTSHADER* pfragment, int force); + + void ResetAlphaVariables(); + + void StartCapture(); + void StopCapture(); + void CaptureFrame(); +}; + +// GL prototypes +extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; +extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; +extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; +extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT; +extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT; +extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT; +extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT; +extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; +extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; +extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; +extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; +extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT; +extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; +extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; +extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; +extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; +extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; +extern PFNGLDRAWBUFFERSPROC glDrawBuffers; + +#endif diff --git a/plugins/zerogs/opengl/zerogsmath.h b/plugins/zerogs/opengl/zerogsmath.h new file mode 100644 index 0000000000..9afad91022 --- /dev/null +++ b/plugins/zerogs/opengl/zerogsmath.h @@ -0,0 +1,903 @@ +#ifndef ZEROGS_MATH_H +#define ZEROGS_MATH_H + +#ifndef _WIN32 +#include +#endif + +#include +#include + +#ifndef PI +#define PI ((dReal)3.141592654) +#endif + +#define rswap(x, y) *(int*)&(x) ^= *(int*)&(y) ^= *(int*)&(x) ^= *(int*)&(y); + +template inline T RAD_2_DEG(T radians) { return (radians * (T)57.29577951); } + +class Transform; +class TransformMatrix; + +typedef float dReal; +typedef dReal dMatrix3[3*4]; + +inline dReal* normalize3(dReal* pfout, const dReal* pf); +inline dReal* normalize4(dReal* pfout, const dReal* pf); +inline dReal* cross3(dReal* pfout, const dReal* pf1, const dReal* pf2); + +// multiplies 3x3 matrices +inline dReal* mult3(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* mult3(double* pfres, const double* pf1, const double* pf2); + +inline dReal* inv3(const dReal* pf, dReal* pfres, int stride); +inline dReal* inv4(const dReal* pf, dReal* pfres); + +// class used for 3 and 4 dim vectors and quaternions +// It is better to use this for a 3 dim vector because it is 16byte aligned and SIMD instructions can be used +class Vector +{ +public: + dReal x, y, z, w; + + Vector() : x(0), y(0), z(0), w(0) {} + Vector(dReal x, dReal y, dReal z) : x(x), y(y), z(z), w(0) {} + Vector(dReal x, dReal y, dReal z, dReal w) : x(x), y(y), z(z), w(w) {} + Vector(const Vector &vec) : x(vec.x), y(vec.y), z(vec.z), w(vec.w) {} + Vector(const dReal* pf) { assert(pf != NULL); x = pf[0]; y = pf[1]; z = pf[2]; w = 0; } + + dReal operator[](int i) const { return (&x)[i]; } + dReal& operator[](int i) { return (&x)[i]; } + + // casting operators + operator dReal* () { return &x; } + operator const dReal* () const { return (const dReal*)&x; } + + // SCALAR FUNCTIONS + inline dReal dot(const Vector &v) const { return x*v.x + y*v.y + z*v.z + w*v.w; } + inline void normalize() { normalize4(&x, &x); } + + inline void Set3(const float* pvals) { x = pvals[0]; y = pvals[1]; z = pvals[2]; } + inline void Set4(const float* pvals) { x = pvals[0]; y = pvals[1]; z = pvals[2]; w = pvals[3]; } + + // 3 dim cross product, w is not touched + /// this = this x v + inline void Cross(const Vector &v) { cross3(&x, &x, v); } + + /// this = u x v + inline void Cross(const Vector &u, const Vector &v) { cross3(&x, u, v); } + + inline Vector operator-() const { Vector v; v.x = -x; v.y = -y; v.z = -z; v.w = -w; return v; } + inline Vector operator+(const Vector &r) const { Vector v; v.x = x+r.x; v.y = y+r.y; v.z = z+r.z; v.w = w+r.w; return v; } + inline Vector operator-(const Vector &r) const { Vector v; v.x = x-r.x; v.y = y-r.y; v.z = z-r.z; v.w = w-r.w; return v; } + inline Vector operator*(const Vector &r) const { Vector v; v.x = r.x*x; v.y = r.y*y; v.z = r.z*z; v.w = r.w*w; return v; } + inline Vector operator*(dReal k) const { Vector v; v.x = k*x; v.y = k*y; v.z = k*z; v.w = k*w; return v; } + + inline Vector& operator += (const Vector& r) { x += r.x; y += r.y; z += r.z; w += r.w; return *this; } + inline Vector& operator -= (const Vector& r) { x -= r.x; y -= r.y; z -= r.z; w -= r.w; return *this; } + inline Vector& operator *= (const Vector& r) { x *= r.x; y *= r.y; z *= r.z; w *= r.w; return *this; } + + inline Vector& operator *= (const dReal k) { x *= k; y *= k; z *= k; w *= k; return *this; } + inline Vector& operator /= (const dReal _k) { dReal k=1/_k; x *= k; y *= k; z *= k; w *= k; return *this; } + + friend Vector operator* (float f, const Vector& v); + //friend ostream& operator<<(ostream& O, const Vector& v); + //friend istream& operator>>(istream& I, Vector& v); +}; + +inline Vector operator* (float f, const Vector& left) +{ + Vector v; + v.x = f * left.x; + v.y = f * left.y; + v.z = f * left.z; + return v; +} + +struct AABB +{ + Vector pos, extents; +}; + +struct OBB +{ + Vector right, up, dir, pos, extents; +}; + +struct TRIANGLE +{ + TRIANGLE() {} + TRIANGLE(const Vector& v1, const Vector& v2, const Vector& v3) : v1(v1), v2(v2), v3(v3) {} + ~TRIANGLE() {} + + Vector v1, v2, v3; //!< the vertices of the triangle + + const Vector& operator[](int i) const { return (&v1)[i]; } + Vector& operator[](int i) { return (&v1)[i]; } + + /// assumes CCW ordering of vertices + inline Vector ComputeNormal() { + Vector normal; + cross3(normal, v2-v1, v3-v1); + return normal; + } +}; + +// Routines made for 3D graphics that deal with 3 or 4 dim algebra structures +// Functions with postfix 3 are for 3x3 operations, etc + +// all fns return pfout on success or NULL on failure +// results and arguments can share pointers + + +// multiplies 4x4 matrices +inline dReal* mult4(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* mult4(double* pfres, const double* pf1, const double* pf2); + +// pf1^T * pf2 +inline dReal* multtrans3(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* multtrans3(double* pfres, const double* pf1, const double* pf2); +inline dReal* multtrans4(dReal* pfres, const dReal* pf1, const dReal* pf2); +inline double* multtrans4(double* pfres, const double* pf1, const double* pf2); + +inline dReal* transpose3(const dReal* pf, dReal* pfres); +inline double* transpose3(const double* pf, double* pfres); +inline dReal* transpose4(const dReal* pf, dReal* pfres); +inline double* transpose4(const double* pf, double* pfres); + +inline dReal dot2(const dReal* pf1, const dReal* pf2); +inline dReal dot3(const dReal* pf1, const dReal* pf2); +inline dReal dot4(const dReal* pf1, const dReal* pf2); + +inline dReal lengthsqr2(const dReal* pf); +inline dReal lengthsqr3(const dReal* pf); +inline dReal lengthsqr4(const dReal* pf); + +inline dReal* normalize2(dReal* pfout, const dReal* pf); +inline dReal* normalize3(dReal* pfout, const dReal* pf); +inline dReal* normalize4(dReal* pfout, const dReal* pf); + +//// +// More complex ops that deal with arbitrary matrices // +//// + +// extract eigen values and vectors from a 2x2 matrix and returns true if all values are real +// returned eigen vectors are normalized +inline bool eig2(const dReal* pfmat, dReal* peigs, dReal& fv1x, dReal& fv1y, dReal& fv2x, dReal& fv2y); + +// Simple routines for linear algebra algorithms // +int CubicRoots (double c0, double c1, double c2, double *r0, double *r1, double *r2); +bool QLAlgorithm3 (dReal* m_aafEntry, dReal* afDiag, dReal* afSubDiag); + +void EigenSymmetric3(dReal* fCovariance, dReal* eval, dReal* fAxes); + +void GetCovarBasisVectors(dReal fCovariance[3][3], Vector* vRight, Vector* vUp, Vector* vDir); + +// first root returned is always >= second, roots are defined if the quadratic doesn't have real solutions +void QuadraticSolver(dReal* pfQuadratic, dReal* pfRoots); + +int insideQuadrilateral(const Vector* p0,const Vector* p1, const Vector* p2,const Vector* p3); +int insideTriangle(const Vector* p0, const Vector* p1, const Vector* p2); + +// multiplies a matrix by a scalar +template inline void mult(T* pf, T fa, int r); + +// multiplies a r1xc1 by c1xc2 matrix into pfres, if badd is true adds the result to pfres +// does not handle cases where pfres is equal to pf1 or pf2, use multtox for those cases +template +inline T* mult(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd = false); + +// pf1 is transposed before mult +// rows of pf2 must equal rows of pf1 +// pfres will be c1xc2 matrix +template +inline T* multtrans(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd = false); + +// pf2 is transposed before mult +// the columns of both matrices must be the same and equal to c1 +// r2 is the number of rows in pf2 +// pfres must be an r1xr2 matrix +template +inline T* multtrans_to2(T* pf1, R* pf2, int r1, int c1, int r2, S* pfres, bool badd = false); + +// multiplies rxc matrix pf1 and cxc matrix pf2 and stores the result in pf1, +// the function needs a temporary buffer the size of c doubles, if pftemp == NULL, +// the function will allocate the necessary memory, otherwise pftemp should be big +// enough to store all the entries +template inline T* multto1(T* pf1, T* pf2, int r1, int c1, T* pftemp = NULL); + +// same as multto1 except stores the result in pf2, pf1 has to be an r2xr2 matrix +// pftemp must be of size r2 if not NULL +template inline T* multto2(T* pf1, S* pf2, int r2, int c2, S* pftemp = NULL); + +// add pf1 + pf2 and store in pf1 +template inline void sub(T* pf1, T* pf2, int r); +template inline T normsqr(T* pf1, int r); +template inline T lengthsqr(T* pf1, T* pf2, int length); +template inline T dot(T* pf1, T* pf2, int length); + +template inline T sum(T* pf, int length); + +// takes the inverse of the 3x3 matrix pf and stores it into pfres, returns true if matrix is invertible +template inline bool inv2(T* pf, T* pfres); + +/////////////////////// +// Function Definitions +/////////////////////// +bool eig2(const dReal* pfmat, dReal* peigs, dReal& fv1x, dReal& fv1y, dReal& fv2x, dReal& fv2y) +{ + // x^2 + bx + c + dReal a, b, c, d; + b = -(pfmat[0] + pfmat[3]); + c = pfmat[0] * pfmat[3] - pfmat[1] * pfmat[2]; + d = b * b - 4.0f * c + 1e-16f; + + if( d < 0 ) return false; + if( d < 1e-16f ) { + a = -0.5f * b; + peigs[0] = a; peigs[1] = a; + fv1x = pfmat[1]; fv1y = a - pfmat[0]; + c = 1 / sqrtf(fv1x*fv1x + fv1y*fv1y); + fv1x *= c; fv1y *= c; + fv2x = -fv1y; fv2y = fv1x; + return true; + } + + // two roots + d = sqrtf(d); + a = -0.5f * (b + d); + peigs[0] = a; + fv1x = pfmat[1]; fv1y = a-pfmat[0]; + c = 1 / sqrtf(fv1x*fv1x + fv1y*fv1y); + fv1x *= c; fv1y *= c; + + a += d; + peigs[1] = a; + fv2x = pfmat[1]; fv2y = a-pfmat[0]; + c = 1 / sqrtf(fv2x*fv2x + fv2y*fv2y); + fv2x *= c; fv2y *= c; + return true; +} + +//#ifndef TI_USING_IPP + +// Functions that are replacable by ipp library funcs +template inline T* _mult3(T* pfres, const T* pf1, const T* pf2) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL ); + + T* pfres2; + if( pfres == pf1 || pfres == pf2 ) pfres2 = (T*)alloca(9 * sizeof(T)); + else pfres2 = pfres; + + pfres2[0*4+0] = pf1[0*4+0]*pf2[0*4+0]+pf1[0*4+1]*pf2[1*4+0]+pf1[0*4+2]*pf2[2*4+0]; + pfres2[0*4+1] = pf1[0*4+0]*pf2[0*4+1]+pf1[0*4+1]*pf2[1*4+1]+pf1[0*4+2]*pf2[2*4+1]; + pfres2[0*4+2] = pf1[0*4+0]*pf2[0*4+2]+pf1[0*4+1]*pf2[1*4+2]+pf1[0*4+2]*pf2[2*4+2]; + + pfres2[1*4+0] = pf1[1*4+0]*pf2[0*4+0]+pf1[1*4+1]*pf2[1*4+0]+pf1[1*4+2]*pf2[2*4+0]; + pfres2[1*4+1] = pf1[1*4+0]*pf2[0*4+1]+pf1[1*4+1]*pf2[1*4+1]+pf1[1*4+2]*pf2[2*4+1]; + pfres2[1*4+2] = pf1[1*4+0]*pf2[0*4+2]+pf1[1*4+1]*pf2[1*4+2]+pf1[1*4+2]*pf2[2*4+2]; + + pfres2[2*4+0] = pf1[2*4+0]*pf2[0*4+0]+pf1[2*4+1]*pf2[1*4+0]+pf1[2*4+2]*pf2[2*4+0]; + pfres2[2*4+1] = pf1[2*4+0]*pf2[0*4+1]+pf1[2*4+1]*pf2[1*4+1]+pf1[2*4+2]*pf2[2*4+1]; + pfres2[2*4+2] = pf1[2*4+0]*pf2[0*4+2]+pf1[2*4+1]*pf2[1*4+2]+pf1[2*4+2]*pf2[2*4+2]; + + if( pfres2 != pfres ) memcpy(pfres, pfres2, 9*sizeof(T)); + + return pfres; +} + +inline dReal* mult3(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _mult3(pfres, pf1, pf2); } +inline double* mult3(double* pfres, const double* pf1, const double* pf2) { return _mult3(pfres, pf1, pf2); } + +template +inline T* _mult4(T* pfres, const T* p1, const T* p2) +{ + assert( pfres != NULL && p1 != NULL && p2 != NULL ); + + T* pfres2; + if( pfres == p1 || pfres == p2 ) pfres2 = (T*)alloca(16 * sizeof(T)); + else pfres2 = pfres; + + pfres2[0*4+0] = p1[0*4+0]*p2[0*4+0] + p1[0*4+1]*p2[1*4+0] + p1[0*4+2]*p2[2*4+0] + p1[0*4+3]*p2[3*4+0]; + pfres2[0*4+1] = p1[0*4+0]*p2[0*4+1] + p1[0*4+1]*p2[1*4+1] + p1[0*4+2]*p2[2*4+1] + p1[0*4+3]*p2[3*4+1]; + pfres2[0*4+2] = p1[0*4+0]*p2[0*4+2] + p1[0*4+1]*p2[1*4+2] + p1[0*4+2]*p2[2*4+2] + p1[0*4+3]*p2[3*4+2]; + pfres2[0*4+3] = p1[0*4+0]*p2[0*4+3] + p1[0*4+1]*p2[1*4+3] + p1[0*4+2]*p2[2*4+3] + p1[0*4+3]*p2[3*4+3]; + + pfres2[1*4+0] = p1[1*4+0]*p2[0*4+0] + p1[1*4+1]*p2[1*4+0] + p1[1*4+2]*p2[2*4+0] + p1[1*4+3]*p2[3*4+0]; + pfres2[1*4+1] = p1[1*4+0]*p2[0*4+1] + p1[1*4+1]*p2[1*4+1] + p1[1*4+2]*p2[2*4+1] + p1[1*4+3]*p2[3*4+1]; + pfres2[1*4+2] = p1[1*4+0]*p2[0*4+2] + p1[1*4+1]*p2[1*4+2] + p1[1*4+2]*p2[2*4+2] + p1[1*4+3]*p2[3*4+2]; + pfres2[1*4+3] = p1[1*4+0]*p2[0*4+3] + p1[1*4+1]*p2[1*4+3] + p1[1*4+2]*p2[2*4+3] + p1[1*4+3]*p2[3*4+3]; + + pfres2[2*4+0] = p1[2*4+0]*p2[0*4+0] + p1[2*4+1]*p2[1*4+0] + p1[2*4+2]*p2[2*4+0] + p1[2*4+3]*p2[3*4+0]; + pfres2[2*4+1] = p1[2*4+0]*p2[0*4+1] + p1[2*4+1]*p2[1*4+1] + p1[2*4+2]*p2[2*4+1] + p1[2*4+3]*p2[3*4+1]; + pfres2[2*4+2] = p1[2*4+0]*p2[0*4+2] + p1[2*4+1]*p2[1*4+2] + p1[2*4+2]*p2[2*4+2] + p1[2*4+3]*p2[3*4+2]; + pfres2[2*4+3] = p1[2*4+0]*p2[0*4+3] + p1[2*4+1]*p2[1*4+3] + p1[2*4+2]*p2[2*4+3] + p1[2*4+3]*p2[3*4+3]; + + pfres2[3*4+0] = p1[3*4+0]*p2[0*4+0] + p1[3*4+1]*p2[1*4+0] + p1[3*4+2]*p2[2*4+0] + p1[3*4+3]*p2[3*4+0]; + pfres2[3*4+1] = p1[3*4+0]*p2[0*4+1] + p1[3*4+1]*p2[1*4+1] + p1[3*4+2]*p2[2*4+1] + p1[3*4+3]*p2[3*4+1]; + pfres2[3*4+2] = p1[3*4+0]*p2[0*4+2] + p1[3*4+1]*p2[1*4+2] + p1[3*4+2]*p2[2*4+2] + p1[3*4+3]*p2[3*4+2]; + pfres2[3*4+3] = p1[3*4+0]*p2[0*4+3] + p1[3*4+1]*p2[1*4+3] + p1[3*4+2]*p2[2*4+3] + p1[3*4+3]*p2[3*4+3]; + + if( pfres != pfres2 ) memcpy(pfres, pfres2, sizeof(T)*16); + return pfres; +} + +inline dReal* mult4(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _mult4(pfres, pf1, pf2); } +inline double* mult4(double* pfres, const double* pf1, const double* pf2) { return _mult4(pfres, pf1, pf2); } + +template +inline T* _multtrans3(T* pfres, const T* pf1, const T* pf2) +{ + T* pfres2; + if( pfres == pf1 ) pfres2 = (T*)alloca(9 * sizeof(T)); + else pfres2 = pfres; + + pfres2[0] = pf1[0]*pf2[0]+pf1[3]*pf2[3]+pf1[6]*pf2[6]; + pfres2[1] = pf1[0]*pf2[1]+pf1[3]*pf2[4]+pf1[6]*pf2[7]; + pfres2[2] = pf1[0]*pf2[2]+pf1[3]*pf2[5]+pf1[6]*pf2[8]; + + pfres2[3] = pf1[1]*pf2[0]+pf1[4]*pf2[3]+pf1[7]*pf2[6]; + pfres2[4] = pf1[1]*pf2[1]+pf1[4]*pf2[4]+pf1[7]*pf2[7]; + pfres2[5] = pf1[1]*pf2[2]+pf1[4]*pf2[5]+pf1[7]*pf2[8]; + + pfres2[6] = pf1[2]*pf2[0]+pf1[5]*pf2[3]+pf1[8]*pf2[6]; + pfres2[7] = pf1[2]*pf2[1]+pf1[5]*pf2[4]+pf1[8]*pf2[7]; + pfres2[8] = pf1[2]*pf2[2]+pf1[5]*pf2[5]+pf1[8]*pf2[8]; + + if( pfres2 != pfres ) memcpy(pfres, pfres2, 9*sizeof(T)); + + return pfres; +} + +template +inline T* _multtrans4(T* pfres, const T* pf1, const T* pf2) +{ + T* pfres2; + if( pfres == pf1 ) pfres2 = (T*)alloca(16 * sizeof(T)); + else pfres2 = pfres; + + for(int i = 0; i < 4; ++i) { + for(int j = 0; j < 4; ++j) { + pfres[4*i+j] = pf1[i] * pf2[j] + pf1[i+4] * pf2[j+4] + pf1[i+8] * pf2[j+8] + pf1[i+12] * pf2[j+12]; + } + } + + return pfres; +} + +inline dReal* multtrans3(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _multtrans3(pfres, pf1, pf2); } +inline double* multtrans3(double* pfres, const double* pf1, const double* pf2) { return _multtrans3(pfres, pf1, pf2); } +inline dReal* multtrans4(dReal* pfres, const dReal* pf1, const dReal* pf2) { return _multtrans4(pfres, pf1, pf2); } +inline double* multtrans4(double* pfres, const double* pf1, const double* pf2) { return _multtrans4(pfres, pf1, pf2); } + +// stride is in T +template inline T* _inv3(const T* pf, T* pfres, int stride) +{ + T* pfres2; + if( pfres == pf ) pfres2 = (T*)alloca(3 * stride * sizeof(T)); + else pfres2 = pfres; + + // inverse = C^t / det(pf) where C is the matrix of coefficients + + // calc C^t + pfres2[0*stride + 0] = pf[1*stride + 1] * pf[2*stride + 2] - pf[1*stride + 2] * pf[2*stride + 1]; + pfres2[0*stride + 1] = pf[0*stride + 2] * pf[2*stride + 1] - pf[0*stride + 1] * pf[2*stride + 2]; + pfres2[0*stride + 2] = pf[0*stride + 1] * pf[1*stride + 2] - pf[0*stride + 2] * pf[1*stride + 1]; + pfres2[1*stride + 0] = pf[1*stride + 2] * pf[2*stride + 0] - pf[1*stride + 0] * pf[2*stride + 2]; + pfres2[1*stride + 1] = pf[0*stride + 0] * pf[2*stride + 2] - pf[0*stride + 2] * pf[2*stride + 0]; + pfres2[1*stride + 2] = pf[0*stride + 2] * pf[1*stride + 0] - pf[0*stride + 0] * pf[1*stride + 2]; + pfres2[2*stride + 0] = pf[1*stride + 0] * pf[2*stride + 1] - pf[1*stride + 1] * pf[2*stride + 0]; + pfres2[2*stride + 1] = pf[0*stride + 1] * pf[2*stride + 0] - pf[0*stride + 0] * pf[2*stride + 1]; + pfres2[2*stride + 2] = pf[0*stride + 0] * pf[1*stride + 1] - pf[0*stride + 1] * pf[1*stride + 0]; + + T fdet = pf[0*stride + 2] * pfres2[2*stride + 0] + pf[1*stride + 2] * pfres2[2*stride + 1] + + pf[2*stride + 2] * pfres2[2*stride + 2]; + + if( fabs(fdet) < 1e-6 ) return NULL; + + fdet = 1 / fdet; + //if( pfdet != NULL ) *pfdet = fdet; + + if( pfres != pf ) { + pfres[0*stride+0] *= fdet; pfres[0*stride+1] *= fdet; pfres[0*stride+2] *= fdet; + pfres[1*stride+0] *= fdet; pfres[1*stride+1] *= fdet; pfres[1*stride+2] *= fdet; + pfres[2*stride+0] *= fdet; pfres[2*stride+1] *= fdet; pfres[2*stride+2] *= fdet; + return pfres; + } + + pfres[0*stride+0] = pfres2[0*stride+0] * fdet; + pfres[0*stride+1] = pfres2[0*stride+1] * fdet; + pfres[0*stride+2] = pfres2[0*stride+2] * fdet; + pfres[1*stride+0] = pfres2[1*stride+0] * fdet; + pfres[1*stride+1] = pfres2[1*stride+1] * fdet; + pfres[1*stride+2] = pfres2[1*stride+2] * fdet; + pfres[2*stride+0] = pfres2[2*stride+0] * fdet; + pfres[2*stride+1] = pfres2[2*stride+1] * fdet; + pfres[2*stride+2] = pfres2[2*stride+2] * fdet; + return pfres; +} + +inline dReal* inv3(const dReal* pf, dReal* pfres, int stride) { return _inv3(pf, pfres, stride); } + +// inverse if 92 mults and 39 adds +template inline T* _inv4(const T* pf, T* pfres) +{ + T* pfres2; + if( pfres == pf ) pfres2 = (T*)alloca(16 * sizeof(T)); + else pfres2 = pfres; + + // inverse = C^t / det(pf) where C is the matrix of coefficients + + // calc C^t + + // determinants of all possibel 2x2 submatrices formed by last two rows + T fd0, fd1, fd2; + T f1, f2, f3; + fd0 = pf[2*4 + 0] * pf[3*4 + 1] - pf[2*4 + 1] * pf[3*4 + 0]; + fd1 = pf[2*4 + 1] * pf[3*4 + 2] - pf[2*4 + 2] * pf[3*4 + 1]; + fd2 = pf[2*4 + 2] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 2]; + + f1 = pf[2*4 + 1] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 1]; + f2 = pf[2*4 + 0] * pf[3*4 + 3] - pf[2*4 + 3] * pf[3*4 + 0]; + f3 = pf[2*4 + 0] * pf[3*4 + 2] - pf[2*4 + 2] * pf[3*4 + 0]; + + pfres2[0*4 + 0] = pf[1*4 + 1] * fd2 - pf[1*4 + 2] * f1 + pf[1*4 + 3] * fd1; + pfres2[0*4 + 1] = -(pf[0*4 + 1] * fd2 - pf[0*4 + 2] * f1 + pf[0*4 + 3] * fd1); + + pfres2[1*4 + 0] = -(pf[1*4 + 0] * fd2 - pf[1*4 + 2] * f2 + pf[1*4 + 3] * f3); + pfres2[1*4 + 1] = pf[0*4 + 0] * fd2 - pf[0*4 + 2] * f2 + pf[0*4 + 3] * f3; + + pfres2[2*4 + 0] = pf[1*4 + 0] * f1 - pf[1*4 + 1] * f2 + pf[1*4 + 3] * fd0; + pfres2[2*4 + 1] = -(pf[0*4 + 0] * f1 - pf[0*4 + 1] * f2 + pf[0*4 + 3] * fd0); + + pfres2[3*4 + 0] = -(pf[1*4 + 0] * fd1 - pf[1*4 + 1] * f3 + pf[1*4 + 2] * fd0); + pfres2[3*4 + 1] = pf[0*4 + 0] * fd1 - pf[0*4 + 1] * f3 + pf[0*4 + 2] * fd0; + + // determinants of first 2 rows of 4x4 matrix + fd0 = pf[0*4 + 0] * pf[1*4 + 1] - pf[0*4 + 1] * pf[1*4 + 0]; + fd1 = pf[0*4 + 1] * pf[1*4 + 2] - pf[0*4 + 2] * pf[1*4 + 1]; + fd2 = pf[0*4 + 2] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 2]; + + f1 = pf[0*4 + 1] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 1]; + f2 = pf[0*4 + 0] * pf[1*4 + 3] - pf[0*4 + 3] * pf[1*4 + 0]; + f3 = pf[0*4 + 0] * pf[1*4 + 2] - pf[0*4 + 2] * pf[1*4 + 0]; + + pfres2[0*4 + 2] = pf[3*4 + 1] * fd2 - pf[3*4 + 2] * f1 + pf[3*4 + 3] * fd1; + pfres2[0*4 + 3] = -(pf[2*4 + 1] * fd2 - pf[2*4 + 2] * f1 + pf[2*4 + 3] * fd1); + + pfres2[1*4 + 2] = -(pf[3*4 + 0] * fd2 - pf[3*4 + 2] * f2 + pf[3*4 + 3] * f3); + pfres2[1*4 + 3] = pf[2*4 + 0] * fd2 - pf[2*4 + 2] * f2 + pf[2*4 + 3] * f3; + + pfres2[2*4 + 2] = pf[3*4 + 0] * f1 - pf[3*4 + 1] * f2 + pf[3*4 + 3] * fd0; + pfres2[2*4 + 3] = -(pf[2*4 + 0] * f1 - pf[2*4 + 1] * f2 + pf[2*4 + 3] * fd0); + + pfres2[3*4 + 2] = -(pf[3*4 + 0] * fd1 - pf[3*4 + 1] * f3 + pf[3*4 + 2] * fd0); + pfres2[3*4 + 3] = pf[2*4 + 0] * fd1 - pf[2*4 + 1] * f3 + pf[2*4 + 2] * fd0; + + T fdet = pf[0*4 + 3] * pfres2[3*4 + 0] + pf[1*4 + 3] * pfres2[3*4 + 1] + + pf[2*4 + 3] * pfres2[3*4 + 2] + pf[3*4 + 3] * pfres2[3*4 + 3]; + + if( fabs(fdet) < 1e-6) return NULL; + + fdet = 1 / fdet; + //if( pfdet != NULL ) *pfdet = fdet; + + if( pfres2 == pfres ) { + mult(pfres, fdet, 16); + return pfres; + } + + int i = 0; + while(i < 16) { + pfres[i] = pfres2[i] * fdet; + ++i; + } + + return pfres; +} + +inline dReal* inv4(const dReal* pf, dReal* pfres) { return _inv4(pf, pfres); } + +template inline T* _transpose3(const T* pf, T* pfres) +{ + assert( pf != NULL && pfres != NULL ); + + if( pf == pfres ) { + rswap(pfres[1], pfres[3]); + rswap(pfres[2], pfres[6]); + rswap(pfres[5], pfres[7]); + return pfres; + } + + pfres[0] = pf[0]; pfres[1] = pf[3]; pfres[2] = pf[6]; + pfres[3] = pf[1]; pfres[4] = pf[4]; pfres[5] = pf[7]; + pfres[6] = pf[2]; pfres[7] = pf[5]; pfres[8] = pf[8]; + + return pfres; +} + +inline dReal* transpose3(const dReal* pf, dReal* pfres) { return _transpose3(pf, pfres); } +inline double* transpose3(const double* pf, double* pfres) { return _transpose3(pf, pfres); } + +template inline T* _transpose4(const T* pf, T* pfres) +{ + assert( pf != NULL && pfres != NULL ); + + if( pf == pfres ) { + rswap(pfres[1], pfres[4]); + rswap(pfres[2], pfres[8]); + rswap(pfres[3], pfres[12]); + rswap(pfres[6], pfres[9]); + rswap(pfres[7], pfres[13]); + rswap(pfres[11], pfres[15]); + return pfres; + } + + pfres[0] = pf[0]; pfres[1] = pf[4]; pfres[2] = pf[8]; pfres[3] = pf[12]; + pfres[4] = pf[1]; pfres[5] = pf[5]; pfres[6] = pf[9]; pfres[7] = pf[13]; + pfres[8] = pf[2]; pfres[9] = pf[6]; pfres[10] = pf[10]; pfres[11] = pf[14]; + pfres[12] = pf[3]; pfres[13] = pf[7]; pfres[14] = pf[11]; pfres[15] = pf[15]; + return pfres; +} + +inline dReal* transpose4(const dReal* pf, dReal* pfres) { return _transpose4(pf, pfres); } +inline double* transpose4(const double* pf, double* pfres) { return _transpose4(pf, pfres); } + +inline dReal dot2(const dReal* pf1, const dReal* pf2) +{ + assert( pf1 != NULL && pf2 != NULL ); + return pf1[0]*pf2[0] + pf1[1]*pf2[1]; +} + +inline dReal dot3(const dReal* pf1, const dReal* pf2) +{ + assert( pf1 != NULL && pf2 != NULL ); + return pf1[0]*pf2[0] + pf1[1]*pf2[1] + pf1[2]*pf2[2]; +} + +inline dReal dot4(const dReal* pf1, const dReal* pf2) +{ + assert( pf1 != NULL && pf2 != NULL ); + return pf1[0]*pf2[0] + pf1[1]*pf2[1] + pf1[2]*pf2[2] + pf1[3] * pf2[3]; +} + +inline dReal lengthsqr2(const dReal* pf) +{ + assert( pf != NULL ); + return pf[0] * pf[0] + pf[1] * pf[1]; +} + +inline dReal lengthsqr3(const dReal* pf) +{ + assert( pf != NULL ); + return pf[0] * pf[0] + pf[1] * pf[1] + pf[2] * pf[2]; +} + +inline dReal lengthsqr4(const dReal* pf) +{ + assert( pf != NULL ); + return pf[0] * pf[0] + pf[1] * pf[1] + pf[2] * pf[2] + pf[3] * pf[3]; +} + +inline dReal* normalize2(dReal* pfout, const dReal* pf) +{ + assert(pf != NULL); + + dReal f = pf[0]*pf[0] + pf[1]*pf[1]; + f = 1.0f / sqrtf(f); + pfout[0] = pf[0] * f; + pfout[1] = pf[1] * f; + + return pfout; +} + +inline dReal* normalize3(dReal* pfout, const dReal* pf) +{ + assert(pf != NULL); + + dReal f = pf[0]*pf[0] + pf[1]*pf[1] + pf[2]*pf[2]; + + f = 1.0f / sqrtf(f); + pfout[0] = pf[0] * f; + pfout[1] = pf[1] * f; + pfout[2] = pf[2] * f; + + return pfout; +} + +inline dReal* normalize4(dReal* pfout, const dReal* pf) +{ + assert(pf != NULL); + + dReal f = pf[0]*pf[0] + pf[1]*pf[1] + pf[2]*pf[2] + pf[3]*pf[3]; + + f = 1.0f / sqrtf(f); + pfout[0] = pf[0] * f; + pfout[1] = pf[1] * f; + pfout[2] = pf[2] * f; + pfout[3] = pf[3] * f; + + return pfout; +} + +inline dReal* cross3(dReal* pfout, const dReal* pf1, const dReal* pf2) +{ + assert( pfout != NULL && pf1 != NULL && pf2 != NULL ); + + dReal temp[3]; + temp[0] = pf1[1] * pf2[2] - pf1[2] * pf2[1]; + temp[1] = pf1[2] * pf2[0] - pf1[0] * pf2[2]; + temp[2] = pf1[0] * pf2[1] - pf1[1] * pf2[0]; + + pfout[0] = temp[0]; pfout[1] = temp[1]; pfout[2] = temp[2]; + return pfout; +} + +template inline void mult(T* pf, T fa, int r) +{ + assert( pf != NULL ); + + while(r > 0) { + --r; + pf[r] *= fa; + } +} + +template +inline T* mult(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL); + int j, k; + + if( !badd ) memset(pfres, 0, sizeof(S) * r1 * c2); + + while(r1 > 0) { + --r1; + + j = 0; + while(j < c2) { + k = 0; + while(k < c1) { + pfres[j] += pf1[k] * pf2[k*c2 + j]; + ++k; + } + ++j; + } + + pf1 += c1; + pfres += c2; + } + + return pfres; +} + +template +inline T* multtrans(T* pf1, R* pf2, int r1, int c1, int c2, S* pfres, bool badd) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL); + int i, j, k; + + if( !badd ) memset(pfres, 0, sizeof(S) * c1 * c2); + + i = 0; + while(i < c1) { + + j = 0; + while(j < c2) { + + k = 0; + while(k < r1) { + pfres[j] += pf1[k*c1] * pf2[k*c2 + j]; + ++k; + } + ++j; + } + + pfres += c2; + ++pf1; + + ++i; + } + + return pfres; +} + +template +inline T* multtrans_to2(T* pf1, R* pf2, int r1, int c1, int r2, S* pfres, bool badd) +{ + assert( pf1 != NULL && pf2 != NULL && pfres != NULL); + int j, k; + + if( !badd ) memset(pfres, 0, sizeof(S) * r1 * r2); + + while(r1 > 0) { + --r1; + + j = 0; + while(j < r2) { + k = 0; + while(k < c1) { + pfres[j] += pf1[k] * pf2[j*c1 + k]; + ++k; + } + ++j; + } + + pf1 += c1; + pfres += r2; + } + + return pfres; +} + +template inline T* multto1(T* pf1, T* pf2, int r, int c, T* pftemp) +{ + assert( pf1 != NULL && pf2 != NULL ); + + int j, k; + bool bdel = false; + + if( pftemp == NULL ) { + pftemp = new T[c]; + bdel = true; + } + + while(r > 0) { + --r; + + j = 0; + while(j < c) { + + pftemp[j] = 0.0; + + k = 0; + while(k < c) { + pftemp[j] += pf1[k] * pf2[k*c + j]; + ++k; + } + ++j; + } + + memcpy(pf1, pftemp, c * sizeof(T)); + pf1 += c; + } + + if( bdel ) delete[] pftemp; + + return pf1; +} + +template inline T* multto2(T* pf1, S* pf2, int r2, int c2, S* pftemp) +{ + assert( pf1 != NULL && pf2 != NULL ); + + int i, j, k; + bool bdel = false; + + if( pftemp == NULL ) { + pftemp = new S[r2]; + bdel = true; + } + + // do columns first + j = 0; + while(j < c2) { + i = 0; + while(i < r2) { + + pftemp[i] = 0.0; + + k = 0; + while(k < r2) { + pftemp[i] += pf1[i*r2 + k] * pf2[k*c2 + j]; + ++k; + } + ++i; + } + + i = 0; + while(i < r2) { + *(pf2+i*c2+j) = pftemp[i]; + ++i; + } + + ++j; + } + + if( bdel ) delete[] pftemp; + + return pf1; +} + +template inline void add(T* pf1, T* pf2, int r) +{ + assert( pf1 != NULL && pf2 != NULL); + + while(r > 0) { + --r; + pf1[r] += pf2[r]; + } +} + +template inline void sub(T* pf1, T* pf2, int r) +{ + assert( pf1 != NULL && pf2 != NULL); + + while(r > 0) { + --r; + pf1[r] -= pf2[r]; + } +} + +template inline T normsqr(T* pf1, int r) +{ + assert( pf1 != NULL ); + + T d = 0.0; + while(r > 0) { + --r; + d += pf1[r] * pf1[r]; + } + + return d; +} + +template inline T lengthsqr(T* pf1, T* pf2, int length) +{ + T d = 0; + while(length > 0) { + --length; + d += sqr(pf1[length] - pf2[length]); + } + + return d; +} + +template inline T dot(T* pf1, T* pf2, int length) +{ + T d = 0; + while(length > 0) { + --length; + d += pf1[length] * pf2[length]; + } + + return d; +} + +template inline T sum(T* pf, int length) +{ + T d = 0; + while(length > 0) { + --length; + d += pf[length]; + } + + return d; +} + +template inline bool inv2(T* pf, T* pfres) +{ + T fdet = pf[0] * pf[3] - pf[1] * pf[2]; + + if( fabs(fdet) < 1e-16 ) return false; + + fdet = 1 / fdet; + //if( pfdet != NULL ) *pfdet = fdet; + + if( pfres != pf ) { + pfres[0] = fdet * pf[3]; pfres[1] = -fdet * pf[1]; + pfres[2] = -fdet * pf[2]; pfres[3] = fdet * pf[0]; + return true; + } + + dReal ftemp = pf[0]; + pfres[0] = pf[3] * fdet; + pfres[1] *= -fdet; + pfres[2] *= -fdet; + pfres[3] = ftemp * pf[0]; + + return true; +} + +#endif diff --git a/plugins/zerogs/opengl/zpipe.cpp b/plugins/zerogs/opengl/zpipe.cpp new file mode 100644 index 0000000000..174daa5f30 --- /dev/null +++ b/plugins/zerogs/opengl/zpipe.cpp @@ -0,0 +1,115 @@ +// zpipe.cpp : Defines the entry point for the console application. +// + +#include + +#include +#include +#include + +//#define ZLIB_WINAPI +#include "zlib/zlib.h" + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress) ; + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) +{ + z_stream strm; + + int ret;//, flush; + unsigned have; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION) ; + if (ret != Z_OK) + return ret; + + /* compress */ + strm.avail_in = bytes_to_compress ; + strm.avail_out = bytes_to_compress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + + ret = deflate(&strm, Z_FINISH) ; + have = bytes_to_compress - strm.avail_out ; + *bytes_after_compressed = have ; + + assert(ret == Z_STREAM_END); /* stream will be complete */ + + /* clean up and return */ + (void)deflateEnd(&strm); + return Z_OK; +} + +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes) +{ + z_stream strm; + + int ret; + //unsigned have; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + + /* decompress */ + strm.avail_in = bytes_to_decompress ; + strm.next_in = (Bytef *)src ; + strm.next_out = (Bytef *)dst ; + strm.avail_out = maximum_after_decompress ; + + ret = inflate(&strm, Z_NO_FLUSH) ; + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + + assert(strm.avail_in == 0); /* all input will be used */ + + if( outbytes != NULL ) + *outbytes = strm.total_out; + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +/* report a zlib or i/o error */ +void zerr(int ret) +{ + fputs("zpipe: ", stderr); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + fputs("error reading stdin\n", stderr); + if (ferror(stdout)) + fputs("error writing stdout\n", stderr); + break; + case Z_STREAM_ERROR: + fputs("invalid compression level\n", stderr); + break; + case Z_DATA_ERROR: + fputs("invalid or incomplete deflate data\n", stderr); + break; + case Z_MEM_ERROR: + fputs("out of memory\n", stderr); + break; + case Z_VERSION_ERROR: + fputs("zlib version mismatch!\n", stderr); + } +} diff --git a/plugins/zerogs/opengl/zpipe.h b/plugins/zerogs/opengl/zpipe.h new file mode 100644 index 0000000000..cb96229553 --- /dev/null +++ b/plugins/zerogs/opengl/zpipe.h @@ -0,0 +1,7 @@ +#ifndef zpipe_h +#define zpipe_h + +int def(char *src, char *dst, int bytes_to_compress, int *bytes_after_compressed) ; +int inf(char *src, char *dst, int bytes_to_decompress, int maximum_after_decompress, int* outbytes); + +#endif diff --git a/plugins/zerogs_2008.sln b/plugins/zerogs_2008.sln new file mode 100644 index 0000000000..41a1dab5cb --- /dev/null +++ b/plugins/zerogs_2008.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zerogs", "zerogs\dx\Win32\zerogs_2008.vcproj", "{5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zerogsogl_2005", "zerogs\opengl\Win32\zerogsogl_2008.vcproj", "{2D4E85B2-F47F-4D65-B091-701E5C031DAC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release (to Public)|Win32 = Release (to Public)|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug|Win32.ActiveCfg = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Debug|Win32.Build.0 = Debug|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release (to Public)|Win32.ActiveCfg = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release (to Public)|Win32.Build.0 = Release (to Public)|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release|Win32.ActiveCfg = Release|Win32 + {5C6B7D28-E73D-4F71-8FC0-17ADA640EBD8}.Release|Win32.Build.0 = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug|Win32.ActiveCfg = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Debug|Win32.Build.0 = Debug|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public)|Win32.ActiveCfg = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release (to Public)|Win32.Build.0 = Release (to Public)|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release|Win32.ActiveCfg = Release|Win32 + {2D4E85B2-F47F-4D65-B091-701E5C031DAC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/zeropad/Linux/callbacks.h b/plugins/zeropad/Linux/callbacks.h new file mode 100644 index 0000000000..cb64e16292 --- /dev/null +++ b/plugins/zeropad/Linux/callbacks.h @@ -0,0 +1,46 @@ +#include + + +void +OnConf_Pad1 (GtkButton *button, + gpointer user_data); + +void +OnConf_Pad2 (GtkButton *button, + gpointer user_data); + +void +OnConf_Key (GtkButton *button, + gpointer user_data); + +void +OnConf_Cancel (GtkButton *button, + gpointer user_data); + +void +OnConf_Ok (GtkButton *button, + gpointer user_data); + +void +on_joydevicescombo_changed (GtkComboBox *combobox, + gpointer user_data); + +void +on_checkbutton_reverselx_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_checkbutton_reversely_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_checkbutton_reverserx_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_checkbutton_reversery_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_forcefeedback_toggled (GtkToggleButton *togglebutton, + gpointer user_data); diff --git a/plugins/zeropad/Linux/interface.c b/plugins/zeropad/Linux/interface.c new file mode 100644 index 0000000000..ffd4261e65 --- /dev/null +++ b/plugins/zeropad/Linux/interface.c @@ -0,0 +1,640 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ + g_object_set_data (G_OBJECT (component), name, widget) + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + const gchar *authors[] = { + "Author: zerofrog(@gmail.com)", + "Thanks to:", + " linuzappz ", + "florin sasu ", + "and SSSPSXPad, TwinPad authors", + NULL + }; + /* TRANSLATORS: Replace this string with your names, one name per line. */ + gchar *translators = _("translator-credits"); + + About = gtk_about_dialog_new (); + gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (About), VERSION); + gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (About), _("ZeroPAD")); + gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (About), authors); + gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (About), translators); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (About, About, "About"); + + return About; +} + +GtkWidget* +create_Conf (void) +{ + GtkWidget *Conf; + GtkWidget *dialog_vbox1; + GtkWidget *vbox1; + GtkWidget *frame1; + GtkWidget *alignment1; + GtkWidget *hbox1; + GtkWidget *PAD1; + GSList *PAD1_group = NULL; + GtkWidget *PAD2; + GtkWidget *label2; + GtkWidget *vbox2; + GtkWidget *label5; + GtkWidget *joydevicescombo; + GtkWidget *fixed1; + GtkWidget *eL2; + GtkWidget *eL1; + GtkWidget *eSelect; + GtkWidget *eStart; + GtkWidget *eUp; + GtkWidget *eRight; + GtkWidget *eLeft; + GtkWidget *eDown; + GtkWidget *eR2; + GtkWidget *eR1; + GtkWidget *eAnalog; + GtkWidget *eSquare; + GtkWidget *eTriangle; + GtkWidget *eCircle; + GtkWidget *eCross; + GtkWidget *eR3; + GtkWidget *eL3; + GtkWidget *eRx; + GtkWidget *eLx; + GtkWidget *eRy; + GtkWidget *eLy; + GtkWidget *Select; + GtkWidget *L1; + GtkWidget *Left; + GtkWidget *Down; + GtkWidget *Analog; + GtkWidget *R2; + GtkWidget *Start; + GtkWidget *R1; + GtkWidget *Cross; + GtkWidget *Triangle; + GtkWidget *Circle; + GtkWidget *Square; + GtkWidget *L3; + GtkWidget *Up; + GtkWidget *L2; + GtkWidget *Lx; + GtkWidget *Ly; + GtkWidget *Rx; + GtkWidget *Ry; + GtkWidget *Right; + GtkWidget *label3; + GtkWidget *R3; + GtkWidget *checkbutton_reverselx; + GtkWidget *checkbutton_reversely; + GtkWidget *checkbutton_reverserx; + GtkWidget *checkbutton_reversery; + GtkWidget *forcefeedback; + GtkWidget *dialog_action_area1; + GtkWidget *cancelbutton1; + GtkWidget *okbutton1; + + Conf = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (Conf), _("ZeroPAD Configuration Dialog")); + gtk_window_set_type_hint (GTK_WINDOW (Conf), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox1 = GTK_DIALOG (Conf)->vbox; + gtk_widget_show (dialog_vbox1); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox1); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox1, TRUE, TRUE, 0); + + frame1 = gtk_frame_new (NULL); + gtk_widget_show (frame1); + gtk_box_pack_start (GTK_BOX (vbox1), frame1, FALSE, FALSE, 0); + + alignment1 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment1); + gtk_container_add (GTK_CONTAINER (frame1), alignment1); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment1), 0, 0, 12, 0); + + hbox1 = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox1); + gtk_container_add (GTK_CONTAINER (alignment1), hbox1); + + PAD1 = gtk_radio_button_new_with_mnemonic (NULL, _("PAD1")); + gtk_widget_show (PAD1); + gtk_box_pack_start (GTK_BOX (hbox1), PAD1, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (PAD1), PAD1_group); + PAD1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (PAD1)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (PAD1), TRUE); + + PAD2 = gtk_radio_button_new_with_mnemonic (NULL, _("PAD2")); + gtk_widget_show (PAD2); + gtk_box_pack_start (GTK_BOX (hbox1), PAD2, FALSE, FALSE, 0); + gtk_radio_button_set_group (GTK_RADIO_BUTTON (PAD2), PAD1_group); + PAD1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (PAD2)); + + label2 = gtk_label_new (_("Choose PAD to modify")); + gtk_widget_show (label2); + gtk_frame_set_label_widget (GTK_FRAME (frame1), label2); + gtk_label_set_use_markup (GTK_LABEL (label2), TRUE); + + vbox2 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (vbox1), vbox2, TRUE, TRUE, 0); + + label5 = gtk_label_new (_("Joystick to use for this PAD")); + gtk_widget_show (label5); + gtk_box_pack_start (GTK_BOX (vbox2), label5, FALSE, FALSE, 0); + + joydevicescombo = gtk_combo_box_entry_new_text (); + gtk_widget_show (joydevicescombo); + gtk_box_pack_start (GTK_BOX (vbox2), joydevicescombo, TRUE, TRUE, 0); + + fixed1 = gtk_fixed_new (); + gtk_widget_show (fixed1); + gtk_box_pack_start (GTK_BOX (vbox1), fixed1, TRUE, TRUE, 0); + + eL2 = gtk_entry_new (); + gtk_widget_show (eL2); + gtk_fixed_put (GTK_FIXED (fixed1), eL2, 64, 40); + gtk_widget_set_size_request (eL2, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eL2), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eL2), 8226); + + eL1 = gtk_entry_new (); + gtk_widget_show (eL1); + gtk_fixed_put (GTK_FIXED (fixed1), eL1, 64, 104); + gtk_widget_set_size_request (eL1, 64, 24); + gtk_entry_set_invisible_char (GTK_ENTRY (eL1), 8226); + + eSelect = gtk_entry_new (); + gtk_widget_show (eSelect); + gtk_fixed_put (GTK_FIXED (fixed1), eSelect, 168, 64); + gtk_widget_set_size_request (eSelect, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eSelect), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eSelect), 8226); + + eStart = gtk_entry_new (); + gtk_widget_show (eStart); + gtk_fixed_put (GTK_FIXED (fixed1), eStart, 280, 64); + gtk_widget_set_size_request (eStart, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eStart), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eStart), 8226); + + eUp = gtk_entry_new (); + gtk_widget_show (eUp); + gtk_fixed_put (GTK_FIXED (fixed1), eUp, 64, 168); + gtk_widget_set_size_request (eUp, 64, 24); + gtk_entry_set_invisible_char (GTK_ENTRY (eUp), 8226); + + eRight = gtk_entry_new (); + gtk_widget_show (eRight); + gtk_fixed_put (GTK_FIXED (fixed1), eRight, 128, 208); + gtk_widget_set_size_request (eRight, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eRight), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eRight), 8226); + + eLeft = gtk_entry_new (); + gtk_widget_show (eLeft); + gtk_fixed_put (GTK_FIXED (fixed1), eLeft, 0, 208); + gtk_widget_set_size_request (eLeft, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eLeft), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eLeft), 8226); + + eDown = gtk_entry_new (); + gtk_widget_show (eDown); + gtk_fixed_put (GTK_FIXED (fixed1), eDown, 64, 256); + gtk_widget_set_size_request (eDown, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eDown), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eDown), 8226); + + eR2 = gtk_entry_new (); + gtk_widget_show (eR2); + gtk_fixed_put (GTK_FIXED (fixed1), eR2, 368, 32); + gtk_widget_set_size_request (eR2, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eR2), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eR2), 8226); + + eR1 = gtk_entry_new (); + gtk_widget_show (eR1); + gtk_fixed_put (GTK_FIXED (fixed1), eR1, 368, 104); + gtk_widget_set_size_request (eR1, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eR1), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eR1), 8226); + + eAnalog = gtk_entry_new (); + gtk_widget_show (eAnalog); + gtk_fixed_put (GTK_FIXED (fixed1), eAnalog, 224, 128); + gtk_widget_set_size_request (eAnalog, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eAnalog), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eAnalog), 8226); + + eSquare = gtk_entry_new (); + gtk_widget_show (eSquare); + gtk_fixed_put (GTK_FIXED (fixed1), eSquare, 304, 208); + gtk_widget_set_size_request (eSquare, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eSquare), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eSquare), 8226); + + eTriangle = gtk_entry_new (); + gtk_widget_show (eTriangle); + gtk_fixed_put (GTK_FIXED (fixed1), eTriangle, 368, 168); + gtk_widget_set_size_request (eTriangle, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eTriangle), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eTriangle), 8226); + + eCircle = gtk_entry_new (); + gtk_widget_show (eCircle); + gtk_fixed_put (GTK_FIXED (fixed1), eCircle, 432, 208); + gtk_widget_set_size_request (eCircle, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eCircle), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eCircle), 8226); + + eCross = gtk_entry_new (); + gtk_widget_show (eCross); + gtk_fixed_put (GTK_FIXED (fixed1), eCross, 368, 256); + gtk_widget_set_size_request (eCross, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eCross), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eCross), 8226); + + eR3 = gtk_entry_new (); + gtk_widget_show (eR3); + gtk_fixed_put (GTK_FIXED (fixed1), eR3, 272, 272); + gtk_widget_set_size_request (eR3, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eR3), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eR3), 8226); + + eL3 = gtk_entry_new (); + gtk_widget_show (eL3); + gtk_fixed_put (GTK_FIXED (fixed1), eL3, 176, 272); + gtk_widget_set_size_request (eL3, 64, 24); + gtk_editable_set_editable (GTK_EDITABLE (eL3), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eL3), 8226); + + eRx = gtk_entry_new (); + gtk_widget_show (eRx); + gtk_fixed_put (GTK_FIXED (fixed1), eRx, 272, 352); + gtk_widget_set_size_request (eRx, 80, 24); + gtk_editable_set_editable (GTK_EDITABLE (eRx), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eRx), 8226); + + eLx = gtk_entry_new (); + gtk_widget_show (eLx); + gtk_fixed_put (GTK_FIXED (fixed1), eLx, 160, 352); + gtk_widget_set_size_request (eLx, 80, 24); + gtk_editable_set_editable (GTK_EDITABLE (eLx), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eLx), 8226); + + eRy = gtk_entry_new (); + gtk_widget_show (eRy); + gtk_fixed_put (GTK_FIXED (fixed1), eRy, 272, 416); + gtk_widget_set_size_request (eRy, 80, 24); + gtk_editable_set_editable (GTK_EDITABLE (eRy), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eRy), 8226); + + eLy = gtk_entry_new (); + gtk_widget_show (eLy); + gtk_fixed_put (GTK_FIXED (fixed1), eLy, 160, 416); + gtk_widget_set_size_request (eLy, 80, 24); + gtk_editable_set_editable (GTK_EDITABLE (eLy), FALSE); + gtk_entry_set_invisible_char (GTK_ENTRY (eLy), 8226); + + Select = gtk_button_new_with_mnemonic (_("Select")); + gtk_widget_show (Select); + gtk_fixed_put (GTK_FIXED (fixed1), Select, 168, 32); + gtk_widget_set_size_request (Select, 64, 32); + + L1 = gtk_button_new_with_mnemonic (_("L1")); + gtk_widget_show (L1); + gtk_fixed_put (GTK_FIXED (fixed1), L1, 64, 72); + gtk_widget_set_size_request (L1, 64, 32); + + Left = gtk_button_new_with_mnemonic (_("Left")); + gtk_widget_show (Left); + gtk_fixed_put (GTK_FIXED (fixed1), Left, 0, 176); + gtk_widget_set_size_request (Left, 64, 32); + + Down = gtk_button_new_with_mnemonic (_("Down")); + gtk_widget_show (Down); + gtk_fixed_put (GTK_FIXED (fixed1), Down, 64, 224); + gtk_widget_set_size_request (Down, 64, 32); + + Analog = gtk_button_new_with_mnemonic (_("Analog")); + gtk_widget_show (Analog); + gtk_fixed_put (GTK_FIXED (fixed1), Analog, 224, 96); + gtk_widget_set_size_request (Analog, 64, 32); + + R2 = gtk_button_new_with_mnemonic (_("R2")); + gtk_widget_show (R2); + gtk_fixed_put (GTK_FIXED (fixed1), R2, 368, 0); + gtk_widget_set_size_request (R2, 64, 32); + + Start = gtk_button_new_with_mnemonic (_("Start")); + gtk_widget_show (Start); + gtk_fixed_put (GTK_FIXED (fixed1), Start, 280, 32); + gtk_widget_set_size_request (Start, 64, 32); + + R1 = gtk_button_new_with_mnemonic (_("R1")); + gtk_widget_show (R1); + gtk_fixed_put (GTK_FIXED (fixed1), R1, 368, 72); + gtk_widget_set_size_request (R1, 64, 32); + + Cross = gtk_button_new_with_mnemonic (_("Cross")); + gtk_widget_show (Cross); + gtk_fixed_put (GTK_FIXED (fixed1), Cross, 368, 224); + gtk_widget_set_size_request (Cross, 64, 32); + + Triangle = gtk_button_new_with_mnemonic (_("Triangle")); + gtk_widget_show (Triangle); + gtk_fixed_put (GTK_FIXED (fixed1), Triangle, 368, 136); + gtk_widget_set_size_request (Triangle, 64, 32); + + Circle = gtk_button_new_with_mnemonic (_("Circle")); + gtk_widget_show (Circle); + gtk_fixed_put (GTK_FIXED (fixed1), Circle, 432, 176); + gtk_widget_set_size_request (Circle, 64, 32); + + Square = gtk_button_new_with_mnemonic (_("Square")); + gtk_widget_show (Square); + gtk_fixed_put (GTK_FIXED (fixed1), Square, 304, 176); + gtk_widget_set_size_request (Square, 64, 32); + + L3 = gtk_button_new_with_mnemonic (_("L3")); + gtk_widget_show (L3); + gtk_fixed_put (GTK_FIXED (fixed1), L3, 176, 240); + gtk_widget_set_size_request (L3, 64, 32); + + Up = gtk_button_new_with_mnemonic (_("Up")); + gtk_widget_show (Up); + gtk_fixed_put (GTK_FIXED (fixed1), Up, 64, 136); + gtk_widget_set_size_request (Up, 64, 32); + + L2 = gtk_button_new_with_mnemonic (_("L2")); + gtk_widget_show (L2); + gtk_fixed_put (GTK_FIXED (fixed1), L2, 64, 8); + gtk_widget_set_size_request (L2, 64, 32); + + Lx = gtk_button_new_with_mnemonic (_("Lx")); + gtk_widget_show (Lx); + gtk_fixed_put (GTK_FIXED (fixed1), Lx, 160, 320); + gtk_widget_set_size_request (Lx, 80, 32); + + Ly = gtk_button_new_with_mnemonic (_("Ly")); + gtk_widget_show (Ly); + gtk_fixed_put (GTK_FIXED (fixed1), Ly, 160, 384); + gtk_widget_set_size_request (Ly, 80, 32); + + Rx = gtk_button_new_with_mnemonic (_("Rx")); + gtk_widget_show (Rx); + gtk_fixed_put (GTK_FIXED (fixed1), Rx, 272, 320); + gtk_widget_set_size_request (Rx, 80, 32); + + Ry = gtk_button_new_with_mnemonic (_("Ry")); + gtk_widget_show (Ry); + gtk_fixed_put (GTK_FIXED (fixed1), Ry, 272, 384); + gtk_widget_set_size_request (Ry, 80, 32); + + Right = gtk_button_new_with_mnemonic (_("Right")); + gtk_widget_show (Right); + gtk_fixed_put (GTK_FIXED (fixed1), Right, 128, 176); + gtk_widget_set_size_request (Right, 64, 32); + + label3 = gtk_label_new (_("Analog Controls (move mouse or analog joystick to select)")); + gtk_widget_show (label3); + gtk_fixed_put (GTK_FIXED (fixed1), label3, 48, 296); + gtk_widget_set_size_request (label3, 408, 16); + gtk_label_set_single_line_mode (GTK_LABEL (label3), TRUE); + + R3 = gtk_button_new_with_mnemonic (_("R3")); + gtk_widget_show (R3); + gtk_fixed_put (GTK_FIXED (fixed1), R3, 272, 240); + gtk_widget_set_size_request (R3, 64, 32); + + checkbutton_reverselx = gtk_check_button_new_with_mnemonic (_("Reverse LX")); + gtk_widget_show (checkbutton_reverselx); + gtk_fixed_put (GTK_FIXED (fixed1), checkbutton_reverselx, 16, 328); + gtk_widget_set_size_request (checkbutton_reverselx, 111, 22); + + checkbutton_reversely = gtk_check_button_new_with_mnemonic (_("Reverse LY")); + gtk_widget_show (checkbutton_reversely); + gtk_fixed_put (GTK_FIXED (fixed1), checkbutton_reversely, 16, 352); + gtk_widget_set_size_request (checkbutton_reversely, 111, 22); + + checkbutton_reverserx = gtk_check_button_new_with_mnemonic (_("Reverse RX")); + gtk_widget_show (checkbutton_reverserx); + gtk_fixed_put (GTK_FIXED (fixed1), checkbutton_reverserx, 16, 376); + gtk_widget_set_size_request (checkbutton_reverserx, 111, 22); + + checkbutton_reversery = gtk_check_button_new_with_mnemonic (_("Reverse RY")); + gtk_widget_show (checkbutton_reversery); + gtk_fixed_put (GTK_FIXED (fixed1), checkbutton_reversery, 16, 400); + gtk_widget_set_size_request (checkbutton_reversery, 111, 22); + + forcefeedback = gtk_check_button_new_with_mnemonic (_("Enable Force\nFeedback")); + gtk_widget_show (forcefeedback); + gtk_fixed_put (GTK_FIXED (fixed1), forcefeedback, 384, 320); + gtk_widget_set_size_request (forcefeedback, 112, 48); + + dialog_action_area1 = GTK_DIALOG (Conf)->action_area; + gtk_widget_show (dialog_action_area1); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); + + cancelbutton1 = gtk_button_new_from_stock ("gtk-cancel"); + gtk_widget_show (cancelbutton1); + gtk_dialog_add_action_widget (GTK_DIALOG (Conf), cancelbutton1, GTK_RESPONSE_CANCEL); + GTK_WIDGET_SET_FLAGS (cancelbutton1, GTK_CAN_DEFAULT); + + okbutton1 = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (okbutton1); + gtk_dialog_add_action_widget (GTK_DIALOG (Conf), okbutton1, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (okbutton1, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) PAD1, "clicked", + G_CALLBACK (OnConf_Pad1), + NULL); + g_signal_connect ((gpointer) PAD2, "clicked", + G_CALLBACK (OnConf_Pad2), + NULL); + g_signal_connect ((gpointer) joydevicescombo, "changed", + G_CALLBACK (on_joydevicescombo_changed), + NULL); + g_signal_connect ((gpointer) Select, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) L1, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Left, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Down, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Analog, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) R2, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Start, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) R1, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Cross, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Triangle, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Circle, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Square, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) L3, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Up, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) L2, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Lx, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Ly, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Rx, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Ry, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) Right, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) R3, "clicked", + G_CALLBACK (OnConf_Key), + NULL); + g_signal_connect ((gpointer) checkbutton_reverselx, "toggled", + G_CALLBACK (on_checkbutton_reverselx_toggled), + NULL); + g_signal_connect ((gpointer) checkbutton_reversely, "toggled", + G_CALLBACK (on_checkbutton_reversely_toggled), + NULL); + g_signal_connect ((gpointer) checkbutton_reverserx, "toggled", + G_CALLBACK (on_checkbutton_reverserx_toggled), + NULL); + g_signal_connect ((gpointer) checkbutton_reversery, "toggled", + G_CALLBACK (on_checkbutton_reversery_toggled), + NULL); + g_signal_connect ((gpointer) forcefeedback, "toggled", + G_CALLBACK (on_forcefeedback_toggled), + NULL); + g_signal_connect ((gpointer) cancelbutton1, "clicked", + G_CALLBACK (OnConf_Cancel), + NULL); + g_signal_connect ((gpointer) okbutton1, "clicked", + G_CALLBACK (OnConf_Ok), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (Conf, Conf, "Conf"); + GLADE_HOOKUP_OBJECT_NO_REF (Conf, dialog_vbox1, "dialog_vbox1"); + GLADE_HOOKUP_OBJECT (Conf, vbox1, "vbox1"); + GLADE_HOOKUP_OBJECT (Conf, frame1, "frame1"); + GLADE_HOOKUP_OBJECT (Conf, alignment1, "alignment1"); + GLADE_HOOKUP_OBJECT (Conf, hbox1, "hbox1"); + GLADE_HOOKUP_OBJECT (Conf, PAD1, "PAD1"); + GLADE_HOOKUP_OBJECT (Conf, PAD2, "PAD2"); + GLADE_HOOKUP_OBJECT (Conf, label2, "label2"); + GLADE_HOOKUP_OBJECT (Conf, vbox2, "vbox2"); + GLADE_HOOKUP_OBJECT (Conf, label5, "label5"); + GLADE_HOOKUP_OBJECT (Conf, joydevicescombo, "joydevicescombo"); + GLADE_HOOKUP_OBJECT (Conf, fixed1, "fixed1"); + GLADE_HOOKUP_OBJECT (Conf, eL2, "eL2"); + GLADE_HOOKUP_OBJECT (Conf, eL1, "eL1"); + GLADE_HOOKUP_OBJECT (Conf, eSelect, "eSelect"); + GLADE_HOOKUP_OBJECT (Conf, eStart, "eStart"); + GLADE_HOOKUP_OBJECT (Conf, eUp, "eUp"); + GLADE_HOOKUP_OBJECT (Conf, eRight, "eRight"); + GLADE_HOOKUP_OBJECT (Conf, eLeft, "eLeft"); + GLADE_HOOKUP_OBJECT (Conf, eDown, "eDown"); + GLADE_HOOKUP_OBJECT (Conf, eR2, "eR2"); + GLADE_HOOKUP_OBJECT (Conf, eR1, "eR1"); + GLADE_HOOKUP_OBJECT (Conf, eAnalog, "eAnalog"); + GLADE_HOOKUP_OBJECT (Conf, eSquare, "eSquare"); + GLADE_HOOKUP_OBJECT (Conf, eTriangle, "eTriangle"); + GLADE_HOOKUP_OBJECT (Conf, eCircle, "eCircle"); + GLADE_HOOKUP_OBJECT (Conf, eCross, "eCross"); + GLADE_HOOKUP_OBJECT (Conf, eR3, "eR3"); + GLADE_HOOKUP_OBJECT (Conf, eL3, "eL3"); + GLADE_HOOKUP_OBJECT (Conf, eRx, "eRx"); + GLADE_HOOKUP_OBJECT (Conf, eLx, "eLx"); + GLADE_HOOKUP_OBJECT (Conf, eRy, "eRy"); + GLADE_HOOKUP_OBJECT (Conf, eLy, "eLy"); + GLADE_HOOKUP_OBJECT (Conf, Select, "Select"); + GLADE_HOOKUP_OBJECT (Conf, L1, "L1"); + GLADE_HOOKUP_OBJECT (Conf, Left, "Left"); + GLADE_HOOKUP_OBJECT (Conf, Down, "Down"); + GLADE_HOOKUP_OBJECT (Conf, Analog, "Analog"); + GLADE_HOOKUP_OBJECT (Conf, R2, "R2"); + GLADE_HOOKUP_OBJECT (Conf, Start, "Start"); + GLADE_HOOKUP_OBJECT (Conf, R1, "R1"); + GLADE_HOOKUP_OBJECT (Conf, Cross, "Cross"); + GLADE_HOOKUP_OBJECT (Conf, Triangle, "Triangle"); + GLADE_HOOKUP_OBJECT (Conf, Circle, "Circle"); + GLADE_HOOKUP_OBJECT (Conf, Square, "Square"); + GLADE_HOOKUP_OBJECT (Conf, L3, "L3"); + GLADE_HOOKUP_OBJECT (Conf, Up, "Up"); + GLADE_HOOKUP_OBJECT (Conf, L2, "L2"); + GLADE_HOOKUP_OBJECT (Conf, Lx, "Lx"); + GLADE_HOOKUP_OBJECT (Conf, Ly, "Ly"); + GLADE_HOOKUP_OBJECT (Conf, Rx, "Rx"); + GLADE_HOOKUP_OBJECT (Conf, Ry, "Ry"); + GLADE_HOOKUP_OBJECT (Conf, Right, "Right"); + GLADE_HOOKUP_OBJECT (Conf, label3, "label3"); + GLADE_HOOKUP_OBJECT (Conf, R3, "R3"); + GLADE_HOOKUP_OBJECT (Conf, checkbutton_reverselx, "checkbutton_reverselx"); + GLADE_HOOKUP_OBJECT (Conf, checkbutton_reversely, "checkbutton_reversely"); + GLADE_HOOKUP_OBJECT (Conf, checkbutton_reverserx, "checkbutton_reverserx"); + GLADE_HOOKUP_OBJECT (Conf, checkbutton_reversery, "checkbutton_reversery"); + GLADE_HOOKUP_OBJECT (Conf, forcefeedback, "forcefeedback"); + GLADE_HOOKUP_OBJECT_NO_REF (Conf, dialog_action_area1, "dialog_action_area1"); + GLADE_HOOKUP_OBJECT (Conf, cancelbutton1, "cancelbutton1"); + GLADE_HOOKUP_OBJECT (Conf, okbutton1, "okbutton1"); + + return Conf; +} + diff --git a/plugins/zeropad/Linux/interface.h b/plugins/zeropad/Linux/interface.h new file mode 100644 index 0000000000..3672165062 --- /dev/null +++ b/plugins/zeropad/Linux/interface.h @@ -0,0 +1,6 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_About (void); +GtkWidget* create_Conf (void); diff --git a/plugins/zeropad/Linux/linux.cpp b/plugins/zeropad/Linux/linux.cpp new file mode 100644 index 0000000000..d520041f50 --- /dev/null +++ b/plugins/zeropad/Linux/linux.cpp @@ -0,0 +1,829 @@ +/* ZeroPAD - author: zerofrog(@gmail.com) + * Copyright (C) 2006-2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#define JOYSTICK_SUPPORT +#ifdef JOYSTICK_SUPPORT +#include +#endif + +#include "zeropad.h" + +extern "C" { +#include "interface.h" +#include "support.h" +#include "callbacks.h" +} + +Display *GSdsp; +static pthread_spinlock_t s_mutexStatus; +static u32 s_keyPress[2], s_keyRelease[2]; // thread safe +static u32 s_bSDLInit = false; + +// holds all joystick info +class JoystickInfo +{ +public: + JoystickInfo(); + ~JoystickInfo() { Destroy(); } + + void Destroy(); + // opens handles to all possible joysticks + static void EnumerateJoysticks(vector& vjoysticks); + + bool Init(int id, bool bStartThread=true); // opens a handle and gets information + void Assign(int pad); // assigns a joystick to a pad + + void TestForce(); + + const string& GetName() { return devname; } + int GetNumButtons() { return numbuttons; } + int GetNumAxes() { return numaxes; } + int GetNumPOV() { return numpov; } + int GetId() { return _id; } + int GetPAD() { return pad; } + int GetDeadzone(int axis) { return deadzone; } + + void SaveState(); + int GetButtonState(int i) { return vbutstate[i]; } + int GetAxisState(int i) { return vaxisstate[i]; } + void SetButtonState(int i, int state) { vbutstate[i] = state; } + void SetAxisState(int i, int value) { vaxisstate[i] = value; } +#ifdef JOYSTICK_SUPPORT + SDL_Joystick* GetJoy() { return joy; } +#endif + +private: + + string devname; // pretty device name + int _id; + int numbuttons, numaxes, numpov; + int axisrange, deadzone; + int pad; + + vector vbutstate, vaxisstate; + +#ifdef JOYSTICK_SUPPORT + SDL_Joystick* joy; +#endif +}; + +static vector s_vjoysticks; + +extern string s_strIniPath; + +void SaveConfig() +{ + int i, j; + FILE *f; + char cfg[255]; + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg,"w"); + if (f == NULL) { + printf("ZeroPAD: failed to save ini %s\n", s_strIniPath.c_str()); + return; + } + + for (j=0; j<2; j++) { + for (i=0; i::iterator it; + FORIT(it, s_vjoysticks) delete *it; + s_vjoysticks.clear(); +} + +void _PADupdate(int pad) +{ + pthread_spin_lock(&s_mutexStatus); + status[pad] |= s_keyRelease[pad]; + status[pad] &= ~s_keyPress[pad]; + s_keyRelease[pad] = 0; + s_keyPress[pad] = 0; + pthread_spin_unlock(&s_mutexStatus); +} + +int _GetJoystickIdFromPAD(int pad) +{ + // select the right joystick id + int joyid = -1; + for(int i = 0; i < PADKEYS; ++i) { + if( IS_JOYSTICK(conf.keys[pad][i]) || IS_JOYBUTTONS(conf.keys[pad][i]) ) { + joyid = PAD_GETJOYID(conf.keys[pad][i]); + break; + } + } + + return joyid; +} + +void CALLBACK PADupdate(int pad) +{ + int i; + XEvent E; + int keyPress=0,keyRelease=0; + KeySym key; + + // keyboard input + while (XPending(GSdsp) > 0) { + XNextEvent(GSdsp, &E); + switch (E.type) { + case KeyPress: + //_KeyPress(pad, XLookupKeysym((XKeyEvent *)&E, 0)); break; + key = XLookupKeysym((XKeyEvent *)&E, 0); + for (i=0; i= 0 && joyid < (int)s_vjoysticks.size()) { + pjoy = s_vjoysticks[joyid]; + if( SDL_JoystickGetButton((pjoy)->GetJoy(), PAD_GETJOYBUTTON(key)) ) { + status[(pjoy)->GetPAD()] &= ~(1<GetPAD()] |= (1<= 0 && joyid < (int)s_vjoysticks.size()) { + + pjoy = s_vjoysticks[joyid]; + int value = SDL_JoystickGetAxis((pjoy)->GetJoy(), PAD_GETJOYSTICK_AXIS(key)); + int pad = (pjoy)->GetPAD(); + switch(i) { + case PAD_LX: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_lanalog[pad].x = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_lanalog[pad].x = -g_lanalog[pad].x; + g_lanalog[pad].x += 0x80; + } + else g_lanalog[pad].x = 0x80; + break; + case PAD_LY: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_lanalog[pad].y = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_lanalog[pad].y = -g_lanalog[pad].y; + g_lanalog[pad].y += 0x80; + } + else g_lanalog[pad].y = 0x80; + break; + case PAD_RX: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_ranalog[pad].x = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_ranalog[pad].x = -g_ranalog[pad].x; + g_ranalog[pad].x += 0x80; + } + else g_ranalog[pad].x = 0x80; + break; + case PAD_RY: + if( abs(value) > (pjoy)->GetDeadzone(value) ) { + g_ranalog[pad].y = value/256; + if( conf.options&PADOPTION_REVERTLX ) + g_ranalog[pad].y = -g_ranalog[pad].y; + g_ranalog[pad].y += 0x80; + } + else g_ranalog[pad].y = 0x80; + break; + } + } + } + else if( IS_POV(key) ) { + int joyid = PAD_GETJOYID(key); + if( joyid >= 0 && joyid < (int)s_vjoysticks.size()) { + + pjoy = s_vjoysticks[joyid]; + + int value = SDL_JoystickGetAxis((pjoy)->GetJoy(), PAD_GETJOYSTICK_AXIS(key)); + int pad = (pjoy)->GetPAD(); + if( PAD_GETPOVSIGN(key) && (value<-2048) ) + status[pad] &= ~(1<2048) ) + status[pad] &= ~(1< 0) { + gtk_entry_set_text(GTK_ENTRY(Btn), tmp.c_str()); + } + else + gtk_entry_set_text(GTK_ENTRY(Btn), "Unknown"); + + gtk_object_set_user_data(GTK_OBJECT(Btn), (void*)(PADKEYS*pad+i)); + } + + // check bounds + int joyid = _GetJoystickIdFromPAD(pad); + if( joyid < 0 || joyid >= (int)s_vjoysticks.size() ) { + // get first unused joystick + for(joyid = 0; joyid < s_vjoysticks.size(); ++joyid) { + if( s_vjoysticks[joyid]->GetPAD() < 0 ) + break; + } + } + + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) { + // select the combo + gtk_combo_box_set_active(GTK_COMBO_BOX(s_devicecombo), joyid); + } + else gtk_combo_box_set_active(GTK_COMBO_BOX(s_devicecombo), s_vjoysticks.size()); // no gamepad + + int padopts = conf.options>>(16*pad); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reverselx")), padopts&PADOPTION_REVERTLX); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reversely")), padopts&PADOPTION_REVERTLY); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reverserx")), padopts&PADOPTION_REVERTRX); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "checkbutton_reversery")), padopts&PADOPTION_REVERTRY); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(Conf, "forcefeedback")), padopts&PADOPTION_FORCEFEEDBACK); +} + +void OnConf_Key(GtkButton *button, gpointer user_data) +{ + GdkEvent *ev; + GtkWidget* label = lookup_widget(Conf, GetLabelFromButton(gtk_button_get_label(button)).c_str()); + if( label == NULL ) { + printf("couldn't find correct label\n"); + return; + } + + int id = (int)(uptr)gtk_object_get_user_data(GTK_OBJECT(label)); + int pad = id/PADKEYS; + int key = id%PADKEYS; + unsigned long *pkey = &conf.keys[pad][key]; + + vector::iterator itjoy; + + // save the states +#ifdef JOYSTICK_SUPPORT + SDL_JoystickUpdate(); + FORIT(itjoy, s_vjoysticks) (*itjoy)->SaveState(); +#endif + + for (;;) { + ev = gdk_event_get(); + if (ev != NULL) { + if (ev->type == GDK_KEY_PRESS) { + *pkey = ev->key.keyval; + + char* tmp = XKeysymToString(*pkey); + if (tmp != NULL) + gtk_entry_set_text(GTK_ENTRY(label), tmp); + else + gtk_entry_set_text(GTK_ENTRY(label), "Unknown"); + return; + } + } + +#ifdef JOYSTICK_SUPPORT + SDL_JoystickUpdate(); + FORIT(itjoy, s_vjoysticks) { + + // MAKE sure to look for changes in the state!! + + for(int i = 0; i < (*itjoy)->GetNumButtons(); ++i) { + int but = SDL_JoystickGetButton((*itjoy)->GetJoy(), i); + if( but != (*itjoy)->GetButtonState(i) ) { + + if( !but ) { // released, we don't really want this + (*itjoy)->SetButtonState(i, 0); + break; + } + + *pkey = PAD_JOYBUTTON((*itjoy)->GetId(), i); + char str[32]; + sprintf(str, "JBut %d", i); + gtk_entry_set_text(GTK_ENTRY(label), str); + return; + } + } + + for(int i = 0; i < (*itjoy)->GetNumAxes(); ++i) { + int value = SDL_JoystickGetAxis((*itjoy)->GetJoy(), i); + + if( value != (*itjoy)->GetAxisState(i) ) { + + if( abs(value) <= (*itjoy)->GetAxisState(i)) {// we don't want this + // released, we don't really want this + (*itjoy)->SetButtonState(i, value); + break; + } + + + if( abs(value) > 0x3fff ) { + if( key < 16 ) { // POV + *pkey = PAD_POV((*itjoy)->GetId(), value<0, i); + char str[32]; + sprintf(str, "JPOV %d%s", i, value<0?"-":"+"); + gtk_entry_set_text(GTK_ENTRY(label), str); + return; + } + else { // axis + *pkey = PAD_JOYSTICK((*itjoy)->GetId(), i); + char str[32]; + sprintf(str, "JAxis %d", i); + gtk_entry_set_text(GTK_ENTRY(label), str); + return; + } + } + } + } + } +#endif + } +} + +void OnConf_Pad1(GtkButton *button, gpointer user_data) +{ + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) ) + UpdateConf(0); +} + +void OnConf_Pad2(GtkButton *button, gpointer user_data) +{ + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) ) + UpdateConf(1); +} + +void OnConf_Ok(GtkButton *button, gpointer user_data) +{ +// conf.analog = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(Analog)); + SaveConfig(); + + gtk_widget_destroy(Conf); + gtk_main_quit(); +} + +void OnConf_Cancel(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(Conf); + gtk_main_quit(); + LoadConfig(); // load previous config +} + +void CALLBACK PADconfigure() +{ + LoadConfig(); + + Conf = create_Conf(); + + // recreate + JoystickInfo::EnumerateJoysticks(s_vjoysticks); + + s_devicecombo = lookup_widget(Conf, "joydevicescombo"); + + // fill the combo + char str[255]; + vector::iterator it; + FORIT(it, s_vjoysticks) { + sprintf(str, "%d: %s - but: %d, axes: %d, pov: %d", (*it)->GetId(), (*it)->GetName().c_str(), + (*it)->GetNumButtons(), (*it)->GetNumAxes(), (*it)->GetNumPOV()); + gtk_combo_box_append_text (GTK_COMBO_BOX (s_devicecombo), str); + } + gtk_combo_box_append_text (GTK_COMBO_BOX (s_devicecombo), "No Gamepad"); + + UpdateConf(0); + + gtk_widget_show_all(Conf); + gtk_main(); +} + +// GUI event handlers +void on_joydevicescombo_changed(GtkComboBox *combobox, gpointer user_data) +{ + int joyid = gtk_combo_box_get_active(combobox); + + // unassign every joystick with this pad + for(int i = 0; i < (int)s_vjoysticks.size(); ++i) { + if( s_vjoysticks[i]->GetPAD() == s_selectedpad ) + s_vjoysticks[i]->Assign(-1); + } + + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) + s_vjoysticks[joyid]->Assign(s_selectedpad); +} + +void on_checkbutton_reverselx_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTLX<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_checkbutton_reversely_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTLY<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_checkbutton_reverserx_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTRX<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_checkbutton_reversery_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTRY<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) conf.options |= mask; + else conf.options &= ~mask; +} + +void on_forcefeedback_toggled(GtkToggleButton *togglebutton, gpointer user_data) +{ + int mask = PADOPTION_REVERTLX<<(16*s_selectedpad); + if( gtk_toggle_button_get_active(togglebutton) ) { + conf.options |= mask; + + int joyid = gtk_combo_box_get_active(GTK_COMBO_BOX(s_devicecombo)); + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) + s_vjoysticks[joyid]->TestForce(); + } + else conf.options &= ~mask; +} + +GtkWidget *About = NULL; + +void OnAbout_Ok(GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(About); + gtk_main_quit(); +} + +void CALLBACK PADabout() { + + About = create_About(); + + gtk_widget_show_all(About); + gtk_main(); +} + +s32 CALLBACK PADtest() { + return 0; +} + +////////////////////////// +// Joystick definitions // +////////////////////////// + +// opens handles to all possible joysticks +void JoystickInfo::EnumerateJoysticks(vector& vjoysticks) +{ +#ifdef JOYSTICK_SUPPORT + + if( !s_bSDLInit ) { + if( SDL_Init(SDL_INIT_JOYSTICK) < 0 ) + return; + SDL_JoystickEventState(SDL_QUERY); + s_bSDLInit = true; + } + + vector::iterator it; + FORIT(it, vjoysticks) delete *it; + + vjoysticks.resize(SDL_NumJoysticks()); + for(int i = 0; i < (int)vjoysticks.size(); ++i) { + vjoysticks[i] = new JoystickInfo(); + vjoysticks[i]->Init(i, true); + } + + // set the pads + for(int pad = 0; pad < 2; ++pad) { + // select the right joystick id + int joyid = -1; + for(int i = 0; i < PADKEYS; ++i) { + if( IS_JOYSTICK(conf.keys[pad][i]) || IS_JOYBUTTONS(conf.keys[pad][i]) ) { + joyid = PAD_GETJOYID(conf.keys[pad][i]); + break; + } + } + + if( joyid >= 0 && joyid < (int)s_vjoysticks.size() ) + s_vjoysticks[joyid]->Assign(pad); + } + +#endif +} + +JoystickInfo::JoystickInfo() +{ +#ifdef JOYSTICK_SUPPORT + joy = NULL; +#endif + _id = -1; + pad = -1; + axisrange = 0x7fff; + deadzone = 2000; +} + +void JoystickInfo::Destroy() +{ +#ifdef JOYSTICK_SUPPORT + if( joy != NULL ) { + if( SDL_JoystickOpened(_id) ) + SDL_JoystickClose(joy); + joy = NULL; + } +#endif +} + +bool JoystickInfo::Init(int id, bool bStartThread) +{ +#ifdef JOYSTICK_SUPPORT + Destroy(); + _id = id; + + joy = SDL_JoystickOpen(id); + if( joy == NULL ) { + printf("failed to open joystick %d\n", id); + return false; + } + + numaxes = SDL_JoystickNumAxes(joy); + numbuttons = SDL_JoystickNumButtons(joy); + numpov = SDL_JoystickNumHats(joy); + devname = SDL_JoystickName(id); + vbutstate.resize(numbuttons); + vaxisstate.resize(numbuttons); + + return true; +#else + return false; +#endif +} + +// assigns a joystick to a pad +void JoystickInfo::Assign(int newpad) +{ + if( pad == newpad ) + return; + + pad = newpad; + + if( pad >= 0 ) { + for(int i = 0; i < PADKEYS; ++i) { + if( IS_JOYBUTTONS(conf.keys[pad][i]) ) { + conf.keys[pad][i] = PAD_JOYBUTTON(_id, PAD_GETJOYBUTTON(conf.keys[pad][i])); + } + else if( IS_JOYSTICK(conf.keys[pad][i]) ) { + conf.keys[pad][i] = PAD_JOYSTICK(_id, PAD_GETJOYBUTTON(conf.keys[pad][i])); + } + } + } +} + +void JoystickInfo::SaveState() +{ +#ifdef JOYSTICK_SUPPORT + for(int i = 0; i < numbuttons; ++i) + vbutstate[i] = SDL_JoystickGetButton(joy, i); + for(int i = 0; i < numaxes; ++i) + vaxisstate[i] = SDL_JoystickGetAxis(joy, i); +#endif +} + +void JoystickInfo::TestForce() +{ +} diff --git a/plugins/zeropad/Linux/support.c b/plugins/zeropad/Linux/support.c new file mode 100644 index 0000000000..00aff29822 --- /dev/null +++ b/plugins/zeropad/Linux/support.c @@ -0,0 +1,144 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "support.h" + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (!parent) + parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to find pixmap files. */ +static gchar* +find_pixmap_file (const gchar *filename) +{ + GList *elem; + + /* We step through each of the pixmaps directory to find it. */ + elem = pixmaps_directories; + while (elem) + { + gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, + G_DIR_SEPARATOR_S, filename); + if (g_file_test (pathname, G_FILE_TEST_EXISTS)) + return pathname; + g_free (pathname); + elem = elem->next; + } + return NULL; +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *pathname = NULL; + GtkWidget *pixmap; + + if (!filename || !filename[0]) + return gtk_image_new (); + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return gtk_image_new (); + } + + pixmap = gtk_image_new_from_file (pathname); + g_free (pathname); + return pixmap; +} + +/* This is an internally used function to create pixmaps. */ +GdkPixbuf* +create_pixbuf (const gchar *filename) +{ + gchar *pathname = NULL; + GdkPixbuf *pixbuf; + GError *error = NULL; + + if (!filename || !filename[0]) + return NULL; + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return NULL; + } + + pixbuf = gdk_pixbuf_new_from_file (pathname, &error); + if (!pixbuf) + { + fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", + pathname, error->message); + g_error_free (error); + } + g_free (pathname); + return pixbuf; +} + +/* This is used to set ATK action descriptions. */ +void +glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description) +{ + gint n_actions, i; + + n_actions = atk_action_get_n_actions (action); + for (i = 0; i < n_actions; i++) + { + if (!strcmp (atk_action_get_name (action, i), action_name)) + atk_action_set_description (action, i, description); + } +} + diff --git a/plugins/zeropad/Linux/support.h b/plugins/zeropad/Linux/support.h new file mode 100644 index 0000000000..a32649e53c --- /dev/null +++ b/plugins/zeropad/Linux/support.h @@ -0,0 +1,69 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# define Q_(String) g_strip_context ((String), gettext (String)) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define Q_(String) g_strip_context ((String), (String)) +# define N_(String) (String) +#endif + + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps used in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + +/* This is used to create the pixbufs used in the interface. */ +GdkPixbuf* create_pixbuf (const gchar *filename); + +/* This is used to set ATK action descriptions. */ +void glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description); + diff --git a/plugins/zeropad/Linux/zeropad.glade b/plugins/zeropad/Linux/zeropad.glade new file mode 100644 index 0000000000..08c54d6205 --- /dev/null +++ b/plugins/zeropad/Linux/zeropad.glade @@ -0,0 +1,1194 @@ + + + + + + + True + False + ZeroPAD + False + Author: zerofrog(@gmail.com) +Thanks to: + linuzappz <linuzappz@hotmail.com> +florin sasu <florinsasu@hotmail.com> +and SSSPSXPad, TwinPad authors + translator-credits + + + + True + ZeroPAD Configuration Dialog + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + False + 0 + + + + True + 0 + 0.5 + GTK_SHADOW_ETCHED_IN + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + False + 0 + + + + True + True + PAD1 + True + GTK_RELIEF_NORMAL + True + True + False + True + + + + 0 + False + False + + + + + + True + True + PAD2 + True + GTK_RELIEF_NORMAL + True + False + False + True + PAD1 + + + + 0 + False + False + + + + + + + + + + True + <b>Choose PAD to modify</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + label_item + + + + + 0 + False + False + + + + + + True + False + 0 + + + + True + Joystick to use for this PAD + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + + False + True + True + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 64 + 40 + + + + + + 64 + 24 + True + True + True + True + 0 + + True + • + False + + + 64 + 104 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 168 + 64 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 280 + 64 + + + + + + 64 + 24 + True + True + True + True + 0 + + True + • + False + + + 64 + 168 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 128 + 208 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 0 + 208 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 64 + 256 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 368 + 32 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 368 + 104 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 224 + 128 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 304 + 208 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 368 + 168 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 432 + 208 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 368 + 256 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 272 + 272 + + + + + + 64 + 24 + True + True + False + True + 0 + + True + • + False + + + 176 + 272 + + + + + + 80 + 24 + True + True + False + True + 0 + + True + • + False + + + 272 + 352 + + + + + + 80 + 24 + True + True + False + True + 0 + + True + • + False + + + 160 + 352 + + + + + + 80 + 24 + True + True + False + True + 0 + + True + • + False + + + 272 + 416 + + + + + + 80 + 24 + True + True + False + True + 0 + + True + • + False + + + 160 + 416 + + + + + + 64 + 32 + True + True + Select + True + GTK_RELIEF_NORMAL + True + + + + 168 + 32 + + + + + + 64 + 32 + True + True + L1 + True + GTK_RELIEF_NORMAL + True + + + + 64 + 72 + + + + + + 64 + 32 + True + True + Left + True + GTK_RELIEF_NORMAL + True + + + + 0 + 176 + + + + + + 64 + 32 + True + True + Down + True + GTK_RELIEF_NORMAL + True + + + + 64 + 224 + + + + + + 64 + 32 + True + True + Analog + True + GTK_RELIEF_NORMAL + True + + + + 224 + 96 + + + + + + 64 + 32 + True + True + R2 + True + GTK_RELIEF_NORMAL + True + + + + 368 + 0 + + + + + + 64 + 32 + True + True + Start + True + GTK_RELIEF_NORMAL + True + + + + 280 + 32 + + + + + + 64 + 32 + True + True + R1 + True + GTK_RELIEF_NORMAL + True + + + + 368 + 72 + + + + + + 64 + 32 + True + True + Cross + True + GTK_RELIEF_NORMAL + True + + + + 368 + 224 + + + + + + 64 + 32 + True + True + Triangle + True + GTK_RELIEF_NORMAL + True + + + + 368 + 136 + + + + + + 64 + 32 + True + True + Circle + True + GTK_RELIEF_NORMAL + True + + + + 432 + 176 + + + + + + 64 + 32 + True + True + Square + True + GTK_RELIEF_NORMAL + True + + + + 304 + 176 + + + + + + 64 + 32 + True + True + L3 + True + GTK_RELIEF_NORMAL + True + + + + 176 + 240 + + + + + + 64 + 32 + True + True + Up + True + GTK_RELIEF_NORMAL + True + + + + 64 + 136 + + + + + + 64 + 32 + True + True + L2 + True + GTK_RELIEF_NORMAL + True + + + + 64 + 8 + + + + + + 80 + 32 + True + True + Lx + True + GTK_RELIEF_NORMAL + True + + + + 160 + 320 + + + + + + 80 + 32 + True + True + Ly + True + GTK_RELIEF_NORMAL + True + + + + 160 + 384 + + + + + + 80 + 32 + True + True + Rx + True + GTK_RELIEF_NORMAL + True + + + + 272 + 320 + + + + + + 80 + 32 + True + True + Ry + True + GTK_RELIEF_NORMAL + True + + + + 272 + 384 + + + + + + 64 + 32 + True + True + Right + True + GTK_RELIEF_NORMAL + True + + + + 128 + 176 + + + + + + 408 + 16 + True + Analog Controls (move mouse or analog joystick to select) + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + True + 0 + + + 48 + 296 + + + + + + 64 + 32 + True + True + R3 + True + GTK_RELIEF_NORMAL + True + + + + 272 + 240 + + + + + + 111 + 22 + True + True + Reverse LX + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 16 + 328 + + + + + + 111 + 22 + True + True + Reverse LY + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 16 + 352 + + + + + + 111 + 22 + True + True + Reverse RX + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 16 + 376 + + + + + + 111 + 22 + True + True + Reverse RY + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 16 + 400 + + + + + + 112 + 48 + True + True + Enable Force +Feedback + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 384 + 320 + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + diff --git a/plugins/zeropad/Makefile.am b/plugins/zeropad/Makefile.am new file mode 100644 index 0000000000..bb6b8d1c1f --- /dev/null +++ b/plugins/zeropad/Makefile.am @@ -0,0 +1,30 @@ +# Create a shared library libZeroPAD +AUTOMAKE_OPTIONS = foreign +noinst_LIBRARIES = libZeroPAD.a +INCLUDES = -I@srcdir@/common + +libZeroPAD_a_CXXFLAGS = $(shell pkg-config --cflags gtk+-2.0) +libZeroPAD_a_CFLAGS = $(shell pkg-config --cflags gtk+-2.0) + +if X86_64 +libZeroPAD_a_CXXFLAGS += -fPIC +libZeroPAD_a_CFLAGS += -fPIC +endif + +# Create a shared object by faking an exe (thanks to ODE makefiles) +traplibdir=$(prefix) + +if DEBUGBUILD +preext=d +endif + +EXEEXT=$(preext)@so_ext@ + +traplib_PROGRAMS=libZeroPAD +libZeroPAD_SOURCES= +libZeroPAD_DEPENDENCIES = libZeroPAD.a +libZeroPAD_LDFLAGS= @SHARED_LDFLAGS@ +libZeroPAD_LDFLAGS+=-Wl,-soname,@ZEROPAD_SONAME@ +libZeroPAD_LDADD=$(libZeroPAD_a_OBJECTS) + +libZeroPAD_a_SOURCES = zeropad.cpp Linux/linux.cpp Linux/support.c Linux/interface.c diff --git a/plugins/zeropad/Windows/ZeroPAD.def b/plugins/zeropad/Windows/ZeroPAD.def new file mode 100644 index 0000000000..b7428bf63f --- /dev/null +++ b/plugins/zeropad/Windows/ZeroPAD.def @@ -0,0 +1,18 @@ +LIBRARY "ZeroPAD" + +EXPORTS + PS2EgetLibType @1 + PS2EgetLibName @2 + PS2EgetLibVersion2 @3 + PADinit @7 + PADshutdown @8 + PADopen @9 + PADclose @10 + PADkeyEvent @11 + PADstartPoll @12 + PADpoll @13 + PADquery @16 + PADconfigure @17 + PADtest @18 + PADabout @19 + PADupdate @20 \ No newline at end of file diff --git a/plugins/zeropad/Windows/ZeroPAD.rc b/plugins/zeropad/Windows/ZeroPAD.rc new file mode 100644 index 0000000000..65146382bc --- /dev/null +++ b/plugins/zeropad/Windows/ZeroPAD.rc @@ -0,0 +1,136 @@ +// 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 + +///////////////////////////////////////////////////////////////////////////// +// Neutral (Sys. Default) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOGEX 3, 1, 443, 266 +STYLE DS_SETFONT | WS_CAPTION | WS_SYSMENU +CAPTION "Pad Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + PUSHBUTTON "OK",IDOK,320,244,56,18,NOT WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,384,244,56,17,NOT WS_TABSTOP + EDITTEXT IDC_ERIGHT,219,31,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP,WS_EX_TRANSPARENT + PUSHBUTTON "Start",IDC_START,219,17,86,15,NOT WS_TABSTOP,WS_EX_TRANSPARENT + EDITTEXT IDC_ER2,129,31,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP,WS_EX_TRANSPARENT + PUSHBUTTON "Select",IDC_SELECT,129,17,86,15,NOT WS_TABSTOP,WS_EX_TRANSPARENT + EDITTEXT IDC_ECIRCLE,340,214,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Cross",IDC2_CROSS,340,199,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ETRIANGLE,340,185,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Square",IDC_SQUARE,340,170,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ESQUARE,340,155,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Circle",IDC_CIRCLE,340,140,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ECROSS,340,125,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Triangle",IDC_TRI,340,111,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ER3,340,96,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "R2",IDC_R2,340,81,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ESELECT,340,67,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "R1",IDC_R1,340,52,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EL2,5,214,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Down",IDC_DOWN,5,199,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EUP,5,185,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Right",IDC_RIGHT,5,170,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EL1,5,155,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Left",IDC_LEFT,5,140,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ELEFT,5,125,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "Up",IDC_UP,5,111,86,15,NOT WS_TABSTOP + EDITTEXT IDC_EL3,5,96,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "L2",IDC_L2,5,81,86,15,NOT WS_TABSTOP + EDITTEXT IDC_ESTART,5,67,86,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "L1",IDC_L1,5,52,86,15,NOT WS_TABSTOP + CONTROL 112,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,94,47,242,183,WS_EX_TRANSPARENT + CONTROL "Tab1",IDC_TABC,"SysTabControl32",0x0,0,0,431,240 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + BOTTOMMARGIN, 265 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Neutral (Sys. Default) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Spanish resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESN) +#ifdef _WIN32 +LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_MODERN +#pragma code_page(1252) +#endif //_WIN32 + +#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 + +#endif // Spanish resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/zeropad/Windows/ZeroPAD_2008.vcproj b/plugins/zeropad/Windows/ZeroPAD_2008.vcproj new file mode 100644 index 0000000000..52c83cee96 --- /dev/null +++ b/plugins/zeropad/Windows/ZeroPAD_2008.vcproj @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/zeropad/Windows/libs/pthread.h b/plugins/zeropad/Windows/libs/pthread.h new file mode 100644 index 0000000000..a0add29f5c --- /dev/null +++ b/plugins/zeropad/Windows/libs/pthread.h @@ -0,0 +1,1368 @@ +/* This is an implementation of the threads API of POSIX 1003.1-2001. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined( PTHREAD_H ) +#define PTHREAD_H + +/* + * See the README file for an explanation of the pthreads-win32 version + * numbering scheme and how the DLL is named etc. + */ +#define PTW32_VERSION 2,7,0,0 +#define PTW32_VERSION_STRING "2, 7, 0, 0\0" + +/* There are three implementations of cancel cleanup. + * Note that pthread.h is included in both application + * compilation units and also internally for the library. + * The code here and within the library aims to work + * for all reasonable combinations of environments. + * + * The three implementations are: + * + * WIN32 SEH + * C + * C++ + * + * Please note that exiting a push/pop block via + * "return", "exit", "break", or "continue" will + * lead to different behaviour amongst applications + * depending upon whether the library was built + * using SEH, C++, or C. For example, a library built + * with SEH will call the cleanup routine, while both + * C++ and C built versions will not. + */ + +/* + * Define defaults for cleanup code. + * Note: Unless the build explicitly defines one of the following, then + * we default to standard C style cleanup. This style uses setjmp/longjmp + * in the cancelation and thread exit implementations and therefore won't + * do stack unwinding if linked to applications that have it (e.g. + * C++ apps). This is currently consistent with most/all commercial Unix + * POSIX threads implementations. + */ +#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) +# define __CLEANUP_C +#endif + +#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) +#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. +#endif + +/* + * Stop here if we are being included by the resource compiler. + */ +#ifndef RC_INVOKED + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#ifdef _UWIN +# define HAVE_STRUCT_TIMESPEC 1 +# define HAVE_SIGNAL_H 1 +# undef HAVE_CONFIG_H +# pragma comment(lib, "pthread") +#endif + +/* + * ------------------------------------------------------------- + * + * + * Module: pthread.h + * + * Purpose: + * Provides an implementation of PThreads based upon the + * standard: + * + * POSIX 1003.1-2001 + * and + * The Single Unix Specification version 3 + * + * (these two are equivalent) + * + * in order to enhance code portability between Windows, + * various commercial Unix implementations, and Linux. + * + * See the ANNOUNCE file for a full list of conforming + * routines and defined constants, and a list of missing + * routines and constants not defined in this implementation. + * + * Authors: + * There have been many contributors to this library. + * The initial implementation was contributed by + * John Bossom, and several others have provided major + * sections or revisions of parts of the implementation. + * Often significant effort has been contributed to + * find and fix important bugs and other problems to + * improve the reliability of the library, which sometimes + * is not reflected in the amount of code which changed as + * result. + * As much as possible, the contributors are acknowledged + * in the ChangeLog file in the source code distribution + * where their changes are noted in detail. + * + * Contributors are listed in the CONTRIBUTORS file. + * + * As usual, all bouquets go to the contributors, and all + * brickbats go to the project maintainer. + * + * Maintainer: + * The code base for this project is coordinated and + * eventually pre-tested, packaged, and made available by + * + * Ross Johnson + * + * QA Testers: + * Ultimately, the library is tested in the real world by + * a host of competent and demanding scientists and + * engineers who report bugs and/or provide solutions + * which are then fixed or incorporated into subsequent + * versions of the library. Each time a bug is fixed, a + * test case is written to prove the fix and ensure + * that later changes to the code don't reintroduce the + * same error. The number of test cases is slowly growing + * and therefore so is the code reliability. + * + * Compliance: + * See the file ANNOUNCE for the list of implemented + * and not-implemented routines and defined options. + * Of course, these are all defined is this file as well. + * + * Web site: + * The source code and other information about this library + * are available from + * + * http://sources.redhat.com/pthreads-win32/ + * + * ------------------------------------------------------------- + */ + +/* Try to avoid including windows.h */ +#if defined(__MINGW32__) && defined(__cplusplus) +#define PTW32_INCLUDE_WINDOWS_H +#endif + +#ifdef PTW32_INCLUDE_WINDOWS_H +#include +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) +/* + * VC++6.0 or early compiler's header has no DWORD_PTR type. + */ +typedef unsigned long DWORD_PTR; +#endif +/* + * ----------------- + * autoconf switches + * ----------------- + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#ifndef NEED_FTIME +#include +#else /* NEED_FTIME */ +/* use native WIN32 time API */ +#endif /* NEED_FTIME */ + +#if HAVE_SIGNAL_H +#include +#endif /* HAVE_SIGNAL_H */ + +#include +#include + +/* + * Boolean values to make us independent of system includes. + */ +enum { + PTW32_FALSE = 0, + PTW32_TRUE = (! PTW32_FALSE) +}; + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Several systems don't define some error numbers. + */ +#ifndef ENOTSUP +# define ENOTSUP 48 /* This is the value in Solaris. */ +#endif + +#ifndef ETIMEDOUT +# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ +#endif + +#ifndef ENOSYS +# define ENOSYS 140 /* Semi-arbitrary value */ +#endif + +#ifndef EDEADLK +# ifdef EDEADLOCK +# define EDEADLK EDEADLOCK +# else +# define EDEADLK 36 /* This is the value in MSVC. */ +# endif +#endif + +#include + +/* + * To avoid including windows.h we define only those things that we + * actually need from it. + */ +#ifndef PTW32_INCLUDE_WINDOWS_H +#ifndef HANDLE +# define PTW32__HANDLE_DEF +# define HANDLE void * +#endif +#ifndef DWORD +# define PTW32__DWORD_DEF +# define DWORD unsigned long +#endif +#endif + +#ifndef HAVE_STRUCT_TIMESPEC +#define HAVE_STRUCT_TIMESPEC 1 +struct timespec { + long tv_sec; + long tv_nsec; +}; +#endif /* HAVE_STRUCT_TIMESPEC */ + +#ifndef SIG_BLOCK +#define SIG_BLOCK 0 +#endif /* SIG_BLOCK */ + +#ifndef SIG_UNBLOCK +#define SIG_UNBLOCK 1 +#endif /* SIG_UNBLOCK */ + +#ifndef SIG_SETMASK +#define SIG_SETMASK 2 +#endif /* SIG_SETMASK */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * ------------------------------------------------------------- + * + * POSIX 1003.1-2001 Options + * ========================= + * + * Options are normally set in , which is not provided + * with pthreads-win32. + * + * For conformance with the Single Unix Specification (version 3), all of the + * options below are defined, and have a value of either -1 (not supported) + * or 200112L (supported). + * + * These options can neither be left undefined nor have a value of 0, because + * either indicates that sysconf(), which is not implemented, may be used at + * runtime to check the status of the option. + * + * _POSIX_THREADS (== 200112L) + * If == 200112L, you can use threads + * + * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) + * If == 200112L, you can control the size of a thread's + * stack + * pthread_attr_getstacksize + * pthread_attr_setstacksize + * + * _POSIX_THREAD_ATTR_STACKADDR (== -1) + * If == 200112L, you can allocate and control a thread's + * stack. If not supported, the following functions + * will return ENOSYS, indicating they are not + * supported: + * pthread_attr_getstackaddr + * pthread_attr_setstackaddr + * + * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) + * If == 200112L, you can use realtime scheduling. + * This option indicates that the behaviour of some + * implemented functions conforms to the additional TPS + * requirements in the standard. E.g. rwlocks favour + * writers over readers when threads have equal priority. + * + * _POSIX_THREAD_PRIO_INHERIT (== -1) + * If == 200112L, you can create priority inheritance + * mutexes. + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PRIO_PROTECT (== -1) + * If == 200112L, you can create priority ceiling mutexes + * Indicates the availability of: + * pthread_mutex_getprioceiling + * pthread_mutex_setprioceiling + * pthread_mutexattr_getprioceiling + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprioceiling + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PROCESS_SHARED (== -1) + * If set, you can create mutexes and condition + * variables that can be shared with another + * process.If set, indicates the availability + * of: + * pthread_mutexattr_getpshared + * pthread_mutexattr_setpshared + * pthread_condattr_getpshared + * pthread_condattr_setpshared + * + * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) + * If == 200112L you can use the special *_r library + * functions that provide thread-safe behaviour + * + * _POSIX_READER_WRITER_LOCKS (== 200112L) + * If == 200112L, you can use read/write locks + * + * _POSIX_SPIN_LOCKS (== 200112L) + * If == 200112L, you can use spin locks + * + * _POSIX_BARRIERS (== 200112L) + * If == 200112L, you can use barriers + * + * + These functions provide both 'inherit' and/or + * 'protect' protocol, based upon these macro + * settings. + * + * ------------------------------------------------------------- + */ + +/* + * POSIX Options + */ +#undef _POSIX_THREADS +#define _POSIX_THREADS 200112L + +#undef _POSIX_READER_WRITER_LOCKS +#define _POSIX_READER_WRITER_LOCKS 200112L + +#undef _POSIX_SPIN_LOCKS +#define _POSIX_SPIN_LOCKS 200112L + +#undef _POSIX_BARRIERS +#define _POSIX_BARRIERS 200112L + +#undef _POSIX_THREAD_SAFE_FUNCTIONS +#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L + +#undef _POSIX_THREAD_ATTR_STACKSIZE +#define _POSIX_THREAD_ATTR_STACKSIZE 200112L + +/* + * The following options are not supported + */ +#undef _POSIX_THREAD_ATTR_STACKADDR +#define _POSIX_THREAD_ATTR_STACKADDR -1 + +#undef _POSIX_THREAD_PRIO_INHERIT +#define _POSIX_THREAD_PRIO_INHERIT -1 + +#undef _POSIX_THREAD_PRIO_PROTECT +#define _POSIX_THREAD_PRIO_PROTECT -1 + +/* TPS is not fully supported. */ +#undef _POSIX_THREAD_PRIORITY_SCHEDULING +#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 + +#undef _POSIX_THREAD_PROCESS_SHARED +#define _POSIX_THREAD_PROCESS_SHARED -1 + + +/* + * POSIX 1003.1-2001 Limits + * =========================== + * + * These limits are normally set in , which is not provided with + * pthreads-win32. + * + * PTHREAD_DESTRUCTOR_ITERATIONS + * Maximum number of attempts to destroy + * a thread's thread-specific data on + * termination (must be at least 4) + * + * PTHREAD_KEYS_MAX + * Maximum number of thread-specific data keys + * available per process (must be at least 128) + * + * PTHREAD_STACK_MIN + * Minimum supported stack size for a thread + * + * PTHREAD_THREADS_MAX + * Maximum number of threads supported per + * process (must be at least 64). + * + * SEM_NSEMS_MAX + * The maximum number of semaphores a process can have. + * (must be at least 256) + * + * SEM_VALUE_MAX + * The maximum value a semaphore can have. + * (must be at least 32767) + * + */ +#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 + +#undef PTHREAD_DESTRUCTOR_ITERATIONS +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +#undef _POSIX_THREAD_KEYS_MAX +#define _POSIX_THREAD_KEYS_MAX 128 + +#undef PTHREAD_KEYS_MAX +#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX + +#undef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 0 + +#undef _POSIX_THREAD_THREADS_MAX +#define _POSIX_THREAD_THREADS_MAX 64 + + /* Arbitrary value */ +#undef PTHREAD_THREADS_MAX +#define PTHREAD_THREADS_MAX 2019 + +#undef _POSIX_SEM_NSEMS_MAX +#define _POSIX_SEM_NSEMS_MAX 256 + + /* Arbitrary value */ +#undef SEM_NSEMS_MAX +#define SEM_NSEMS_MAX 1024 + +#undef _POSIX_SEM_VALUE_MAX +#define _POSIX_SEM_VALUE_MAX 32767 + +#undef SEM_VALUE_MAX +#define SEM_VALUE_MAX INT_MAX + + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * The Open Watcom C/C++ compiler uses a non-standard calling convention + * that passes function args in registers unless __cdecl is explicitly specified + * in exposed function prototypes. + * + * We force all calls to cdecl even though this could slow Watcom code down + * slightly. If you know that the Watcom compiler will be used to build both + * the DLL and application, then you can probably define this as a null string. + * Remember that pthread.h (this file) is used for both the DLL and application builds. + */ +#define PTW32_CDECL __cdecl + +#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX +# include +#else +/* + * Generic handle type - intended to extend uniqueness beyond + * that available with a simple pointer. It should scale for either + * IA-32 or IA-64. + */ +typedef struct { + void * p; /* Pointer to actual object */ + unsigned int x; /* Extra information - reuse count etc */ +} ptw32_handle_t; + +typedef ptw32_handle_t pthread_t; +typedef struct pthread_attr_t_ * pthread_attr_t; +typedef struct pthread_once_t_ pthread_once_t; +typedef struct pthread_key_t_ * pthread_key_t; +typedef struct pthread_mutex_t_ * pthread_mutex_t; +typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; +typedef struct pthread_cond_t_ * pthread_cond_t; +typedef struct pthread_condattr_t_ * pthread_condattr_t; +#endif +typedef struct pthread_rwlock_t_ * pthread_rwlock_t; +typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; +typedef struct pthread_spinlock_t_ * pthread_spinlock_t; +typedef struct pthread_barrier_t_ * pthread_barrier_t; +typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; + +/* + * ==================== + * ==================== + * POSIX Threads + * ==================== + * ==================== + */ + +enum { +/* + * pthread_attr_{get,set}detachstate + */ + PTHREAD_CREATE_JOINABLE = 0, /* Default */ + PTHREAD_CREATE_DETACHED = 1, + +/* + * pthread_attr_{get,set}inheritsched + */ + PTHREAD_INHERIT_SCHED = 0, + PTHREAD_EXPLICIT_SCHED = 1, /* Default */ + +/* + * pthread_{get,set}scope + */ + PTHREAD_SCOPE_PROCESS = 0, + PTHREAD_SCOPE_SYSTEM = 1, /* Default */ + +/* + * pthread_setcancelstate paramters + */ + PTHREAD_CANCEL_ENABLE = 0, /* Default */ + PTHREAD_CANCEL_DISABLE = 1, + +/* + * pthread_setcanceltype parameters + */ + PTHREAD_CANCEL_ASYNCHRONOUS = 0, + PTHREAD_CANCEL_DEFERRED = 1, /* Default */ + +/* + * pthread_mutexattr_{get,set}pshared + * pthread_condattr_{get,set}pshared + */ + PTHREAD_PROCESS_PRIVATE = 0, + PTHREAD_PROCESS_SHARED = 1, + +/* + * pthread_barrier_wait + */ + PTHREAD_BARRIER_SERIAL_THREAD = -1 +}; + +/* + * ==================== + * ==================== + * Cancelation + * ==================== + * ==================== + */ +#define PTHREAD_CANCELED ((void *) -1) + + +/* + * ==================== + * ==================== + * Once Key + * ==================== + * ==================== + */ +#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} + +struct pthread_once_t_ +{ + int done; /* indicates if user function has been executed */ + void * lock; + int reserved1; + int reserved2; +}; + + +/* + * ==================== + * ==================== + * Object initialisers + * ==================== + * ==================== + */ +#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1) +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t) -2) +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t) -3) + +/* + * Compatibility with LinuxThreads + */ +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER + +#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1) + +#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1) + +#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1) + + +/* + * Mutex types. + */ +enum +{ + /* Compatibility with LinuxThreads */ + PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, + /* For compatibility with POSIX */ + PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +}; + + +typedef struct ptw32_cleanup_t ptw32_cleanup_t; + +#if defined(_MSC_VER) +/* Disable MSVC 'anachronism used' warning */ +#pragma warning( disable : 4229 ) +#endif + +typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); + +#if defined(_MSC_VER) +#pragma warning( default : 4229 ) +#endif + +struct ptw32_cleanup_t +{ + ptw32_cleanup_callback_t routine; + void *arg; + struct ptw32_cleanup_t *prev; +}; + +#ifdef __CLEANUP_SEH + /* + * WIN32 SEH version of cancel cleanup. + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ + _cleanup.arg = (_arg); \ + __try \ + { \ + +#define pthread_cleanup_pop( _execute ) \ + } \ + __finally \ + { \ + if( _execute || AbnormalTermination()) \ + { \ + (*(_cleanup.routine))( _cleanup.arg ); \ + } \ + } \ + } + +#else /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_C + + /* + * C implementation of PThreads cancel cleanup + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ + +#define pthread_cleanup_pop( _execute ) \ + (void) ptw32_pop_cleanup( _execute ); \ + } + +#else /* __CLEANUP_C */ + +#ifdef __CLEANUP_CXX + + /* + * C++ version of cancel cleanup. + * - John E. Bossom. + */ + + class PThreadCleanup { + /* + * PThreadCleanup + * + * Purpose + * This class is a C++ helper class that is + * used to implement pthread_cleanup_push/ + * pthread_cleanup_pop. + * The destructor of this class automatically + * pops the pushed cleanup routine regardless + * of how the code exits the scope + * (i.e. such as by an exception) + */ + ptw32_cleanup_callback_t cleanUpRout; + void * obj; + int executeIt; + + public: + PThreadCleanup() : + cleanUpRout( 0 ), + obj( 0 ), + executeIt( 0 ) + /* + * No cleanup performed + */ + { + } + + PThreadCleanup( + ptw32_cleanup_callback_t routine, + void * arg ) : + cleanUpRout( routine ), + obj( arg ), + executeIt( 1 ) + /* + * Registers a cleanup routine for 'arg' + */ + { + } + + ~PThreadCleanup() + { + if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) + { + (void) (*cleanUpRout)( obj ); + } + } + + void execute( int exec ) + { + executeIt = exec; + } + }; + + /* + * C++ implementation of PThreads cancel cleanup; + * This implementation takes advantage of a helper + * class who's destructor automatically calls the + * cleanup routine if we exit our scope weirdly + */ +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ + (void *) (_arg) ); + +#define pthread_cleanup_pop( _execute ) \ + cleanup.execute( _execute ); \ + } + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ + +#endif /* __CLEANUP_C */ + +#endif /* __CLEANUP_SEH */ + +/* + * =============== + * =============== + * Methods + * =============== + * =============== + */ + +/* + * PThread Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, + int *detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, + void **stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, + size_t * stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, + int detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, + void *stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, + size_t stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (pthread_attr_t *, + int *); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, + int inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(pthread_attr_t * attr, + int * inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, + int *); + +/* + * PThread Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, + const pthread_attr_t * attr, + void *(*start) (void *), + void *arg); + +PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); + +PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, + pthread_t t2); + +PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); + +PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, + void **value_ptr); + +PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, + int *oldstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, + int *oldtype); + +PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, + void (*init_routine) (void)); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); + +PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, + void (*routine) (void *), + void *arg); +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread Specific Data Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, + void (*destructor) (void *)); + +PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); + +PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, + const void *value); + +PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); + + +/* + * Mutex Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, + int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind); + +/* + * Barrier Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, + int pshared); + +/* + * Mutex Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, + const pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t *mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); + +/* + * Spinlock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); + +/* + * Barrier Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, + unsigned int count); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); + +/* + * Condition Variable Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, + int pshared); + +/* + * Condition Variable Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, + const pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, + pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); + +/* + * Scheduling + */ +PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, + int policy, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, + int *policy, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); + +PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); + +/* + * Read-Write Lock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, + const pthread_rwlockattr_t *attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, + int pshared); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 + +/* + * Signal Functions. Should be defined in but MSVC and MinGW32 + * already have signal.h that don't define these. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); + +/* + * Non-portable functions + */ + +/* + * Compatibility with Linux. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, + int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, + int *kind); + +/* + * Possibly supported by other POSIX threads implementations + */ +PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); +PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); + +/* + * Useful if an application wants to statically link + * the lib rather than load the DLL at run-time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); + +/* + * Features that are auto-detected at load/run time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); +enum ptw32_features { + PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ + PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ +}; + +/* + * Register a system time change with the library. + * Causes the library to perform various functions + * in response to the change. Should be called whenever + * the application's top level window receives a + * WM_TIMECHANGE message. It can be passed directly to + * pthread_create() as a new thread if desired. + */ +PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); + +#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* + * Returns the Win32 HANDLE for the POSIX thread. + */ +PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); + + +/* + * Protected Methods + * + * This function blocks until the given WIN32 handle + * is signaled or pthread_cancel had been called. + * This function allows the caller to hook into the + * PThreads cancel mechanism. It is implemented using + * + * WaitForMultipleObjects + * + * on 'waitHandle' and a manually reset WIN32 Event + * used to implement pthread_cancel. The 'timeout' + * argument to TimedWait is simply passed to + * WaitForMultipleObjects. + */ +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, + DWORD timeout); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread-Safe C Runtime Library Mappings. + */ +#ifndef _UWIN +# if defined(NEED_ERRNO) + PTW32_DLLPORT int * PTW32_CDECL _errno( void ); +# else +# ifndef errno +# if (defined(_MT) || defined(_DLL)) + __declspec(dllimport) extern int * __cdecl _errno(void); +# define errno (*_errno()) +# endif +# endif +# endif +#endif + +/* + * WIN32 C runtime library had been made thread-safe + * without affecting the user interface. Provide + * mappings from the UNIX thread-safe versions to + * the standard C runtime library calls. + * Only provide function mappings for functions that + * actually exist on WIN32. + */ + +#if !defined(__MINGW32__) +#define strtok_r( _s, _sep, _lasts ) \ + ( *(_lasts) = strtok( (_s), (_sep) ) ) +#endif /* !__MINGW32__ */ + +#define asctime_r( _tm, _buf ) \ + ( strcpy( (_buf), asctime( (_tm) ) ), \ + (_buf) ) + +#define ctime_r( _clock, _buf ) \ + ( strcpy( (_buf), ctime( (_clock) ) ), \ + (_buf) ) + +#define gmtime_r( _clock, _result ) \ + ( *(_result) = *gmtime( (_clock) ), \ + (_result) ) + +#define localtime_r( _clock, _result ) \ + ( *(_result) = *localtime( (_clock) ), \ + (_result) ) + +#define rand_r( _seed ) \ + ( _seed == _seed? rand() : rand() ) + + +/* + * Some compiler environments don't define some things. + */ +#if defined(__BORLANDC__) +# define _ftime ftime +# define _timeb timeb +#endif + +#ifdef __cplusplus + +/* + * Internal exceptions + */ +class ptw32_exception {}; +class ptw32_exception_cancel : public ptw32_exception {}; +class ptw32_exception_exit : public ptw32_exception {}; + +#endif + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* FIXME: This is only required if the library was built using SEH */ +/* + * Get internal SEH tag + */ +PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#ifndef PTW32_BUILD + +#ifdef __CLEANUP_SEH + +/* + * Redefine the SEH __except keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#define __except( E ) \ + __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ + ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) + +#endif /* __CLEANUP_SEH */ + +#ifdef __CLEANUP_CXX + +/* + * Redefine the C++ catch keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#ifdef _MSC_VER + /* + * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' + * if you want Pthread-Win32 cancelation and pthread_exit to work. + */ + +#ifndef PtW32NoCatchWarn + +#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") +#pragma message("------------------------------------------------------------------") +#pragma message("When compiling applications with MSVC++ and C++ exception handling:") +#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") +#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") +#pragma message(" cancelation and pthread_exit to work. For example:") +#pragma message("") +#pragma message(" #ifdef PtW32CatchAll") +#pragma message(" PtW32CatchAll") +#pragma message(" #else") +#pragma message(" catch(...)") +#pragma message(" #endif") +#pragma message(" {") +#pragma message(" /* Catchall block processing */") +#pragma message(" }") +#pragma message("------------------------------------------------------------------") + +#endif + +#define PtW32CatchAll \ + catch( ptw32_exception & ) { throw; } \ + catch( ... ) + +#else /* _MSC_VER */ + +#define catch( E ) \ + catch( ptw32_exception & ) { throw; } \ + catch( E ) + +#endif /* _MSC_VER */ + +#endif /* __CLEANUP_CXX */ + +#endif /* ! PTW32_BUILD */ + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#ifdef PTW32__HANDLE_DEF +# undef HANDLE +#endif +#ifdef PTW32__DWORD_DEF +# undef DWORD +#endif + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* ! RC_INVOKED */ + +#endif /* PTHREAD_H */ diff --git a/plugins/zeropad/Windows/libs/pthreadVC2.lib b/plugins/zeropad/Windows/libs/pthreadVC2.lib new file mode 100644 index 0000000000000000000000000000000000000000..b447a8b71ec31903598669991dac05f24ace9f25 GIT binary patch literal 29280 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 literal 0 HcmV?d00001 diff --git a/plugins/zeropad/Windows/libs/sched.h b/plugins/zeropad/Windows/libs/sched.h new file mode 100644 index 0000000000..10ecb5d7ea --- /dev/null +++ b/plugins/zeropad/Windows/libs/sched.h @@ -0,0 +1,178 @@ +/* + * Module: sched.h + * + * Purpose: + * Provides an implementation of POSIX realtime extensions + * as defined in + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef _SCHED_H +#define _SCHED_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#if defined(__MINGW32__) || defined(_UWIN) +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +/* For pid_t */ +# include +/* Required by Unix 98 */ +# include +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ +#else +typedef int pid_t; +#endif + +/* Thread scheduling policies */ + +enum { + SCHED_OTHER = 0, + SCHED_FIFO, + SCHED_RR, + SCHED_MIN = SCHED_OTHER, + SCHED_MAX = SCHED_RR +}; + +struct sched_param { + int sched_priority; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PTW32_DLLPORT int __cdecl sched_yield (void); + +PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); + +PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); + +PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); + +PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); + +/* + * Note that this macro returns ENOTSUP rather than + * ENOSYS as might be expected. However, returning ENOSYS + * should mean that sched_get_priority_{min,max} are + * not implemented as well as sched_rr_get_interval. + * This is not the case, since we just don't support + * round-robin scheduling. Therefore I have chosen to + * return the same value as sched_setscheduler when + * SCHED_RR is passed to it. + */ +#define sched_rr_get_interval(_pid, _interval) \ + ( errno = ENOTSUP, (int) -1 ) + + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !_SCHED_H */ + diff --git a/plugins/zeropad/Windows/libs/semaphore.h b/plugins/zeropad/Windows/libs/semaphore.h new file mode 100644 index 0000000000..ea42ce3703 --- /dev/null +++ b/plugins/zeropad/Windows/libs/semaphore.h @@ -0,0 +1,166 @@ +/* + * Module: semaphore.h + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined( SEMAPHORE_H ) +#define SEMAPHORE_H + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#if __GNUC__ && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the DLL code, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the DLL, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#ifndef PTW32_STATIC_LIB +# ifdef PTW32_BUILD +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#ifdef NEED_ERRNO +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#define _POSIX_SEMAPHORES + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#ifndef HAVE_MODE_T +typedef unsigned int mode_t; +#endif + + +typedef struct sem_t_ * sem_t; + +PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, + int pshared, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, + const struct timespec * abstime); + +PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, + int count); + +PTW32_DLLPORT int __cdecl sem_open (const char * name, + int oflag, + mode_t mode, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_unlink (const char * name); + +PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, + int * sval); + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* !SEMAPHORE_H */ diff --git a/plugins/zeropad/Windows/resource.h b/plugins/zeropad/Windows/resource.h new file mode 100644 index 0000000000..eec9db5935 --- /dev/null +++ b/plugins/zeropad/Windows/resource.h @@ -0,0 +1,70 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ZeroPAD.rc +// +#define IDD_DIALOG1 110 +#define IDB_BITMAP1 112 +#define IDC_EL3 1012 +#define IDC_L2 1013 +#define IDC_ER3 1014 +#define IDC_R2 1015 +#define IDC_ESTART 1016 +#define IDC_L1 1017 +#define IDC_ESELECT 1018 +#define IDC_R1 1019 +#define IDC_ECROSS 1020 +#define IDC_TRI 1021 +#define IDC_ESQUARE 1022 +#define IDC_CIRCLE 1023 +#define IDC_ECIRCLE 1024 +#define IDC2_CROSS 1025 +#define IDC_ETRIANGLE 1026 +#define IDC_SQUARE 1027 +#define IDC_ER2 1028 +#define IDC_SELECT 1029 +#define IDC_ER1 1030 +#define IDC_L3 1031 +#define IDC_EDOWN 1032 +#define IDC_R3 1033 +#define IDC_ERIGHT 1034 +#define IDC_START 1035 +#define IDC_ELEFT 1036 +#define IDC_UP 1037 +#define IDC_EUP 1038 +#define IDC_RIGHT 1039 +#define IDC_EL2 1040 +#define IDC_DOWN 1041 +#define IDC_EL1 1042 +#define IDC_LEFT 1043 +#define IDC_TABC 1044 +#define IDC_LAX 1045 +#define IDC_LAY 1046 +#define IDC_RAX 1047 +#define IDC_RAY 1048 +#define IDC_SCROSS 1049 +#define IDC_CHECK1 1050 +#define IDC_LOG 1050 +#define IDC_SCIRCLE 1051 +#define IDC_SSQUARE 1052 +#define IDC_STRIANGLE 1053 +#define IDC_SL3 1054 +#define IDC_SUP 1055 +#define IDC_SDOWN 1056 +#define IDC_SLEFT 1057 +#define IDC_SRIGHT 1058 +#define IDC_SR3 1059 +#define IDC_SL1 1060 +#define IDC_SL2 1061 +#define IDC_SR1 1062 +#define IDC_SR2 1063 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 114 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1051 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/zeropad/Windows/vsprops/pcsx2_plugin_common.vsprops b/plugins/zeropad/Windows/vsprops/pcsx2_plugin_common.vsprops new file mode 100644 index 0000000000..086133a60a --- /dev/null +++ b/plugins/zeropad/Windows/vsprops/pcsx2_plugin_common.vsprops @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/plugins/zeropad/Windows/vsprops/postBuild.tmpl b/plugins/zeropad/Windows/vsprops/postBuild.tmpl new file mode 100644 index 0000000000..b0f9fb472f --- /dev/null +++ b/plugins/zeropad/Windows/vsprops/postBuild.tmpl @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%\%3-r$WCREV$$WCMODS?m:$%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/zeropad/Windows/vsprops/postBuild.unknown b/plugins/zeropad/Windows/vsprops/postBuild.unknown new file mode 100644 index 0000000000..360b05cad5 --- /dev/null +++ b/plugins/zeropad/Windows/vsprops/postBuild.unknown @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%%3%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/zeropad/Windows/vsprops/preBuild.cmd b/plugins/zeropad/Windows/vsprops/preBuild.cmd new file mode 100644 index 0000000000..fea16bd143 --- /dev/null +++ b/plugins/zeropad/Windows/vsprops/preBuild.cmd @@ -0,0 +1,20 @@ +@echo off + +rem Usage: preBuild.cmd ProjectSrcDir VspropsDir +rem +rem ProjectSrcDir - $(ProjectDir)\.. - Directory of project source code. +rem VspropsDir - $(PrjectDir)\vsprops - Directory of this script and its counterparts. + +SubWCRev.exe %1 %2\svnrev_template.h %1\svnrev.h +if not ERRORLEVEL 0 ( + echo Automatic revision update unavailable, using generic template instead. + echo You can safely ignore this message - see svnrev.h for details. + copy /Y %2\svnrev_unknown.h %1\svnrev.h + copy /Y %2\postBuild.unknown %2\postBuild.cmd +) else ( + SubWCRev.exe %1 %2\postBuild.tmpl %2\postBuild.cmd +) + +rem Clear the error level -- this allows compilation to continue if SubWCRev failed. + +set ERRORLEVEL=0 diff --git a/plugins/zeropad/Windows/vsprops/svnrev_template.h b/plugins/zeropad/Windows/vsprops/svnrev_template.h new file mode 100644 index 0000000000..afab6c4fd1 --- /dev/null +++ b/plugins/zeropad/Windows/vsprops/svnrev_template.h @@ -0,0 +1,18 @@ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ +#define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/zeropad/Windows/vsprops/svnrev_unknown.h b/plugins/zeropad/Windows/vsprops/svnrev_unknown.h new file mode 100644 index 0000000000..a2a3703186 --- /dev/null +++ b/plugins/zeropad/Windows/vsprops/svnrev_unknown.h @@ -0,0 +1,23 @@ +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 +#define SVN_MODS "" \ No newline at end of file diff --git a/plugins/zeropad/Windows/win.cpp b/plugins/zeropad/Windows/win.cpp new file mode 100644 index 0000000000..3c181cca72 --- /dev/null +++ b/plugins/zeropad/Windows/win.cpp @@ -0,0 +1,457 @@ +/* ZeroPAD - author: zerofrog(@gmail.com) + * Copyright (C) 2006-2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "resource.h" +#include "../zeropad.h" + +#include +#include + +using namespace std; + +HINSTANCE hInst=NULL; +static pthread_spinlock_t s_mutexStatus; +static u32 s_keyPress[2], s_keyRelease[2]; +extern u16 status[2]; + +extern string s_strIniPath; +LRESULT WINAPI PADwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +WNDPROC GSwndProc=NULL; +HWND GShwnd=NULL; + +extern keyEvent event; + + +void SaveConfig() +{ + char *szTemp; + char szIniFile[256], szValue[256], szProf[256]; + int i, j; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + strcpy(szTemp, "\\inis\\zeropad.ini"); + + for (j=0; j<2; j++) { + for (i=0; i=0x60 && key<=0x69) { + sprintf(buff, "NumPad %c", '0' + key - 0x60); + } + else sprintf(buff, "%c", key); + } + } + else if (key >= 0x1000 && key < 0x2000) + { + sprintf (buff, "J%d_%d", (key & 0xfff) / 0x100, (key & 0xff) + 1); + } + else if (key >= 0x2000 && key < 0x3000) + { + static const char name[][4] = { "MIN", "MAX" }; + const int axis = (key & 0xff); + sprintf (buff, "J%d_AXIS%d_%s", (key & 0xfff) / 0x100, axis / 2, name[axis % 2]); + if (index >= 17 && index <= 20) + buff[strlen (buff) -4] = '\0'; + } + else if (key >= 0x3000 && key < 0x4000) + { + static const char name[][7] = { "FOWARD", "RIGHT", "BACK", "LEFT" }; + const int pov = (key & 0xff); + sprintf (buff, "J%d_POV%d_%s", (key & 0xfff) / 0x100, pov /4, name[pov % 4]); + } + + return buff; +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { + HWND hWC; + TCITEM tcI; + int i,key, numkeys; + u8* pkeyboard; + static int disabled=0; + static int padn=0; + + switch(uMsg) { + case WM_INITDIALOG: + LoadConfig(); + padn = 0; + if (conf.log) CheckDlgButton(hW, IDC_LOG, TRUE); + + for (i=0; i. + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/zeropad/mkinstalldirs b/plugins/zeropad/mkinstalldirs new file mode 100644 index 0000000000..259dbfcd35 --- /dev/null +++ b/plugins/zeropad/mkinstalldirs @@ -0,0 +1,158 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2005-06-29.22 + +# Original author: Noah Friedman +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/zeropad/zeropad.cpp b/plugins/zeropad/zeropad.cpp new file mode 100644 index 0000000000..a5f9aabcfe --- /dev/null +++ b/plugins/zeropad/zeropad.cpp @@ -0,0 +1,528 @@ +/* ZeroPAD - author: zerofrog(@gmail.com) + * Copyright (C) 2006-2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include "zeropad.h" + +#include +#include +#include +#ifndef _WIN32 +#include +#else +#include "svnrev.h" +#endif + +char libraryName[256]; + +PADAnalog g_lanalog[2], g_ranalog[2]; +PADconf conf; + +keyEvent event; + +u16 status[2]; +int pressure; +string s_strIniPath="inis/zeropad.ini"; + +const unsigned char version = PS2E_PAD_VERSION; +const unsigned char revision = 0; +const unsigned char build = 2; // increase that with each version + + +u32 pads=0; +u8 stdpar[2][20] = { {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; +u8 cmd40[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}}; +u8 cmd41[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}}; +u8 unk46[2][8] = { {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}, + {0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}}; +u8 unk47[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}}; +u8 unk4c[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +u8 unk4d[2][8] = { {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; +u8 cmd4f[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}}; +u8 stdcfg[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // 2 & 3 = 0 +u8 stdmode[2][8] = { {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +u8 stdmodel[2][8] = { {0xff, 0x5a, + 0x03, // 03 - dualshock2, 01 - dualshock + 0x02, // number of modes + 0x01, // current mode: 01 - analog, 00 - digital + 0x02, + 0x01, + 0x00}, + {0xff, 0x5a, + 0x03, // 03 - dualshock2, 01 - dualshock + 0x02, // number of modes + 0x01, // current mode: 01 - analog, 00 - digital + 0x02, + 0x01, + 0x00}}; + +u8 *buf; +int padID[2]; +int padMode[2]; +int curPad; +int curByte; +int curCmd; +int cmdLen; +int ds2mode = 0; // DS Mode at start +FILE *padLog = NULL; + +int POV(u32 direction, u32 angle){ + if ((direction==0) && (angle>= 0) && (angle< 4500)) return 1;//forward + if ((direction==2) && (angle>= 4500) && (angle<13500)) return 1;//right + if ((direction==1) && (angle>=13500) && (angle<22500)) return 1;//backward + if ((direction==3) && (angle>=22500) && (angle<31500)) return 1;//left + if ((direction==0) && (angle>=31500) && (angle<36000)) return 1;//forward + return 0; +} + +void _KeyPress(int pad, u32 key) +{ + int i; + + for (i=0; i> 8; + stdpar[curPad][3] = status[curPad] & 0xff; + stdpar[curPad][4] = g_ranalog[curPad].x; + stdpar[curPad][5] = g_ranalog[curPad].y; + stdpar[curPad][6] = g_lanalog[curPad].x; + stdpar[curPad][7] = g_lanalog[curPad].y; + if (padMode[curPad] == 1) cmdLen = 20; + else cmdLen = 4; + button_check2 = stdpar[curPad][2] >> 4; + switch(stdpar[curPad][3]) + { + case 0xBF: // X + stdpar[curPad][14] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][16])); + break; + case 0xDF: // Circle + stdpar[curPad][13] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][17])); + break; + case 0xEF: // Triangle + stdpar[curPad][12] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][19])); + break; + case 0x7F: // Square + stdpar[curPad][15] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][18])); + break; + case 0xFB: // L1 + stdpar[curPad][16] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][26])); + break; + case 0xF7: // R1 + stdpar[curPad][17] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][28])); + break; + case 0xFE: // L2 + stdpar[curPad][18] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][27])); + break; + case 0xFD: // R2 + stdpar[curPad][19] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][29])); + break; + default: + stdpar[curPad][14] = 0x00; // Not pressed + stdpar[curPad][13] = 0x00; // Not pressed + stdpar[curPad][12] = 0x00; // Not pressed + stdpar[curPad][15] = 0x00; // Not pressed + stdpar[curPad][16] = 0x00; // Not pressed + stdpar[curPad][17] = 0x00; // Not pressed + stdpar[curPad][18] = 0x00; // Not pressed + stdpar[curPad][19] = 0x00; // Not pressed + break; + } + switch(button_check2) + { + case 0xE: // UP + stdpar[curPad][10] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][21])); + break; + case 0xB: // DOWN + stdpar[curPad][11] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][22])); + break; + case 0x7: // LEFT + stdpar[curPad][9] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][23])); + break; + case 0xD: // RIGHT + stdpar[curPad][8] = (pressure*255)/100; //0xff/(100/(100-conf.keys[curPad][24])); + break; + default: + stdpar[curPad][8] = 0x00; // Not pressed + stdpar[curPad][9] = 0x00; // Not pressed + stdpar[curPad][10] = 0x00; // Not pressed + stdpar[curPad][11] = 0x00; // Not pressed + break; + } + buf = stdpar[curPad]; + return padID[curPad]; + + case 0x43: // CONFIG_MODE + cmdLen = 8; + buf = stdcfg[curPad]; + if (stdcfg[curPad][3] == 0xff) return 0xf3; + else return padID[curPad]; + + case 0x44: // SET_MODE_AND_LOCK + cmdLen = 8; + buf = stdmode[curPad]; + return 0xf3; + + case 0x45: // QUERY_MODEL_AND_MODE + cmdLen = 8; + buf = stdmodel[curPad]; + buf[4] = padMode[curPad]; + return 0xf3; + + case 0x46: // ?? + cmdLen = 8; + buf = unk46[curPad]; + return 0xf3; + + case 0x47: // ?? + cmdLen = 8; + buf = unk47[curPad]; + return 0xf3; + + case 0x4c: // QUERY_MODE ?? + cmdLen = 8; + buf = unk4c[curPad]; + return 0xf3; + + case 0x4d: + cmdLen = 8; + buf = unk4d[curPad]; + return 0xf3; + + case 0x4f: // SET_DS2_NATIVE_MODE + cmdLen = 8; + padID[curPad] = 0x79; // setting ds2 mode + ds2mode = 1; // Set DS2 Mode + buf = cmd4f[curPad]; + return 0xf3; + + default: +#ifdef PAD_LOG + PAD_LOG("*PADpoll*: unknown cmd %x\n", value); +#endif + break; + } + } + + switch (curCmd) { + case 0x43: + if(curByte == 2) + { + switch(value){ + case 0: + buf[2] = 0; + buf[3] = 0; + break; + case 1: + buf[2] = 0xff; + buf[3] = 0xff; + break; + } + } + break; + + case 0x44: + if (curByte == 2) { + PADsetMode(curPad, value); + } + break; + + case 0x46: + if(curByte == 2) { + switch(value) { + case 0: // default + buf[5] = 0x2; + buf[6] = 0x0; + buf[7] = 0xA; + break; + case 1: // Param std conf change + buf[5] = 0x1; + buf[6] = 0x1; + buf[7] = 0x14; + break; + } + } + break; + + case 0x4c: + if (curByte == 2) { + switch (value) { + case 0: // mode 0 - digital mode + buf[5] = 0x4; + break; + + case 1: // mode 1 - analog mode + buf[5] = 0x7; + break; + } + } + break; + } + + if (curByte >= cmdLen) return 0; + return buf[curByte++]; +} + +u8 CALLBACK PADpoll(u8 value) +{ + u8 ret; + ret = _PADpoll(value); +#ifdef PAD_LOG + PAD_LOG("PADpoll: %x (%d: %x)\n", value, curByte, ret); +#endif + return ret; +} + +// PADkeyEvent is called every vsync (return NULL if no event) +static keyEvent s_event; +keyEvent* CALLBACK PADkeyEvent() +{ + s_event = event; + event.evt = 0; + return &s_event; +} diff --git a/plugins/zeropad/zeropad.h b/plugins/zeropad/zeropad.h new file mode 100644 index 0000000000..1cdea52a15 --- /dev/null +++ b/plugins/zeropad/zeropad.h @@ -0,0 +1,134 @@ +/* ZeroPAD - author: zerofrog(@gmail.com) + * Copyright (C) 2006-2007 + * + * 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 __PAD_H__ +#define __PAD_H__ + +#include +#include + +#ifdef _WIN32 +#include +#include + +#else + +#include +#include +#include + +#endif + +#include +#include +#include +using namespace std; + +#define PADdefs +extern "C" { +#include "PS2Edefs.h" +} + +extern char libraryName[256]; + +#define FORIT(it, v) for(it = (v).begin(); it != (v).end(); (it)++) + +#define IS_KEYBOARD(key) (key<0x10000) +#define IS_JOYBUTTONS(key) (key>=0x10000 && key<0x20000) // buttons +#define IS_JOYSTICK(key) (key>=0x20000&&key<0x30000) // analog +#define IS_POV(key) (key>=0x30000&&key<0x40000) // uses analog as buttons (cares about sign) +#define IS_MOUSE(key) (key>=0x40000&&key<0x50000) // mouse + +#define PAD_GETKEY(key) ((key)&0xffff) +#define PAD_GETJOYID(key) (((key)&0xf000)>>12) +#define PAD_GETJOYBUTTON(key) ((key)&0xff) +#define PAD_GETJOYSTICK_AXIS(key) ((key)&0xff) +#define PAD_JOYBUTTON(joyid, buttonid) (0x10000|((joyid)<<12)|(buttonid)) +#define PAD_JOYSTICK(joyid, axisid) (0x20000|((joyid)<<12)|(axisid)) +#define PAD_POV(joyid, sign, axisid) (0x30000|((joyid)<<12)|((sign)<<8)|(axisid)) +#define PAD_GETPOVSIGN(key) (((key)&0x100)>>8) + +#define PADKEYS 20 + +#define PADOPTION_FORCEFEEDBACK 1 +#define PADOPTION_REVERTLX 0x2 +#define PADOPTION_REVERTLY 0x4 +#define PADOPTION_REVERTRX 0x8 +#define PADOPTION_REVERTRY 0x10 + +typedef struct { + unsigned long keys[2][PADKEYS]; + int log; + int options; // upper 16 bits are for pad2 +} PADconf; + +typedef struct { + u8 x,y; +} PADAnalog; + +extern PADconf conf; + +extern PADAnalog g_lanalog[2], g_ranalog[2]; +extern FILE *padLog; +#define PAD_LOG __Log + +#define PAD_RY 19 +#define PAD_LY 18 +#define PAD_RX 17 +#define PAD_LX 16 +#define PAD_LEFT 15 +#define PAD_DOWN 14 +#define PAD_RIGHT 13 +#define PAD_UP 12 +#define PAD_START 11 +#define PAD_R3 10 +#define PAD_L3 9 +#define PAD_SELECT 8 +#define PAD_SQUARE 7 +#define PAD_CROSS 6 +#define PAD_CIRCLE 5 +#define PAD_TRIANGLE 4 +#define PAD_R1 3 +#define PAD_L1 2 +#define PAD_R2 1 +#define PAD_L2 0 + +/* end of pad.h */ + +extern keyEvent event; + +extern u16 status[2]; +extern u32 pads; + +int POV(u32 direction, u32 angle); +s32 _PADopen(void *pDsp); +void _PADclose(); +void _KeyPress(int pad, u32 key); +void _KeyRelease(int pad, u32 key); +void PADsetMode(int pad, int mode); +void _PADupdate(int pad); + +void __Log(char *fmt, ...); +void LoadConfig(); +void SaveConfig(); + +void SysMessage(char *fmt, ...); + +#endif + + diff --git a/plugins/zerospu2/3rdparty/SoundTouch/3dnow_win.cpp b/plugins/zerospu2/3rdparty/SoundTouch/3dnow_win.cpp new file mode 100644 index 0000000000..2e369904ec --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/3dnow_win.cpp @@ -0,0 +1,350 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the AMD 3DNow! optimized routines for AMD K6-2/Athlon +/// processors. All 3DNow! optimized functions have been gathered into this +/// single source code file, regardless to their class or original source code +/// file, in order to ease porting the library to other compiler and processor +/// platforms. +/// +/// By the way; the performance gain depends heavily on the CPU generation: On +/// K6-2 these routines provided speed-up of even 2.4 times, while on Athlon the +/// difference to the original routines stayed at unremarkable 8%! Such a small +/// improvement on Athlon is due to 3DNow can perform only two operations in +/// parallel, and obviously also the Athlon FPU is doing a very good job with +/// the standard C floating point routines! Here these routines are anyway, +/// although it might not be worth the effort to convert these to GCC platform, +/// for Athlon CPU at least. The situation is different regarding the SSE +/// optimizations though, thanks to the four parallel operations of SSE that +/// already make a difference. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see '3dnow_gcc.cpp' for the gcc compiler version for all +/// GNU platforms (if file supplied). +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support 3DNow! instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: 3dnow_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +#ifndef _WIN32 +#error "wrong platform - this source code file is exclusively for Win32 platform" +#endif + +using namespace soundtouch; + +#ifdef ALLOW_3DNOW +// 3DNow! routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'TDStretch3DNow' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// these are declared in 'TDStretch.cpp' +extern int scanOffsets[4][24]; + + +// Calculates cross correlation of two buffers +double TDStretch3DNow::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint overlapLengthLocal = overlapLength; + float corr; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + /* + c-pseudocode: + + corr = 0; + for (i = 0; i < overlapLength / 4; i ++) + { + corr += pV1[0] * pV2[0]; + pV1[1] * pV2[1]; + pV1[2] * pV2[2]; + pV1[3] * pV2[3]; + pV1[4] * pV2[4]; + pV1[5] * pV2[5]; + pV1[6] * pV2[6]; + pV1[7] * pV2[7]; + + pV1 += 8; + pV2 += 8; + } + */ + + _asm + { + // give prefetch hints to CPU of what data are to be needed soonish. + // give more aggressive hints on pV1 as that changes more between different calls + // while pV2 stays the same. + prefetch [pV1] + prefetch [pV2] + prefetch [pV1 + 32] + + mov eax, dword ptr pV2 + mov ebx, dword ptr pV1 + + pxor mm0, mm0 + + mov ecx, overlapLengthLocal + shr ecx, 2 // div by four + + loop1: + movq mm1, [eax] + prefetch [eax + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm1, [ebx] + prefetch [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movq mm2, [eax + 8] + pfadd mm0, mm1 + pfmul mm2, [ebx + 8] + + movq mm3, [eax + 16] + pfadd mm0, mm2 + pfmul mm3, [ebx + 16] + + movq mm4, [eax + 24] + pfadd mm0, mm3 + pfmul mm4, [ebx + 24] + + add eax, 32 + pfadd mm0, mm4 + add ebx, 32 + + dec ecx + jnz loop1 + + // add halfs of mm0 together and return the result. + // note: mm1 is used as a dummy parameter only, we actually don't care about it's value + pfacc mm0, mm1 + movd corr, mm0 + femms + } + + return corr; +} + + + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of 3DNow! optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilter3DNow::FIRFilter3DNow() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilter3DNow::~FIRFilter3DNow() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for 3DNow! routine +void FIRFilter3DNow::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + +// 3DNow!-optimized version of the filter routine for stereo sound +uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, const uint numSamples) const +{ + float *filterCoeffsLocal = filterCoeffsAlign; + uint count = (numSamples - length) & -2; + uint lengthLocal = length / 4; + + assert(length != 0); + assert(count % 2 == 0); + + /* original code: + + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + filterCoeffsLocal = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * filterCoeffsLocal[0] + + ptr[2] * filterCoeffsLocal[2] + + ptr[4] * filterCoeffsLocal[4] + + ptr[6] * filterCoeffsLocal[6]; + + sumr1 += ptr[1] * filterCoeffsLocal[1] + + ptr[3] * filterCoeffsLocal[3] + + ptr[5] * filterCoeffsLocal[5] + + ptr[7] * filterCoeffsLocal[7]; + + suml2 += ptr[8] * filterCoeffsLocal[0] + + ptr[10] * filterCoeffsLocal[2] + + ptr[12] * filterCoeffsLocal[4] + + ptr[14] * filterCoeffsLocal[6]; + + sumr2 += ptr[9] * filterCoeffsLocal[1] + + ptr[11] * filterCoeffsLocal[3] + + ptr[13] * filterCoeffsLocal[5] + + ptr[15] * filterCoeffsLocal[7]; + + ptr += 16; + filterCoeffsLocal += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + + */ + _asm + { + mov eax, dword ptr dest + mov ebx, dword ptr src + mov edx, count + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + prefetch [ebx] // give a prefetch hint to CPU what data are to be needed soonish + prefetch [filterCoeffsLocal] // give a prefetch hint to CPU what data are to be needed soonish + + mov esi, ebx + mov edi, filterCoeffsLocal + pxor mm0, mm0 + pxor mm1, mm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round four FIR filter taps are evaluated for 2*2 output samples + movq mm2, [edi] + movq mm3, mm2 + prefetch [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm2, [esi] + prefetch [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + pfmul mm3, [esi + 8] + + movq mm4, [edi + 8] + movq mm5, mm4 + pfadd mm0, mm2 + pfmul mm4, [esi + 8] + pfadd mm1, mm3 + pfmul mm5, [esi + 16] + + movq mm2, [edi + 16] + movq mm6, mm2 + pfadd mm0, mm4 + pfmul mm2, [esi + 16] + pfadd mm1, mm5 + pfmul mm6, [esi + 24] + + movq mm3, [edi + 24] + movq mm7, mm3 + pfadd mm0, mm2 + pfmul mm3, [esi + 24] + pfadd mm1, mm6 + pfmul mm7, [esi + 32] + add esi, 32 + pfadd mm0, mm3 + add edi, 32 + pfadd mm1, mm7 + + dec ecx + jnz loop2 + + movq [eax], mm0 + add ebx, 16 + movq [eax + 8], mm1 + add eax, 16 + + dec edx + jnz loop1 + + femms + } + + return count; +} + + +#endif // ALLOW_3DNOW diff --git a/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.cpp b/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.cpp new file mode 100644 index 0000000000..9a5cf539c0 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.cpp @@ -0,0 +1,184 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// FIR low-pass (anti-alias) filter with filter coefficient design routine and +/// MMX optimization. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "AAFilter.h" +#include "FIRFilter.h" + +using namespace soundtouch; + +#define PI 3.141592655357989 +#define TWOPI (2 * PI) + +/***************************************************************************** + * + * Implementation of the class 'AAFilter' + * + *****************************************************************************/ + +AAFilter::AAFilter(const uint length) +{ + pFIR = FIRFilter::newInstance(); + cutoffFreq = 0.5; + setLength(length); +} + + + +AAFilter::~AAFilter() +{ + delete pFIR; +} + + + +// Sets new anti-alias filter cut-off edge frequency, scaled to +// sampling frequency (nyquist frequency = 0.5). +// The filter will cut frequencies higher than the given frequency. +void AAFilter::setCutoffFreq(const double newCutoffFreq) +{ + cutoffFreq = newCutoffFreq; + calculateCoeffs(); +} + + + +// Sets number of FIR filter taps +void AAFilter::setLength(const uint newLength) +{ + length = newLength; + calculateCoeffs(); +} + + + +// Calculates coefficients for a low-pass FIR filter using Hamming window +void AAFilter::calculateCoeffs() +{ + uint i; + double cntTemp, temp, tempCoeff,h, w; + double fc2, wc; + double scaleCoeff, sum; + double *work; + SAMPLETYPE *coeffs; + + assert(length > 0); + assert(length % 4 == 0); + assert(cutoffFreq >= 0); + assert(cutoffFreq <= 0.5); + + work = new double[length]; + coeffs = new SAMPLETYPE[length]; + + fc2 = 2.0 * cutoffFreq; + wc = PI * fc2; + tempCoeff = TWOPI / (double)length; + + sum = 0; + for (i = 0; i < length; i ++) + { + cntTemp = (double)i - (double)(length / 2); + + temp = cntTemp * wc; + if (temp != 0) + { + h = fc2 * sin(temp) / temp; // sinc function + } + else + { + h = 1.0; + } + w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window + + temp = w * h; + work[i] = temp; + + // calc net sum of coefficients + sum += temp; + } + + // ensure the sum of coefficients is larger than zero + assert(sum > 0); + + // ensure we've really designed a lowpass filter... + assert(work[length/2] > 0); + assert(work[length/2 + 1] > -1e-6); + assert(work[length/2 - 1] > -1e-6); + + // Calculate a scaling coefficient in such a way that the result can be + // divided by 16384 + scaleCoeff = 16384.0f / sum; + + for (i = 0; i < length; i ++) + { + // scale & round to nearest integer + temp = work[i] * scaleCoeff; + temp += (temp >= 0) ? 0.5 : -0.5; + // ensure no overfloods + assert(temp >= -32768 && temp <= 32767); + coeffs[i] = (SAMPLETYPE)temp; + } + + // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 + pFIR->setCoefficients(coeffs, length, 14); + + delete[] work; + delete[] coeffs; +} + + +// Applies the filter to the given sequence of samples. +// Note : The amount of outputted samples is by value of 'filter length' +// smaller than the amount of input samples. +uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const +{ + return pFIR->evaluate(dest, src, numSamples, numChannels); +} + + +uint AAFilter::getLength() const +{ + return pFIR->getLength(); +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.h b/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.h new file mode 100644 index 0000000000..4c85dcdbe7 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/AAFilter.h @@ -0,0 +1,91 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef AAFilter_H +#define AAFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class AAFilter +{ +protected: + class FIRFilter *pFIR; + + /// Low-pass filter cut-off frequency, negative = invalid + double cutoffFreq; + + /// num of filter taps + uint length; + + /// Calculate the FIR coefficients realizing the given cutoff-frequency + void calculateCoeffs(); +public: + AAFilter(uint length); + + ~AAFilter(); + + /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling + /// frequency (nyquist frequency = 0.5). The filter will cut off the + /// frequencies than that. + void setCutoffFreq(double newCutoffFreq); + + /// Sets number of FIR filter taps, i.e. ~filter complexity + void setLength(uint newLength); + + uint getLength() const; + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter length' + /// smaller than the amount of input samples. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; +}; + +} + +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/BPMDetect.h b/plugins/zerospu2/3rdparty/SoundTouch/BPMDetect.h new file mode 100644 index 0000000000..ac616e7e2b --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/BPMDetect.h @@ -0,0 +1,159 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Beats-per-minute (BPM) detection routine. +/// +/// The beat detection algorithm works as follows: +/// - Use function 'inputSamples' to input a chunks of samples to the class for +/// analysis. It's a good idea to enter a large sound file or stream in smallish +/// chunks of around few kilosamples in order not to extinguish too much RAM memory. +/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, +/// which is basically ok as low (bass) frequencies mostly determine the beat rate. +/// Simple averaging is used for anti-alias filtering because the resulting signal +/// quality isn't of that high importance. +/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by +/// taking absolute value that's smoothed by sliding average. Signal levels that +/// are below a couple of times the general RMS amplitude level are cut away to +/// leave only notable peaks there. +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// autocorrelation function of the enveloped signal. +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// function, calculates it's precise location and converts this reading to bpm's. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.5 $ +// +// $Id: BPMDetect.h,v 1.5 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _BPMDetect_H_ +#define _BPMDetect_H_ + +#include "STTypes.h" +#include "FIFOSampleBuffer.h" + +/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. +#define MIN_BPM 45 + +/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. +#define MAX_BPM 230 + + +/// Class for calculating BPM rate for audio data. +class BPMDetect +{ +protected: + /// Auto-correlation accumulator bins. + float *xcorr; + + /// Amplitude envelope sliding average approximation level accumulator + float envelopeAccu; + + /// RMS volume sliding average approximation level accumulator + float RMSVolumeAccu; + + /// Sample average counter. + int decimateCount; + + /// Sample average accumulator for FIFO-like decimation. + soundtouch::LONG_SAMPLETYPE decimateSum; + + /// Decimate sound by this coefficient to reach approx. 500 Hz. + int decimateBy; + + /// Auto-correlation window length + int windowLen; + + /// Number of channels (1 = mono, 2 = stereo) + int channels; + + /// sample rate + int sampleRate; + + /// Beginning of auto-correlation window: Autocorrelation isn't being updated for + /// the first these many correlation bins. + int windowStart; + + /// FIFO-buffer for decimated processing samples. + soundtouch::FIFOSampleBuffer *buffer; + + /// Initialize the class for processing. + void init(int numChannels, int sampleRate); + + /// Updates auto-correlation function for given number of decimated samples that + /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe + /// though). + void updateXCorr(int process_samples /// How many samples are processed. + ); + + /// Decimates samples to approx. 500 Hz. + /// + /// \return Number of output samples. + int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer + const soundtouch::SAMPLETYPE *src, ///< Source sample buffer + int numsamples ///< Number of source samples. + ); + + /// Calculates amplitude envelope for the buffer of samples. + /// Result is output to 'samples'. + void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer + int numsamples ///< Number of samples in buffer + ); + +public: + /// Constructor. + BPMDetect(int numChannels, ///< Number of channels in sample data. + int sampleRate ///< Sample rate in Hz. + ); + + /// Destructor. + virtual ~BPMDetect(); + + /// Inputs a block of samples for analyzing: Envelopes the samples and then + /// updates the autocorrelation estimation. When whole song data has been input + /// in smaller blocks using this function, read the resulting bpm with 'getBpm' + /// function. + /// + /// Notice that data in 'samples' array can be disrupted in processing. + void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer + int numSamples ///< Number of samples in buffer + ); + + + /// Analyzes the results and returns the BPM rate. Use this function to read result + /// after whole song data has been input to the class by consecutive calls of + /// 'inputSamples' function. + /// + /// \return Beats-per-minute rate, or zero if detection failed. + float getBpm(); +}; + +#endif // _BPMDetect_H_ diff --git a/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.cpp b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.cpp new file mode 100644 index 0000000000..2bf965b763 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.cpp @@ -0,0 +1,252 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// outputted samples from the buffer, as well as grows the buffer size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.11 $ +// +// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include "FIFOSampleBuffer.h" + +using namespace soundtouch; + +// Constructor +FIFOSampleBuffer::FIFOSampleBuffer(uint numChannels) +{ + sizeInBytes = 0; // reasonable initial value + buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)]; + bufferUnaligned = NULL; + samplesInBuffer = 0; + bufferPos = 0; + channels = numChannels; +} + + +// destructor +FIFOSampleBuffer::~FIFOSampleBuffer() +{ + delete[] bufferUnaligned; +} + + +// Sets number of channels, 1 = mono, 2 = stereo +void FIFOSampleBuffer::setChannels(const uint numChannels) +{ + uint usedBytes; + + usedBytes = channels * samplesInBuffer; + channels = numChannels; + samplesInBuffer = usedBytes / channels; +} + + +// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and +// zeroes this pointer by copying samples from the 'bufferPos' pointer +// location on to the beginning of the buffer. +void FIFOSampleBuffer::rewind() +{ + if (bufferPos) + { + memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); + bufferPos = 0; + } +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position to +// the sample buffer. +void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + memcpy(ptrEnd(numSamples), samples, sizeof(SAMPLETYPE) * numSamples * channels); + samplesInBuffer += numSamples; +} + + +// Increases the number of samples in the buffer without copying any actual +// samples. +// +// This function is used to update the number of samples in the sample buffer +// when accessing the buffer directly with 'ptrEnd' function. Please be +// careful though! +void FIFOSampleBuffer::putSamples(uint numSamples) +{ + uint req; + + req = samplesInBuffer + numSamples; + ensureCapacity(req); + samplesInBuffer += numSamples; +} + + +// Returns a pointer to the end of the used part of the sample buffer (i.e. +// where the new samples are to be inserted). This function may be used for +// inserting new samples into the sample buffer directly. Please be careful! +// +// Parameter 'slackCapacity' tells the function how much free capacity (in +// terms of samples) there _at least_ should be, in order to the caller to +// succesfully insert all the required samples to the buffer. When necessary, +// the function grows the buffer size to comply with this requirement. +// +// When using this function as means for inserting new samples, also remember +// to increase the sample count afterwards, by calling the +// 'putSamples(numSamples)' function. +SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) +{ + ensureCapacity(samplesInBuffer + slackCapacity); + return buffer + samplesInBuffer * channels; +} + + +// Returns a pointer to the beginning of the currently non-outputted samples. +// This function is provided for accessing the output samples directly. +// Please be careful! +// +// When using this function to output samples, also remember to 'remove' the +// outputted samples from the buffer by calling the +// 'receiveSamples(numSamples)' function +SAMPLETYPE *FIFOSampleBuffer::ptrBegin() const +{ + return buffer + bufferPos * channels; +} + + +// Ensures that the buffer has enought capacity, i.e. space for _at least_ +// 'capacityRequirement' number of samples. The buffer is grown in steps of +// 4 kilobytes to eliminate the need for frequently growing up the buffer, +// as well as to round the buffer size up to the virtual memory page size. +void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) +{ + SAMPLETYPE *tempUnaligned, *temp; + + if (capacityRequirement > getCapacity()) + { + // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) + sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096; + assert(sizeInBytes % 2 == 0); + tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; + if (tempUnaligned == NULL) + { + throw std::runtime_error("Couldn't allocate memory!\n"); + } + temp = (SAMPLETYPE *)(((ulongptr)tempUnaligned + 15) & -16); + memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); + delete[] bufferUnaligned; + buffer = temp; + bufferUnaligned = tempUnaligned; + bufferPos = 0; + } + else + { + // simply rewind the buffer (if necessary) + rewind(); + } +} + + +// Returns the current buffer capacity in terms of samples +uint FIFOSampleBuffer::getCapacity() const +{ + return sizeInBytes / (channels * sizeof(SAMPLETYPE)); +} + + +// Returns the number of samples currently in the buffer +uint FIFOSampleBuffer::numSamples() const +{ + return samplesInBuffer; +} + + +// Output samples from beginning of the sample buffer. Copies demanded number +// of samples to output and removes them from the sample buffer. If there +// are less than 'numsample' samples in the buffer, returns all available. +// +// Returns number of samples copied. +uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) +{ + uint num; + + num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; + + memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); + return receiveSamples(num); +} + + +// Removes samples from the beginning of the sample buffer without copying them +// anywhere. Used to reduce the number of samples in the buffer, when accessing +// the sample buffer with the 'ptrBegin' function. +uint FIFOSampleBuffer::receiveSamples(uint maxSamples) +{ + if (maxSamples >= samplesInBuffer) + { + uint temp; + + temp = samplesInBuffer; + samplesInBuffer = 0; + return temp; + } + + samplesInBuffer -= maxSamples; + bufferPos += maxSamples; + + return maxSamples; +} + + +// Returns nonzero if the sample buffer is empty +int FIFOSampleBuffer::isEmpty() const +{ + return (samplesInBuffer == 0) ? 1 : 0; +} + + +// Clears the sample buffer +void FIFOSampleBuffer::clear() +{ + samplesInBuffer = 0; + bufferPos = 0; +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.h b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.h new file mode 100644 index 0000000000..09f74c9a65 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSampleBuffer.h @@ -0,0 +1,174 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// output samples from the buffer as well as grows the storage size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.9 $ +// +// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSampleBuffer_H +#define FIFOSampleBuffer_H + +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes +/// care of storage size adjustment and data moving during input/output operations. +/// +/// Notice that in case of stereo audio, one sample is considered to consist of +/// both channel data. +class FIFOSampleBuffer : public FIFOSamplePipe +{ +private: + /// Sample buffer. + SAMPLETYPE *buffer; + + // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first + // 16-byte aligned location of this buffer + SAMPLETYPE *bufferUnaligned; + + /// Sample buffer size in bytes + uint sizeInBytes; + + /// How many samples are currently in buffer. + uint samplesInBuffer; + + /// Channels, 1=mono, 2=stereo. + uint channels; + + /// Current position pointer to the buffer. This pointer is increased when samples are + /// removed from the pipe so that it's necessary to actually rewind buffer (move data) + /// only new data when is put to the pipe. + uint bufferPos; + + /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real + /// beginning of the buffer. + void rewind(); + + /// Ensures that the buffer has capacity for at least this many samples. + void ensureCapacity(const uint capacityRequirement); + + /// Returns current capacity. + uint getCapacity() const; + +public: + + /// Constructor + FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. + ///< Default is stereo. + ); + + /// destructor + ~FIFOSampleBuffer(); + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const; + + /// Returns a pointer to the end of the used part of the sample buffer (i.e. + /// where the new samples are to be inserted). This function may be used for + /// inserting new samples into the sample buffer directly. Please be careful + /// not corrupt the book-keeping! + /// + /// When using this function as means for inserting new samples, also remember + /// to increase the sample count afterwards, by calling the + /// 'putSamples(numSamples)' function. + SAMPLETYPE *ptrEnd( + uint slackCapacity ///< How much free capacity (in samples) there _at least_ + ///< should be so that the caller can succesfully insert the + ///< desired samples to the buffer. If necessary, the function + ///< grows the buffer size to comply with this requirement. + ); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ); + + /// Adjusts the book-keeping to increase number of samples in the buffer without + /// copying any actual samples. + /// + /// This function is used to update the number of samples in the sample buffer + /// when accessing the buffer directly with 'ptrEnd' function. Please be + /// careful though! + virtual void putSamples(uint numSamples ///< Number of samples been inserted. + ); + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ); + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ); + + /// Returns number of samples currently available. + virtual uint numSamples() const; + + /// Sets number of channels, 1 = mono, 2 = stereo. + void setChannels(uint numChannels); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const; + + /// Clears all the samples. + virtual void clear(); +}; + +} + +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/FIFOSamplePipe.h b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSamplePipe.h new file mode 100644 index 0000000000..33e33c7e36 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/FIFOSamplePipe.h @@ -0,0 +1,217 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound +/// samples by operating like a first-in-first-out pipe: New samples are fed +/// into one end of the pipe with the 'putSamples' function, and the processed +/// samples are received from the other end with the 'receiveSamples' function. +/// +/// 'FIFOProcessor' : A base class for classes the do signal processing with +/// the samples while operating like a first-in-first-out pipe. When samples +/// are input with the 'putSamples' function, the class processes them +/// and moves the processed samples to the given 'output' pipe object, which +/// may be either another processing stage, or a fifo sample buffer object. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.8 $ +// +// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSamplePipe_H +#define FIFOSamplePipe_H + +#include +#include +#include "STTypes.h" + +namespace soundtouch +{ + +/// Abstract base class for FIFO (first-in-first-out) sample processing classes. +class FIFOSamplePipe +{ +public: + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const = 0; + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ) = 0; + + + // Moves samples from the 'other' pipe instance to this instance. + void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. + ) + { + int oNumSamples = other.numSamples(); + + putSamples(other.ptrBegin(), oNumSamples); + other.receiveSamples(oNumSamples); + }; + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) = 0; + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) = 0; + + /// Returns number of samples currently available. + virtual uint numSamples() const = 0; + + // Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const = 0; + + /// Clears all the samples. + virtual void clear() = 0; +}; + + + +/// Base-class for sound processing routines working in FIFO principle. With this base +/// class it's easy to implement sound processing stages that can be chained together, +/// so that samples that are fed into beginning of the pipe automatically go through +/// all the processing stages. +/// +/// When samples are input to this class, they're first processed and then put to +/// the FIFO pipe that's defined as output of this class. This output pipe can be +/// either other processing stage or a FIFO sample buffer. +class FIFOProcessor :public FIFOSamplePipe +{ +protected: + /// Internal pipe where processed samples are put. + FIFOSamplePipe *output; + + /// Sets output pipe. + void setOutPipe(FIFOSamplePipe *pOutput) + { + assert(output == NULL); + assert(pOutput != NULL); + output = pOutput; + } + + + /// Constructor. Doesn't define output pipe; it has to be set be + /// 'setOutPipe' function. + FIFOProcessor() + { + output = NULL; + } + + + /// Constructor. Configures output pipe. + FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. + ) + { + output = pOutput; + } + + + /// Destructor. + virtual ~FIFOProcessor() + { + } + + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() const + { + return output->ptrBegin(); + } + +public: + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) + { + return output->receiveSamples(outBuffer, maxSamples); + } + + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) + { + return output->receiveSamples(maxSamples); + } + + + /// Returns number of samples currently available. + virtual uint numSamples() const + { + return output->numSamples(); + } + + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const + { + return output->isEmpty(); + } +}; + +} + +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.cpp b/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.cpp new file mode 100644 index 0000000000..ac57335a18 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.cpp @@ -0,0 +1,272 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "FIRFilter.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/***************************************************************************** + * + * Implementation of the class 'FIRFilter' + * + *****************************************************************************/ + +FIRFilter::FIRFilter() +{ + resultDivFactor = 0; + length = 0; + lengthDiv8 = 0; + filterCoeffs = NULL; +} + + +FIRFilter::~FIRFilter() +{ + delete[] filterCoeffs; +} + +// Usual C-version of the filter routine for stereo sound +uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE suml, sumr; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + assert(length != 0); + + end = 2 * (numSamples - length); + + for (j = 0; j < end; j += 2) + { + const SAMPLETYPE *ptr; + + suml = sumr = 0; + ptr = src + j; + + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + + ptr[2 * i + 2] * filterCoeffs[i + 1] + + ptr[2 * i + 4] * filterCoeffs[i + 2] + + ptr[2 * i + 6] * filterCoeffs[i + 3]; + sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + + ptr[2 * i + 3] * filterCoeffs[i + 1] + + ptr[2 * i + 5] * filterCoeffs[i + 2] + + ptr[2 * i + 7] * filterCoeffs[i + 3]; + } + +#ifdef INTEGER_SAMPLES + suml >>= resultDivFactor; + sumr >>= resultDivFactor; + // saturate to 16 bit integer limits + suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; + // saturate to 16 bit integer limits + sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; +#else + suml *= dScaler; + sumr *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)suml; + dest[j + 1] = (SAMPLETYPE)sumr; + } + return numSamples - length; +} + + + + +// Usual C-version of the filter routine for mono sound +uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + uint i, j, end; + LONG_SAMPLETYPE sum; +#ifdef FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + + assert(length != 0); + + end = numSamples - length; + for (j = 0; j < end; j ++) + { + sum = 0; + for (i = 0; i < length; i += 4) + { + // loop is unrolled by factor of 4 here for efficiency + sum += src[i + 0] * filterCoeffs[i + 0] + + src[i + 1] * filterCoeffs[i + 1] + + src[i + 2] * filterCoeffs[i + 2] + + src[i + 3] * filterCoeffs[i + 3]; + } +#ifdef INTEGER_SAMPLES + sum >>= resultDivFactor; + // saturate to 16 bit integer limits + sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; +#else + sum *= dScaler; +#endif // INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)sum; + src ++; + } + return end; +} + + +// Set filter coeffiecients and length. +// +// Throws an exception if filter length isn't divisible by 8 +void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) +{ + assert(newLength > 0); + if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8"); + + lengthDiv8 = newLength / 8; + length = lengthDiv8 * 8; + assert(length == newLength); + + resultDivFactor = uResultDivFactor; +#ifdef INTEGER_SAMPLES + resultDivider = (SAMPLETYPE)(1< 0); + assert(lengthDiv8 * 8 == length); + if (numSamples < length) return 0; + assert(resultDivFactor >= 0); + if (numChannels == 2) + { + return evaluateFilterStereo(dest, src, numSamples); + } else { + return evaluateFilterMono(dest, src, numSamples); + } +} + + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX-capable CPU available or not. +void * FIRFilter::operator new(size_t s) +{ + // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! + throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!"); + return NULL; +} + + +FIRFilter * FIRFilter::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new FIRFilterMMX; + } + else +#endif // ALLOW_MMX + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new FIRFilterSSE; + } + else +#endif // ALLOW_SSE + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new FIRFilter3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new FIRFilter; + } +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.h b/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.h new file mode 100644 index 0000000000..be5cdd2943 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/FIRFilter.h @@ -0,0 +1,163 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.17 $ +// +// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIRFilter_H +#define FIRFilter_H + +#include "STTypes.h" + +namespace soundtouch +{ + +class FIRFilter +{ +protected: + // Number of FIR filter taps + uint length; + // Number of FIR filter taps divided by 8 + uint lengthDiv8; + + // Result divider factor in 2^k format + uint resultDivFactor; + + // Result divider value. + SAMPLETYPE resultDivider; + + // Memory for filter coefficients + SAMPLETYPE *filterCoeffs; + + virtual uint evaluateFilterStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + virtual uint evaluateFilterMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + +public: + FIRFilter(); + virtual ~FIRFilter(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX-capable CPU available or not. + void * operator new(size_t s); + + static FIRFilter *newInstance(); + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter_length' + /// smaller than the amount of input samples. + /// + /// \return Number of samples copied to 'dest'. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; + + uint getLength() const; + + virtual void setCoefficients(const SAMPLETYPE *coeffs, + uint newLength, + uint uResultDivFactor); +}; + + +// Optional subclasses that implement CPU-specific optimizations: + +#ifdef ALLOW_MMX + + /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. + class FIRFilterMMX : public FIRFilter + { + protected: + short *filterCoeffsUnalign; + short *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; + public: + FIRFilterMMX(); + ~FIRFilterMMX(); + + virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_MMX + + +#ifdef ALLOW_3DNOW + + /// Class that implements 3DNow! optimized functions exclusive for floating point samples type. + class FIRFilter3DNow : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilter3DNow(); + ~FIRFilter3DNow(); + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized functions exclusive for floating point samples type. + class FIRFilterSSE : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilterSSE(); + ~FIRFilterSSE(); + + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // ALLOW_SSE + +} + +#endif // FIRFilter_H diff --git a/plugins/zerospu2/3rdparty/SoundTouch/Makefile.am b/plugins/zerospu2/3rdparty/SoundTouch/Makefile.am new file mode 100644 index 0000000000..a09ae5f081 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/Makefile.am @@ -0,0 +1,46 @@ +## Process this file with automake to create Makefile.in +## +## $Id: Makefile.am,v 1.3 2006/02/05 18:33:34 Olli Exp $ +## +## Copyright (C) 2003 - David W. Durham +## +## This file is part of SoundTouch, an audio processing library for pitch/time adjustments +## +## SoundTouch 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. +## +## SoundTouch 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 + +AUTOMAKE_OPTIONS = foreign + +noinst_HEADERS=AAFilter.h cpu_detect.h FIRFilter.h RateTransposer.h TDStretch.h cpu_detect_x86_gcc.cpp +noinst_LIBRARIES = libSoundTouch.a + +if X86_64 +libSoundTouch_a_CXXFLAGS = -fPIC +libSoundTouch_a_CFLAGS = -fPIC +else +libSoundTouch_a_CXXFLAGS = -msse -mmmx +libSoundTouch_a_CFLAGS = -msse -mmmx +endif + +#lib_LTLIBRARIES=libSoundTouch.la +# the mmx_gcc.cpp and cpu_detect_x86_gcc.cpp may need to be conditionally included here from things discovered in configure.ac +libSoundTouch_a_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp mmx_optimized.cpp sse_optimized.cpp \ +RateTransposer.cpp SoundTouch.cpp TDStretch.cpp WavFile.cpp cpu_detect_x86_gcc.cpp + +# ??? test for -fcheck-new in configure.ac +# other compiler flags to add +AM_CXXFLAGS=-O3 -msse -fcheck-new -I../../include + +# other linking flags to add +#libSoundTouch_la_LIBADD= + diff --git a/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.cpp b/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.cpp new file mode 100644 index 0000000000..b7414b90a6 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.cpp @@ -0,0 +1,626 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application) +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/03/19 10:05:49 $ +// File revision : $Revision: 1.13 $ +// +// $Id: RateTransposer.cpp,v 1.13 2006/03/19 10:05:49 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "RateTransposer.h" +#include "AAFilter.h" + +using namespace soundtouch; + + +/// A linear samplerate transposer class that uses integer arithmetics. +/// for the transposing. +class RateTransposerInteger : public RateTransposer +{ +protected: + int iSlopeCount; + uint uRate; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerInteger(); + virtual ~RateTransposerInteger(); + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + +}; + + +/// A linear samplerate transposer class that uses floating point arithmetics +/// for the transposing. +class RateTransposerFloat : public RateTransposer +{ +protected: + float fSlopeCount; + float fRateStep; + SAMPLETYPE sPrevSampleL, sPrevSampleR; + + virtual void resetRegisters(); + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposerFloat(); + virtual ~RateTransposerFloat(); +}; + + + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * RateTransposer::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +RateTransposer *RateTransposer::newInstance() +{ +#ifdef INTEGER_SAMPLES + return ::new RateTransposerInteger; +#else + return ::new RateTransposerFloat; +#endif +} + + +// Constructor +RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) +{ + uChannels = 2; + bUseAAFilter = TRUE; + + // Instantiates the anti-alias filter with default tap length + // of 32 + pAAFilter = new AAFilter(32); +} + + + +RateTransposer::~RateTransposer() +{ + delete pAAFilter; +} + + + +/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable +void RateTransposer::enableAAFilter(const BOOL newMode) +{ + bUseAAFilter = newMode; +} + + +/// Returns nonzero if anti-alias filter is enabled. +BOOL RateTransposer::isAAFilterEnabled() const +{ + return bUseAAFilter; +} + + +AAFilter *RateTransposer::getAAFilter() const +{ + return pAAFilter; +} + + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposer::setRate(float newRate) +{ + float fCutoff; + + fRate = newRate; + + // design a new anti-alias filter + if (newRate > 1.0f) + { + fCutoff = 0.5f / newRate; + } + else + { + fCutoff = 0.5f * newRate; + } + pAAFilter->setCutoffFreq(fCutoff); +} + + +// Outputs as many samples of the 'outputBuffer' as possible, and if there's +// any room left, outputs also as many of the incoming samples as possible. +// The goal is to drive the outputBuffer empty. +// +// It's allowed for 'output' and 'input' parameters to point to the same +// memory position. +void RateTransposer::flushStoreBuffer() +{ + if (storeBuffer.isEmpty()) return; + + outputBuffer.moveSamples(storeBuffer); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void RateTransposer::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + processSamples(samples, numSamples); +} + + + +// Transposes up the sample rate, causing the observed playback 'rate' of the +// sound to decrease +void RateTransposer::upsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp, num; + + // If the parameter 'uRate' value is smaller than 'SCALE', first transpose + // the samples and then apply the anti-alias filter to remove aliasing. + + // First check that there's enough room in 'storeBuffer' + // (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + + // Transpose the samples, store the result into the end of "storeBuffer" + count = transpose(storeBuffer.ptrEnd(sizeTemp), src, numSamples); + storeBuffer.putSamples(count); + + // Apply the anti-alias filter to samples in "store output", output the + // result to "dest" + num = storeBuffer.numSamples(); + count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), + storeBuffer.ptrBegin(), num, uChannels); + outputBuffer.putSamples(count); + + // Remove the processed samples from "storeBuffer" + storeBuffer.receiveSamples(count); +} + + +// Transposes down the sample rate, causing the observed playback 'rate' of the +// sound to increase +void RateTransposer::downsample(const SAMPLETYPE *src, uint numSamples) +{ + int count, sizeTemp; + + // If the parameter 'uRate' value is larger than 'SCALE', first apply the + // anti-alias filter to remove high frequencies (prevent them from folding + // over the lover frequencies), then transpose. */ + + // Add the new samples to the end of the storeBuffer */ + storeBuffer.putSamples(src, numSamples); + + // Anti-alias filter the samples to prevent folding and output the filtered + // data to tempBuffer. Note : because of the FIR filter length, the + // filtering routine takes in 'filter_length' more samples than it outputs. + assert(tempBuffer.isEmpty()); + sizeTemp = storeBuffer.numSamples(); + + count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp), + storeBuffer.ptrBegin(), sizeTemp, uChannels); + + // Remove the filtered samples from 'storeBuffer' + storeBuffer.receiveSamples(count); + + // Transpose the samples (+16 is to reserve some slack in the destination buffer) + sizeTemp = (int)((float)numSamples / fRate + 16.0f); + count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count); + outputBuffer.putSamples(count); +} + + +// Transposes sample rate by applying anti-alias filter to prevent folding. +// Returns amount of samples returned in the "dest" buffer. +// The maximum amount of samples that can be returned at a time is set by +// the 'set_returnBuffer_size' function. +void RateTransposer::processSamples(const SAMPLETYPE *src, uint numSamples) +{ + uint count; + uint sizeReq; + + if (numSamples == 0) return; + assert(pAAFilter); + + // If anti-alias filter is turned off, simply transpose without applying + // the filter + if (bUseAAFilter == FALSE) + { + sizeReq = (int)((float)numSamples / fRate + 1.0f); + count = transpose(outputBuffer.ptrEnd(sizeReq), src, numSamples); + outputBuffer.putSamples(count); + return; + } + + // Transpose with anti-alias filter + if (fRate < 1.0f) + { + upsample(src, numSamples); + } + else + { + downsample(src, numSamples); + } +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// Returns the number of samples returned in the "dest" buffer +inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + if (uChannels == 2) + { + return transposeStereo(dest, src, numSamples); + } + else + { + return transposeMono(dest, src, numSamples); + } +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void RateTransposer::setChannels(const uint numchannels) +{ + if (uChannels == numchannels) return; + + assert(numchannels == 1 || numchannels == 2); + uChannels = numchannels; + + storeBuffer.setChannels(uChannels); + tempBuffer.setChannels(uChannels); + outputBuffer.setChannels(uChannels); + + // Inits the linear interpolation registers + resetRegisters(); +} + + +// Clears all the samples in the object +void RateTransposer::clear() +{ + outputBuffer.clear(); + storeBuffer.clear(); +} + + +// Returns nonzero if there aren't any samples available for outputting. +uint RateTransposer::isEmpty() +{ + int res; + + res = FIFOProcessor::isEmpty(); + if (res == 0) return 0; + return storeBuffer.isEmpty(); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerInteger - integer arithmetic implementation +// + +/// fixed-point interpolation routine precision +#define SCALE 65536 + +// Constructor +RateTransposerInteger::RateTransposerInteger() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerInteger::~RateTransposerInteger() +{ +} + + +void RateTransposerInteger::resetRegisters() +{ + iSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + LONG_SAMPLETYPE temp, vol1; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[used] * vol1 + iSlopeCount * src[used + 1]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Stereo' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + LONG_SAMPLETYPE temp, vol1; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (iSlopeCount <= SCALE) + { + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = vol1 * sPrevSampleR + iSlopeCount * src[1]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + i++; + iSlopeCount += uRate; + } + // now always (iSlopeCount > SCALE) + iSlopeCount -= SCALE; + + while (1) + { + while (iSlopeCount > SCALE) + { + iSlopeCount -= SCALE; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); + temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2]; + dest[2 * i] = (SAMPLETYPE)(temp / SCALE); + temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3]; + dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); + + i++; + iSlopeCount += uRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} + + +// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower +// uRate, larger faster uRates. +void RateTransposerInteger::setRate(float newRate) +{ + uRate = (int)(newRate * SCALE + 0.5f); + RateTransposer::setRate(newRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// RateTransposerFloat - floating point arithmetic implementation +// +////////////////////////////////////////////////////////////////////////////// + +// Constructor +RateTransposerFloat::RateTransposerFloat() : RateTransposer() +{ + // call these here as these are virtual functions; calling these + // from the base class constructor wouldn't execute the overloaded + // versions (peculiar C++ can be). + resetRegisters(); + setRate(1.0f); +} + + +RateTransposerFloat::~RateTransposerFloat() +{ +} + + +void RateTransposerFloat::resetRegisters() +{ + fSlopeCount = 0; + sPrevSampleL = + sPrevSampleR = 0; +} + + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int i, used; + + used = 0; + i = 0; + + // Process the last sample saved from the previous call first... + while (fSlopeCount <= 1.0f) + { + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + i++; + fSlopeCount += fRate; + } + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]); + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[numSamples - 1]; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) +{ + unsigned int srcPos, i, used; + + if (numSamples == 0) return 0; // no samples, no work + + used = 0; + i = 0; + + // Process the last sample saved from the sPrevSampleLious call first... + while (fSlopeCount <= 1.0f) + { + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]); + i++; + fSlopeCount += fRate; + } + // now always (iSlopeCount > 1.0f) + fSlopeCount -= 1.0f; + + if (numSamples == 1) goto end; + + while (1) + { + while (fSlopeCount > 1.0f) + { + fSlopeCount -= 1.0f; + used ++; + if (used >= numSamples - 1) goto end; + } + srcPos = 2 * used; + + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos] + + fSlopeCount * src[srcPos + 2]); + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1] + + fSlopeCount * src[srcPos + 3]); + + i++; + fSlopeCount += fRate; + } +end: + // Store the last sample for the next round + sPrevSampleL = src[2 * numSamples - 2]; + sPrevSampleR = src[2 * numSamples - 1]; + + return i; +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.h b/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.h new file mode 100644 index 0000000000..f73978e639 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/RateTransposer.h @@ -0,0 +1,162 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application). +/// +/// Use either of the derived classes of 'RateTransposerInteger' or +/// 'RateTransposerFloat' for corresponding integer/floating point tranposing +/// algorithm implementation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: RateTransposer.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef RateTransposer_H +#define RateTransposer_H + +#include "AAFilter.h" +#include "FIFOSamplePipe.h" +#include "FIFOSampleBuffer.h" + +#include "STTypes.h" + +namespace soundtouch +{ + +/// A common linear samplerate transposer class. +/// +/// Note: Use function "RateTransposer::newInstance()" to create a new class +/// instance instead of the "new" operator; that function automatically +/// chooses a correct implementation depending on if integer or floating +/// arithmetics are to be used. +class RateTransposer : public FIFOProcessor +{ +protected: + /// Anti-alias filter object + AAFilter *pAAFilter; + + float fRate; + + uint uChannels; + + /// Buffer for collecting samples to feed the anti-alias filter between + /// two batches + FIFOSampleBuffer storeBuffer; + + /// Buffer for keeping samples between transposing & anti-alias filter + FIFOSampleBuffer tempBuffer; + + /// Output sample buffer + FIFOSampleBuffer outputBuffer; + + BOOL bUseAAFilter; + + void init(); + + virtual void resetRegisters() = 0; + + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) = 0; + uint transpose(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples); + + void flushStoreBuffer(); + + void downsample(const SAMPLETYPE *src, + uint numSamples); + void upsample(const SAMPLETYPE *src, + uint numSamples); + + /// Transposes sample rate by applying anti-alias filter to prevent folding. + /// Returns amount of samples returned in the "dest" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(const SAMPLETYPE *src, + uint numSamples); + + +public: + RateTransposer(); + virtual ~RateTransposer(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we're to use integer or floating point arithmetics. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct implementation, depending on if + /// integer ot floating point arithmetics are to be used. + static RateTransposer *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the store buffer object + FIFOSamplePipe *getStore() { return &storeBuffer; }; + + /// Return anti-alias filter object + AAFilter *getAAFilter() const; + + /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable + void enableAAFilter(BOOL newMode); + + /// Returns nonzero if anti-alias filter is enabled. + BOOL isAAFilterEnabled() const; + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint channels); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + void putSamples(const SAMPLETYPE *samples, uint numSamples); + + /// Clears all the samples in the object + void clear(); + + /// Returns nonzero if there aren't any samples available for outputting. + uint isEmpty(); +}; + +} + +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/STTypes.h b/plugins/zerospu2/3rdparty/SoundTouch/STTypes.h new file mode 100644 index 0000000000..f3a6a5d5c0 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/STTypes.h @@ -0,0 +1,202 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Common type definitions for SoundTouch audio processing library. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: STTypes.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef STTypes_H +#define STTypes_H + +//#define INTEGER_SAMPLES 1 + +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifdef __x86_64__ +typedef unsigned long long ulongptr; +#else +typedef unsigned long ulongptr; +#endif + + +#ifdef __GNUC__ + // In GCC, include soundtouch_config.h made by config scritps +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Use Integer as Sample type */ +//#define INTEGER_SAMPLES 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +#endif + +#ifndef _WINDEF_ + // if these aren't defined already by Windows headers, define now + + typedef int BOOL; + +#ifndef FALSE + #define FALSE 0 +#endif + +#ifndef TRUE + #define TRUE 1 +#endif + +#endif // _WINDEF_ + + +namespace soundtouch +{ +/// Activate these undef's to overrule the possible sampletype +/// setting inherited from some other header file: +//#undef INTEGER_SAMPLES +//#undef FLOAT_SAMPLES + +#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) + + /// Choose either 32bit floating point or 16bit integer sampletype + /// by choosing one of the following defines, unless this selection + /// has already been done in some other file. + //// + /// Notes: + /// - In Windows environment, choose the sample format with the + /// following defines. + /// - In GNU environment, the floating point samples are used by + /// default, but integer samples can be chosen by giving the + /// following switch to the configure script: + /// ./configure --enable-integer-samples + /// However, if you still prefer to select the sample format here + /// also in GNU environment, then please #undef the INTEGER_SAMPLE + /// and FLOAT_SAMPLE defines first as in comments above. + //#define INTEGER_SAMPLES 1 //< 16bit integer samples + #define FLOAT_SAMPLES 1 //< 32bit float samples + + #endif + + /// Define this to allow CPU-specific assembler optimizations. Notice that + /// having this enabled on non-x86 platforms doesn't matter; the compiler can + /// drop unsupported extensions on different platforms automatically. + /// However, if you're having difficulties getting the optimized routines + /// compiled with your compler (e.g. some gcc compiler versions may be picky), + /// you may wish to disable the optimizations to make the library compile. + #if !defined(_MSC_VER) || !defined(__x86_64__) + #define ALLOW_OPTIMIZATIONS 1 + #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 + #endif + + + // If defined, allows the SIMD-optimized routines to take minor shortcuts + // for improved performance. Undefine to require faithfully similar SIMD + // calculations as in normal C implementation. + + + + #ifdef INTEGER_SAMPLES + // 16bit integer sample type + typedef short SAMPLETYPE; + // data type for sample accumulation: Use 32bit integer to prevent overflows + typedef long LONG_SAMPLETYPE; + + #ifdef FLOAT_SAMPLES + // check that only one sample type is defined + #error "conflicting sample types defined" + #endif // FLOAT_SAMPLES + + #ifdef ALLOW_OPTIMIZATIONS + #if (_WIN32 || __i386__ || __x86_64__) + // Allow MMX optimizations + #define ALLOW_MMX 1 + #endif + #endif + + #else + + // floating point samples + typedef float SAMPLETYPE; + // data type for sample accumulation: Use double to utilize full precision. + typedef double LONG_SAMPLETYPE; + + #ifdef ALLOW_OPTIMIZATIONS + // Allow 3DNow! and SSE optimizations + #if _WIN32 + // #define ALLOW_3DNOW 1 + #endif + + #if (_WIN32 || __i386__ || __x86_64__) + #define ALLOW_SSE 1 + #endif + #endif + + #endif // INTEGER_SAMPLES +}; + +#endif \ No newline at end of file diff --git a/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.cpp b/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.cpp new file mode 100644 index 0000000000..d20fd326ba --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.cpp @@ -0,0 +1,474 @@ +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.13 $ +// +// $Id: SoundTouch.cpp,v 1.13 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "SoundTouch.h" +#include "TDStretch.h" +#include "RateTransposer.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/// Print library version string +extern "C" void soundtouch_ac_test() +{ + printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); +} + + +SoundTouch::SoundTouch() +{ + // Initialize rate transposer and tempo changer instances + + pRateTransposer = RateTransposer::newInstance(); + pTDStretch = TDStretch::newInstance(); + + setOutPipe(pTDStretch); + + rate = tempo = 0; + + virtualPitch = + virtualRate = + virtualTempo = 1.0; + + calcEffectiveRateAndTempo(); + + channels = 0; + bSrateSet = FALSE; +} + + + +SoundTouch::~SoundTouch() +{ + delete pRateTransposer; + delete pTDStretch; +} + + + +/// Get SoundTouch library version string +const char *SoundTouch::getVersionString() +{ + static const char *_version = SOUNDTOUCH_VERSION; + + return _version; +} + + +/// Get SoundTouch library version Id +uint SoundTouch::getVersionId() +{ + return SOUNDTOUCH_VERSION_ID; +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void SoundTouch::setChannels(uint numChannels) +{ + if (numChannels != 1 && numChannels != 2) + { + throw std::runtime_error("Illegal number of channels"); + } + channels = numChannels; + pRateTransposer->setChannels(numChannels); + pTDStretch->setChannels(numChannels); +} + + + +// Sets new rate control value. Normal rate = 1.0, smaller values +// represent slower rate, larger faster rates. +void SoundTouch::setRate(float newRate) +{ + virtualRate = newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new rate control value as a difference in percents compared +// to the original rate (-50 .. +100 %) +void SoundTouch::setRateChange(float newRate) +{ + virtualRate = 1.0f + 0.01f * newRate; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value. Normal tempo = 1.0, smaller values +// represent slower tempo, larger faster tempo. +void SoundTouch::setTempo(float newTempo) +{ + virtualTempo = newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new tempo control value as a difference in percents compared +// to the original tempo (-50 .. +100 %) +void SoundTouch::setTempoChange(float newTempo) +{ + virtualTempo = 1.0f + 0.01f * newTempo; + calcEffectiveRateAndTempo(); +} + + + +// Sets new pitch control value. Original pitch = 1.0, smaller values +// represent lower pitches, larger values higher pitch. +void SoundTouch::setPitch(float newPitch) +{ + virtualPitch = newPitch; + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in octaves compared to the original pitch +// (-1.00 .. +1.00) +void SoundTouch::setPitchOctaves(float newPitch) +{ + virtualPitch = (float)exp(0.69314718056f * newPitch); + calcEffectiveRateAndTempo(); +} + + + +// Sets pitch change in semi-tones compared to the original pitch +// (-12 .. +12) +void SoundTouch::setPitchSemiTones(int newPitch) +{ + setPitchOctaves((float)newPitch / 12.0f); +} + + + +void SoundTouch::setPitchSemiTones(float newPitch) +{ + setPitchOctaves(newPitch / 12.0f); +} + + +// Calculates 'effective' rate and tempo values from the +// nominal control values. +void SoundTouch::calcEffectiveRateAndTempo() +{ + float oldTempo = tempo; + float oldRate = rate; + + tempo = virtualTempo / virtualPitch; + rate = virtualPitch * virtualRate; + + if (rate != oldRate) pRateTransposer->setRate(rate); + if (tempo != oldTempo) pTDStretch->setTempo(tempo); + + if (rate > 1.0f) + { + if (output != pRateTransposer) + { + FIFOSamplePipe *transOut; + + assert(output == pTDStretch); + // move samples in the current output buffer to the output of pRateTransposer + transOut = pRateTransposer->getOutput(); + transOut->moveSamples(*output); + // move samples in tempo changer's input to pitch transposer's input + pRateTransposer->moveSamples(*pTDStretch->getInput()); + + output = pRateTransposer; + } + } + else + { + if (output != pTDStretch) + { + FIFOSamplePipe *tempoOut; + + assert(output == pRateTransposer); + // move samples in the current output buffer to the output of pTDStretch + tempoOut = pTDStretch->getOutput(); + tempoOut->moveSamples(*output); + // move samples in pitch transposer's store buffer to tempo changer's input + pTDStretch->moveSamples(*pRateTransposer->getStore()); + + output = pTDStretch; + + } + } +} + + +// Sets sample rate. +void SoundTouch::setSampleRate(uint srate) +{ + bSrateSet = TRUE; + // set sample rate, leave other tempo changer parameters as they are. + pTDStretch->setParameters(srate); +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + if (bSrateSet == FALSE) + { + throw std::runtime_error("SoundTouch : Sample rate not defined"); + } + else if (channels == 0) + { + throw std::runtime_error("SoundTouch : Number of channels not defined"); + } + + // Transpose the rate of the new samples if necessary + /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... + if (rate == 1.0f) + { + // The rate value is same as the original, simply evaluate the tempo changer. + assert(output == pTDStretch); + if (pRateTransposer->isEmpty() == 0) + { + // yet flush the last samples in the pitch transposer buffer + // (may happen if 'rate' changes from a non-zero value to zero) + pTDStretch->moveSamples(*pRateTransposer); + } + pTDStretch->putSamples(samples, numSamples); + } + */ + else if (rate <= 1.0f) + { + // transpose the rate down, output the transposed sound to tempo changer buffer + assert(output == pTDStretch); + pRateTransposer->putSamples(samples, numSamples); + pTDStretch->moveSamples(*pRateTransposer); + } + else + { + assert(rate > 1.0f); + // evaluate the tempo changer, then transpose the rate up, + assert(output == pRateTransposer); + pTDStretch->putSamples(samples, numSamples); + pRateTransposer->moveSamples(*pTDStretch); + } +} + + +// Flushes the last samples from the processing pipeline to the output. +// Clears also the internal processing buffers. +// +// Note: This function is meant for extracting the last samples of a sound +// stream. This function may introduce additional blank samples in the end +// of the sound stream, and thus it's not recommended to call this function +// in the middle of a sound stream. +void SoundTouch::flush() +{ + int i; + uint nOut; + SAMPLETYPE buff[128]; + + nOut = numSamples(); + + memset(buff, 0, 128 * sizeof(SAMPLETYPE)); + // "Push" the last active samples out from the processing pipeline by + // feeding blank samples into the processing pipeline until new, + // processed samples appear in the output (not however, more than + // 8ksamples in any case) + for (i = 0; i < 128; i ++) + { + putSamples(buff, 64); + if (numSamples() != nOut) break; // new samples have appeared in the output! + } + + // Clear working buffers + pRateTransposer->clear(); + pTDStretch->clearInput(); + // yet leave the 'tempoChanger' output intouched as that's where the + // flushed samples are! +} + + +// Changes a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +BOOL SoundTouch::setSetting(uint settingId, uint value) +{ + uint sampleRate, sequenceMs, seekWindowMs, overlapMs; + + // read current tdstretch routine parameters + pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + // enables / disabless anti-alias filter + pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_AA_FILTER_LENGTH : + // sets anti-alias filter length + pRateTransposer->getAAFilter()->setLength(value); + return TRUE; + + case SETTING_USE_QUICKSEEK : + // enables / disables tempo routine quick seeking algorithm + pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE); + return TRUE; + + case SETTING_SEQUENCE_MS: + // change time-stretch sequence duration parameter + pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); + return TRUE; + + case SETTING_SEEKWINDOW_MS: + // change time-stretch seek window length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); + return TRUE; + + case SETTING_OVERLAP_MS: + // change time-stretch overlap length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); + return TRUE; + + default : + return FALSE; + } +} + + +// Reads a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +// +// Returns the setting value. +uint SoundTouch::getSetting(uint settingId) const +{ + uint temp; + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + return pRateTransposer->isAAFilterEnabled(); + + case SETTING_AA_FILTER_LENGTH : + return pRateTransposer->getAAFilter()->getLength(); + + case SETTING_USE_QUICKSEEK : + return pTDStretch->isQuickSeekEnabled(); + + case SETTING_SEQUENCE_MS: + pTDStretch->getParameters(NULL, &temp, NULL, NULL); + return temp; + + case SETTING_SEEKWINDOW_MS: + pTDStretch->getParameters(NULL, NULL, &temp, NULL); + return temp; + + case SETTING_OVERLAP_MS: + pTDStretch->getParameters(NULL, NULL, NULL, &temp); + return temp; + + default : + return 0; + } +} + + +// Clears all the samples in the object's output and internal processing +// buffers. +void SoundTouch::clear() +{ + pRateTransposer->clear(); + pTDStretch->clear(); +} + + + +/// Returns number of samples currently unprocessed. +uint SoundTouch::numUnprocessedSamples() const +{ + FIFOSamplePipe * psp; + if (pTDStretch) + { + psp = pTDStretch->getInput(); + if (psp) + { + return psp->numSamples(); + } + } + return 0; +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.h b/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.h new file mode 100644 index 0000000000..fab3bb9845 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/SoundTouch.h @@ -0,0 +1,252 @@ +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.14 $ +// +// $Id: SoundTouch.h,v 1.14 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef SoundTouch_H +#define SoundTouch_H + +#include "FIFOSamplePipe.h" +#include "STTypes.h" + +namespace soundtouch +{ + +/// Soundtouch library version string +#define SOUNDTOUCH_VERSION "1.3.1" + +/// SoundTouch library version id +#define SOUNDTOUCH_VERSION_ID 010301 + +// +// Available setting IDs for the 'setSetting' & 'get_setting' functions: + +/// Enable/disable anti-alias filter in pitch transposer (0 = disable) +#define SETTING_USE_AA_FILTER 0 + +/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) +#define SETTING_AA_FILTER_LENGTH 1 + +/// Enable/disable quick seeking algorithm in tempo changer routine +/// (enabling quick seeking lowers CPU utilization but causes a minor sound +/// quality compromising) +#define SETTING_USE_QUICKSEEK 2 + +/// Time-stretch algorithm single processing sequence length in milliseconds. This determines +/// to how long sequences the original sound is chopped in the time-stretch algorithm. +/// See "STTypes.h" or README for more information. +#define SETTING_SEQUENCE_MS 3 + +/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the +/// best possible overlapping location. This determines from how wide window the algorithm +/// may look for an optimal joining location when mixing the sound sequences back together. +/// See "STTypes.h" or README for more information. +#define SETTING_SEEKWINDOW_MS 4 + +/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences +/// are mixed back together, to form a continuous sound stream, this parameter defines over +/// how long period the two consecutive sequences are let to overlap each other. +/// See "STTypes.h" or README for more information. +#define SETTING_OVERLAP_MS 5 + + +class SoundTouch : public FIFOProcessor +{ +private: + /// Rate transposer class instance + class RateTransposer *pRateTransposer; + + /// Time-stretch class instance + class TDStretch *pTDStretch; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualRate; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualTempo; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + float virtualPitch; + + /// Flag: Has sample rate been set? + BOOL bSrateSet; + + /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and + /// 'virtualPitch' parameters. + void calcEffectiveRateAndTempo(); + +protected : + /// Number of channels + uint channels; + + /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float rate; + + /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + float tempo; + +public: + SoundTouch(); + virtual ~SoundTouch(); + + /// Get SoundTouch library version string + static const char *getVersionString(); + + /// Get SoundTouch library version Id + static uint getVersionId(); + + /// Sets new rate control value. Normal rate = 1.0, smaller values + /// represent slower rate, larger faster rates. + void setRate(float newRate); + + /// Sets new tempo control value. Normal tempo = 1.0, smaller values + /// represent slower tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Sets new rate control value as a difference in percents compared + /// to the original rate (-50 .. +100 %) + void setRateChange(float newRate); + + /// Sets new tempo control value as a difference in percents compared + /// to the original tempo (-50 .. +100 %) + void setTempoChange(float newTempo); + + /// Sets new pitch control value. Original pitch = 1.0, smaller values + /// represent lower pitches, larger values higher pitch. + void setPitch(float newPitch); + + /// Sets pitch change in octaves compared to the original pitch + /// (-1.00 .. +1.00) + void setPitchOctaves(float newPitch); + + /// Sets pitch change in semi-tones compared to the original pitch + /// (-12 .. +12) + void setPitchSemiTones(int newPitch); + void setPitchSemiTones(float newPitch); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Sets sample rate. + void setSampleRate(uint srate); + + /// Flushes the last samples from the processing pipeline to the output. + /// Clears also the internal processing buffers. + // + /// Note: This function is meant for extracting the last samples of a sound + /// stream. This function may introduce additional blank samples in the end + /// of the sound stream, and thus it's not recommended to call this function + /// in the middle of a sound stream. + void flush(); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. Notice that sample rate _has_to_ be set before + /// calling this function, otherwise throws a runtime_error exception. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Pointer to sample buffer. + uint numSamples ///< Number of samples in buffer. Notice + ///< that in case of stereo-sound a single sample + ///< contains data for both channels. + ); + + /// Clears all the samples in the object's output and internal processing + /// buffers. + virtual void clear(); + + /// Changes a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return 'TRUE' if the setting was succesfully changed + BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines. + uint value ///< New setting value. + ); + + /// Reads a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return the setting value. + uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines. + ) const; + + /// Returns number of samples currently unprocessed. + virtual uint numUnprocessedSamples() const; + + + /// Other handy functions that are implemented in the ancestor classes (see + /// classes 'FIFOProcessor' and 'FIFOSamplePipe') + /// + /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. + /// - numSamples() : Get number of 'ready' samples that can be received with + /// function 'receiveSamples()' + /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. + /// - clear() : Clears all samples from ready/processing buffers. +}; + +} +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.cpp b/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.cpp new file mode 100644 index 0000000000..d809623689 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.cpp @@ -0,0 +1,940 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like +/// method with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific +/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.24 $ +// +// $Id: TDStretch.cpp,v 1.24 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include "STTypes.h" +#include "cpu_detect.h" +#include "TDStretch.h" + +using namespace soundtouch; + +#ifndef min +#define min(a,b) ((a > b) ? b : a) +#define max(a,b) ((a < b) ? b : a) +#endif + + + +/***************************************************************************** + * + * Constant definitions + * + *****************************************************************************/ + + +// Table for the hierarchical mixing position seeking algorithm +int scanOffsets[4][24]={ + { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, + 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0}, + {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/***************************************************************************** + * + * Implementation of the class 'TDStretch' + * + *****************************************************************************/ + + +TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) +{ + bQuickseek = FALSE; + channels = 2; + bMidBufferDirty = FALSE; + + pMidBuffer = NULL; + pRefMidBufferUnaligned = NULL; + overlapLength = 0; + + setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); + + setTempo(1.0f); +} + + + + +TDStretch::~TDStretch() +{ + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; +} + + + +// Calculates the x having the closest 2^x value for the given value +static int _getClosest2Power(double value) +{ + return (int)(log(value) / log(2.0) + 0.5); +} + + + +// Sets routine control parameters. These control are certain time constants +// defining how the sound is stretched to the desired duration. +// +// 'sampleRate' = sample rate of the sound +// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) +// 'seekwindowMS' = seeking window length for scanning the best overlapping +// position (default = 28 ms) +// 'overlapMS' = overlapping length (default = 12 ms) + +void TDStretch::setParameters(uint aSampleRate, uint aSequenceMS, + uint aSeekWindowMS, uint aOverlapMS) +{ + this->sampleRate = aSampleRate; + this->sequenceMs = aSequenceMS; + this->seekWindowMs = aSeekWindowMS; + this->overlapMs = aOverlapMS; + + seekLength = (sampleRate * seekWindowMs) / 1000; + seekWindowLength = (sampleRate * sequenceMs) / 1000; + + maxOffset = seekLength; + + calculateOverlapLength(overlapMs); + + // set tempo to recalculate 'sampleReq' + setTempo(tempo); + +} + + + +/// Get routine control parameters, see setParameters() function. +/// Any of the parameters to this function can be NULL, in such case corresponding parameter +/// value isn't returned. +void TDStretch::getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs) +{ + if (pSampleRate) + { + *pSampleRate = sampleRate; + } + + if (pSequenceMs) + { + *pSequenceMs = sequenceMs; + } + + if (pSeekWindowMs) + { + *pSeekWindowMs = seekWindowMs; + } + + if (pOverlapMs) + { + *pOverlapMs = overlapMs; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input' +void TDStretch::overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const +{ + int i, itemp; + + for (i = 0; i < (int)overlapLength ; i ++) + { + itemp = overlapLength - i; + output[i] = (input[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits; + } +} + + + +void TDStretch::clearMidBuffer() +{ + if (bMidBufferDirty) + { + memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = FALSE; + } +} + + +void TDStretch::clearInput() +{ + inputBuffer.clear(); + clearMidBuffer(); +} + + +// Clears the sample buffers +void TDStretch::clear() +{ + outputBuffer.clear(); + inputBuffer.clear(); + clearMidBuffer(); +} + + + +// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero +// to enable +void TDStretch::enableQuickSeek(BOOL enable) +{ + bQuickseek = enable; +} + + +// Returns nonzero if the quick seeking algorithm is enabled. +BOOL TDStretch::isQuickSeekEnabled() const +{ + return bQuickseek; +} + + +// Seeks for the optimal overlap-mixing position. +uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) +{ + if (channels == 2) + { + // stereo sound + if (bQuickseek) + { + return seekBestOverlapPositionStereoQuick(refPos); + } + else + { + return seekBestOverlapPositionStereo(refPos); + } + } + else + { + // mono sound + if (bQuickseek) + { + return seekBestOverlapPositionMonoQuick(refPos); + } + else + { + return seekBestOverlapPositionMono(refPos); + } + } +} + + + + +// Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position +// of 'ovlPos'. +inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const +{ + if (channels == 2) + { + // stereo sound + overlapStereo(output, input + 2 * ovlPos); + } else { + // mono sound. + overlapMono(output, input + ovlPos); + } +} + + + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint i; + + // Slopes the amplitudes of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (i = 0; i < seekLength; i ++) + { + // Calculates correlation value for the mixing position corresponding + // to 'i' + corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = i; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceStereo(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos) +{ + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint tempOffset; + const SAMPLETYPE *compare; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + for (tempOffset = 0; tempOffset < seekLength; tempOffset ++) + { + compare = refPos + tempOffset; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(pRefMidBuffer, compare); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Seeks for the optimal overlap-mixing position. The 'mono' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +uint TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos) +{ + uint j; + uint bestOffs; + LONG_SAMPLETYPE bestCorr, corr; + uint scanCount, corrOffset, tempOffset; + + // Slopes the amplitude of the 'midBuffer' samples + precalcCorrReferenceMono(); + + bestCorr = INT_MIN; + bestOffs = 0; + corrOffset = 0; + tempOffset = 0; + + // Scans for the best correlation value using four-pass hierarchical search. + // + // The look-up table 'scans' has hierarchical position adjusting steps. + // In first pass the routine searhes for the highest correlation with + // relatively coarse steps, then rescans the neighbourhood of the highest + // correlation with better resolution and so on. + for (scanCount = 0;scanCount < 4; scanCount ++) + { + j = 0; + while (scanOffsets[scanCount][j]) + { + tempOffset = corrOffset + scanOffsets[scanCount][j]; + if (tempOffset >= seekLength) break; + + // Calculates correlation value for the mixing position corresponding + // to 'tempOffset' + corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = tempOffset; + } + j ++; + } + corrOffset = bestOffs; + } + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +/// clear cross correlation routine state if necessary +void TDStretch::clearCrossCorrState() +{ + // default implementation is empty. +} + + +// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower +// tempo, larger faster tempo. +void TDStretch::setTempo(float newTempo) +{ + uint intskip; + + tempo = newTempo; + + // Calculate ideal skip length (according to tempo value) + nominalSkip = tempo * (seekWindowLength - overlapLength); + skipFract = 0; + intskip = (int)(nominalSkip + 0.5f); + + // Calculate how many samples are needed in the 'inputBuffer' to + // process another batch of samples + sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset; +} + + + +// Sets the number of channels, 1 = mono, 2 = stereo +void TDStretch::setChannels(uint numChannels) +{ + if (channels == numChannels) return; + assert(numChannels == 1 || numChannels == 2); + + channels = numChannels; + inputBuffer.setChannels(channels); + outputBuffer.setChannels(channels); +} + + +// nominal tempo, no need for processing, just pass the samples through +// to outputBuffer +void TDStretch::processNominalTempo() +{ + assert(tempo == 1.0f); + + if (bMidBufferDirty) + { + // If there are samples in pMidBuffer waiting for overlapping, + // do a single sliding overlapping with them in order to prevent a + // clicking distortion in the output sound + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength input samples + return; + } + // Mix the samples in the beginning of 'inputBuffer' with the + // samples in 'midBuffer' using sliding overlapping + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); + outputBuffer.putSamples(overlapLength); + inputBuffer.receiveSamples(overlapLength); + clearMidBuffer(); + // now we've caught the nominal sample flow and may switch to + // bypass mode + } + + // Simply bypass samples from input to output + outputBuffer.moveSamples(inputBuffer); +} + + +// Processes as many processing frames of the samples 'inputBuffer', store +// the result into 'outputBuffer' +void TDStretch::processSamples() +{ + uint ovlSkip, offset; + int temp; + + /* Removed this small optimization - can introduce a click to sound when tempo setting + crosses the nominal value + if (tempo == 1.0f) + { + // tempo not changed from the original, so bypass the processing + processNominalTempo(); + return; + } + */ + + if (bMidBufferDirty == FALSE) + { + // if midBuffer is empty, move the first samples of the input stream + // into it + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength samples + return; + } + memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE)); + inputBuffer.receiveSamples(overlapLength); + bMidBufferDirty = TRUE; + } + + // Process samples as long as there are enough samples in 'inputBuffer' + // to form a processing frame. + while (inputBuffer.numSamples() >= sampleReq) + { + // If tempo differs from the normal ('SCALE'), scan for the best overlapping + // position + offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); + + // Mix the samples in the 'inputBuffer' at position of 'offset' with the + // samples in 'midBuffer' using sliding overlapping + // ... first partially overlap with the end of the previous sequence + // (that's in 'midBuffer') + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset); + outputBuffer.putSamples(overlapLength); + + // ... then copy sequence samples from 'inputBuffer' to output + temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe; + if (temp > 0) + { + outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp); + } + + // Copies the end of the current sequence from 'inputBuffer' to + // 'midBuffer' for being mixed with the beginning of the next + // processing sequence and so on + assert(offset + seekWindowLength <= inputBuffer.numSamples()); + memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength), + channels * sizeof(SAMPLETYPE) * overlapLength); + bMidBufferDirty = TRUE; + + // Remove the processed samples from the input buffer. Update + // the difference between integer & nominal skip step to 'skipFract' + // in order to prevent the error from accumulating over time. + skipFract += nominalSkip; // real skip size + ovlSkip = (int)skipFract; // rounded to integer skip + skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip + inputBuffer.receiveSamples(ovlSkip); + } +} + + +// Adds 'numsamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples) +{ + // Add the samples into the input buffer + inputBuffer.putSamples(samples, numSamples); + // Process the samples in input buffer + processSamples(); +} + + + +/// Set new overlap length parameter & reallocate RefMidBuffer if necessary. +void TDStretch::acceptNewOverlapLength(uint newOverlapLength) +{ + uint prevOvl; + + prevOvl = overlapLength; + overlapLength = newOverlapLength; + + if (overlapLength > prevOvl) + { + delete[] pMidBuffer; + delete[] pRefMidBufferUnaligned; + + pMidBuffer = new SAMPLETYPE[overlapLength * 2]; + bMidBufferDirty = TRUE; + clearMidBuffer(); + + pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)]; + // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency + pRefMidBuffer = (SAMPLETYPE *)((((ulongptr)pRefMidBufferUnaligned) + 15) & -16); + } +} + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * TDStretch::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + assert(FALSE); + return NULL; +} + + +TDStretch * TDStretch::newInstance() +{ + uint uExtensions = 0; + +#if !defined(_MSC_VER) || !defined(__x86_64__) + uExtensions = detectCPUextensions(); +#endif + + // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + +#ifdef ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new TDStretchMMX; + } + else +#endif // ALLOW_MMX + + +#ifdef ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new TDStretchSSE; + } + else +#endif // ALLOW_SSE + + +#ifdef ALLOW_3DNOW + if (uExtensions & SUPPORT_3DNOW) + { + // 3DNow! support + return ::new TDStretch3DNow; + } + else +#endif // ALLOW_3DNOW + + { + // ISA optimizations not supported, use plain C version + return ::new TDStretch; + } +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Integer arithmetics specific algorithm implementations. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef INTEGER_SAMPLES + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + int temp, temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + cnt2 = i * 2; + + temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider; + pRefMidBuffer[cnt2] = (short)(temp2); + temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider; + pRefMidBuffer[cnt2 + 1] = (short)(temp2); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + long temp; + long temp2; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = i * (overlapLength - i); + temp2 = (pMidBuffer[i] * temp) / slopingDivider; + pRefMidBuffer[i] = (short)temp2; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' +// version of the routine. +void TDStretch::overlapStereo(short *output, const short *input) const +{ + int i; + short temp; + uint cnt2; + + for (i = 0; i < (int)overlapLength ; i ++) + { + temp = (short)(overlapLength - i); + cnt2 = 2 * i; + output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength; + output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength; + } +} + + +/// Calculates overlap period length in samples. +/// Integer version rounds overlap length to closest power of 2 +/// for a divide scaling operation. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0); + if (overlapDividerBits > 9) overlapDividerBits = 9; + if (overlapDividerBits < 4) overlapDividerBits = 4; + newOvl = 1<> overlapDividerBits; + } + + return corr; +} + + +long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const +{ + long corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += (mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; + } + + return corr; +} + +#endif // INTEGER_SAMPLES + +////////////////////////////////////////////////////////////////////////////// +// +// Floating point arithmetics specific algorithm implementations. +// + +#ifdef FLOAT_SAMPLES + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceStereo() +{ + int i, cnt2; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + cnt2 = i * 2; + pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp); + pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp); + } +} + + +// Slopes the amplitude of the 'midBuffer' samples so that cross correlation +// is faster to calculate +void TDStretch::precalcCorrReferenceMono() +{ + int i; + float temp; + + for (i=0 ; i < (int)overlapLength ;i ++) + { + temp = (float)i * (float)(overlapLength - i); + pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp); + } +} + + +// SSE-optimized version of the function overlapStereo +void TDStretch::overlapStereo(float *output, const float *input) const +{ + int i; + uint cnt2; + float fTemp; + float fScale; + float fi; + + fScale = 1.0f / (float)overlapLength; + + for (i = 0; i < (int)overlapLength ; i ++) + { + fTemp = (float)(overlapLength - i) * fScale; + fi = (float)i * fScale; + cnt2 = 2 * i; + output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp; + output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp; + } +} + + +/// Calculates overlap period length in samples. +void TDStretch::calculateOverlapLength(uint overlapMs) +{ + uint newOvl; + + newOvl = (sampleRate * overlapMs) / 1000; + if (newOvl < 16) newOvl = 16; + + // must be divisible by 8 + newOvl -= newOvl % 8; + + acceptNewOverlapLength(newOvl); +} + + + +double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 1; i < overlapLength; i ++) + { + corr += mixingPos[i] * compare[i]; + } + + return corr; +} + + +double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const +{ + double corr; + uint i; + + corr = 0; + for (i = 2; i < 2 * overlapLength; i += 2) + { + corr += mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]; + } + + return corr; +} + +#endif // FLOAT_SAMPLES diff --git a/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.h b/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.h new file mode 100644 index 0000000000..a05a7072fc --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/TDStretch.h @@ -0,0 +1,236 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.16 $ +// +// $Id: TDStretch.h,v 1.16 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TDStretch_H +#define TDStretch_H + +#include "STTypes.h" +#include "RateTransposer.h" +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +// Default values for sound processing parameters: + +/// Default length of a single processing sequence, in milliseconds. This determines to how +/// long sequences the original sound is chopped in the time-stretch algorithm. +/// +/// The larger this value is, the lesser sequences are used in processing. In principle +/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo +/// and vice versa. +/// +/// Increasing this value reduces computational burden & vice versa. +#define DEFAULT_SEQUENCE_MS 61 + +#define DEFAULT_SEEKWINDOW_MS 18 + +#define DEFAULT_OVERLAP_MS 7 + + +/// Class that does the time-stretch (tempo change) effect for the processed +/// sound. +class TDStretch : public FIFOProcessor +{ +protected: + uint channels; + uint sampleReq; + float tempo; + + SAMPLETYPE *pMidBuffer; + SAMPLETYPE *pRefMidBuffer; + SAMPLETYPE *pRefMidBufferUnaligned; + uint overlapLength; + uint overlapDividerBits; + uint slopingDivider; + uint seekLength; + uint seekWindowLength; + uint maxOffset; + float nominalSkip; + float skipFract; + FIFOSampleBuffer outputBuffer; + FIFOSampleBuffer inputBuffer; + BOOL bQuickseek; + BOOL bMidBufferDirty; + + uint sampleRate; + uint sequenceMs; + uint seekWindowMs; + uint overlapMs; + + void acceptNewOverlapLength(uint newOverlapLength); + + virtual void clearCrossCorrState(); + void calculateOverlapLength(uint overlapMs); + + virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + + virtual uint seekBestOverlapPositionStereo(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMono(const SAMPLETYPE *refPos); + virtual uint seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos); + uint seekBestOverlapPosition(const SAMPLETYPE *refPos); + + virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; + virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; + + void clearMidBuffer(); + void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; + + void precalcCorrReferenceMono(); + void precalcCorrReferenceStereo(); + + void processNominalTempo(); + + /// Changes the tempo of the given sound samples. + /// Returns amount of samples returned in the "output" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(); + +public: + TDStretch(); + virtual ~TDStretch(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX/SSE/etc-capable CPU available or not. + void *operator new(size_t s); + + /// Use this function instead of "new" operator to create a new instance of this class. + /// This function automatically chooses a correct feature set depending on if the CPU + /// supports MMX/SSE/etc extensions. + static TDStretch *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the input buffer object + FIFOSamplePipe *getInput() { return &inputBuffer; }; + + /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower + /// tempo, larger faster tempo. + void setTempo(float newTempo); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual void clear(); + + /// Clears the input buffer + void clearInput(); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Enables/disables the quick position seeking algorithm. Zero to disable, + /// nonzero to enable + void enableQuickSeek(BOOL enable); + + /// Returns nonzero if the quick seeking algorithm is enabled. + BOOL isQuickSeekEnabled() const; + + /// Sets routine control parameters. These control are certain time constants + /// defining how the sound is stretched to the desired duration. + // + /// 'sampleRate' = sample rate of the sound + /// 'sequenceMS' = one processing sequence length in milliseconds + /// 'seekwindowMS' = seeking window length for scanning the best overlapping + /// position + /// 'overlapMS' = overlapping length + void setParameters(uint sampleRate, ///< Samplerate of sound being processed (Hz) + uint sequenceMS = DEFAULT_SEQUENCE_MS, ///< Single processing sequence length (ms) + uint seekwindowMS = DEFAULT_SEEKWINDOW_MS, ///< Offset seeking window length (ms) + uint overlapMS = DEFAULT_OVERLAP_MS ///< Sequence overlapping length (ms) + ); + + /// Get routine control parameters, see setParameters() function. + /// Any of the parameters to this function can be NULL, in such case corresponding parameter + /// value isn't returned. + void getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs); + + /// Adds 'numsamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Input sample data + uint numSamples ///< Number of samples in 'samples' so that one sample + ///< contains both channels if stereo + ); +}; + + + +// Implementation-specific class declarations: + +//#ifdef ALLOW_MMX +// /// Class that implements MMX optimized routines for 16bit integer samples type. +// class TDStretchMMX : public TDStretch +// { +// protected: +// long calcCrossCorrStereo(const short *mixingPos, const short *compare) const; +// virtual void overlapStereo(short *output, const short *input) const; +// virtual void clearCrossCorrState(); +// }; +//#endif /// ALLOW_MMX +// +// +//#ifdef ALLOW_3DNOW +// /// Class that implements 3DNow! optimized routines for floating point samples type. +// class TDStretch3DNow : public TDStretch +// { +// protected: +// double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; +// }; +//#endif /// ALLOW_3DNOW + + +#ifdef ALLOW_SSE + /// Class that implements SSE optimized routines for floating point samples type. + class TDStretchSSE : public TDStretch + { + protected: + double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; + }; + +#endif /// ALLOW_SSE + +} +#endif /// TDStretch_H diff --git a/plugins/zerospu2/3rdparty/SoundTouch/WavFile.cpp b/plugins/zerospu2/3rdparty/SoundTouch/WavFile.cpp new file mode 100644 index 0000000000..77db8cc431 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/WavFile.cpp @@ -0,0 +1,714 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, +/// but the reason for 'yet another' one is that those generic WAV reader +/// libraries are exhaustingly large and cumbersome! Wanted to have something +/// simpler here, i.e. something that's not already larger than rest of the +/// SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.15 $ +// +// $Id: WavFile.cpp,v 1.15 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include +#include + +#include "WavFile.h" + +using namespace std; + +const static char riffStr[] = "RIFF"; +const static char waveStr[] = "WAVE"; +const static char fmtStr[] = "fmt "; +const static char dataStr[] = "data"; + + +////////////////////////////////////////////////////////////////////////////// +// +// Helper functions for swapping byte order to correctly read/write WAV files +// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to +// turn-on the conversion if it appears necessary. +// +// For example, Intel x86 is little-endian and doesn't require conversion, +// while PowerPC of Mac's and many other RISC cpu's are big-endian. + +#ifdef BYTE_ORDER + // In gcc compiler detect the byte order automatically + #if BYTE_ORDER == BIG_ENDIAN + // big-endian platform. + #define _BIG_ENDIAN_ + #endif +#endif + +#ifdef _BIG_ENDIAN_ + // big-endian CPU, swap bytes in 16 & 32 bit words + + // helper-function to swap byte-order of 32bit integer + static inline void _swap32(unsigned int &dwData) + { + dwData = ((dwData >> 24) & 0x000000FF) | + ((dwData >> 8) & 0x0000FF00) | + ((dwData << 8) & 0x00FF0000) | + ((dwData << 24) & 0xFF000000); + } + + // helper-function to swap byte-order of 16bit integer + static inline void _swap16(unsigned short &wData) + { + wData = ((wData >> 8) & 0x00FF) | + ((wData << 8) & 0xFF00); + } + + // helper-function to swap byte-order of buffer of 16bit integers + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords) + { + unsigned long i; + + for (i = 0; i < dwNumWords; i ++) + { + _swap16(pData[i]); + } + } + +#else // BIG_ENDIAN + // little-endian CPU, WAV file is ok as such + + // dummy helper-function + static inline void _swap32(unsigned int &dwData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16(unsigned short &wData) + { + // do nothing + } + + // dummy helper-function + static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) + { + // do nothing + } + +#endif // BIG_ENDIAN + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavInFile +// + +WavInFile::WavInFile(const char *fileName) +{ + int hdrsOk; + + // Try to open the file for reading + fptr = fopen(fileName, "rb"); + if (fptr == NULL) + { + // didn't succeed + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for reading."; + throw runtime_error(msg); + } + + // Read the file headers + hdrsOk = readWavHeaders(); + if (hdrsOk != 0) + { + // Something didn't match in the wav file headers + string msg = "File \""; + msg += fileName; + msg += "\" is corrupt or not a WAV file"; + throw runtime_error(msg); + } + + if (header.format.fixed != 1) + { + string msg = "File \""; + msg += fileName; + msg += "\" uses unsupported encoding."; + throw runtime_error(msg); + } + + dataRead = 0; +} + + + +WavInFile::~WavInFile() +{ + close(); +} + + + +void WavInFile::rewind() +{ + int hdrsOk; + + fseek(fptr, 0, SEEK_SET); + hdrsOk = readWavHeaders(); + assert(hdrsOk == 0); + dataRead = 0; +} + + +int WavInFile::checkCharTags() +{ + // header.format.fmt should equal to 'fmt ' + if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; + // header.data.data_field should equal to 'data' + if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; + + return 0; +} + + +int WavInFile::read(char *buffer, int maxElems) +{ + int numBytes; + uint afterDataRead; + + // ensure it's 8 bit format + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples."); + } + assert(sizeof(char) == 1); + + numBytes = maxElems; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + + return numBytes; +} + + +int WavInFile::read(short *buffer, int maxElems) +{ + unsigned int afterDataRead; + int numBytes; + int numElems; + + if (header.format.bits_per_sample == 8) + { + // 8 bit format + char *temp = new char[maxElems]; + int i; + + numElems = read(temp, maxElems); + // convert from 8 to 16 bit + for (i = 0; i < numElems; i ++) + { + buffer[i] = temp[i] << 8; + } + delete[] temp; + } + else + { + // 16 bit format + assert(header.format.bits_per_sample == 16); + assert(sizeof(short) == 2); + + numBytes = maxElems * 2; + afterDataRead = dataRead + numBytes; + if (afterDataRead > header.data.data_len) + { + // Don't read more samples than are marked available in header + numBytes = header.data.data_len - dataRead; + assert(numBytes >= 0); + } + + numBytes = fread(buffer, 1, numBytes, fptr); + dataRead += numBytes; + numElems = numBytes / 2; + + // 16bit samples, swap byte order if necessary + _swap16Buffer((unsigned short *)buffer, numElems); + } + + return numElems; +} + + + +int WavInFile::read(float *buffer, int maxElems) +{ + short *temp = new short[maxElems]; + int num; + int i; + double fscale; + + num = read(temp, maxElems); + + fscale = 1.0 / 32768.0; + // convert to floats, scale to range [-1..+1[ + for (i = 0; i < num; i ++) + { + buffer[i] = (float)(fscale * (double)temp[i]); + } + + delete[] temp; + + return num; +} + + +int WavInFile::eof() const +{ + // return true if all data has been read or file eof has reached + return (dataRead == header.data.data_len || feof(fptr)); +} + + +void WavInFile::close() +{ + fclose(fptr); + fptr = NULL; +} + + + +// test if character code is between a white space ' ' and little 'z' +static int isAlpha(char c) +{ + return (c >= ' ' && c <= 'z') ? 1 : 0; +} + + +// test if all characters are between a white space ' ' and little 'z' +static int isAlphaStr(char *str) +{ + int c; + + c = str[0]; + while (c) + { + if (isAlpha(c) == 0) return 0; + str ++; + c = str[0]; + } + + return 1; +} + + +int WavInFile::readRIFFBlock() +{ + fread(&(header.riff), sizeof(WavRiff), 1, fptr); + + // swap 32bit data byte order if necessary + _swap32((unsigned int &)header.riff.package_len); + + // header.riff.riff_char should equal to 'RIFF'); + if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; + // header.riff.wave should equal to 'WAVE' + if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; + + return 0; +} + + + + +int WavInFile::readHeaderBlock() +{ + char label[5]; + string sLabel; + + // lead label string + fread(label, 1, 4, fptr); + label[4] = 0; + + if (isAlphaStr(label) == 0) return -1; // not a valid label + + // Decode blocks according to their label + if (strcmp(label, fmtStr) == 0) + { + int nLen, nDump; + + // 'fmt ' block + memcpy(header.format.fmt, fmtStr, 4); + + // read length of the format field + fread(&nLen, sizeof(int), 1, fptr); + // swap byte order if necessary + _swap32((unsigned int &)nLen); // int format_len; + header.format.format_len = nLen; + + // calculate how much length differs from expected + nDump = nLen - (sizeof(header.format) - 8); + + // if format_len is larger than expected, read only as much data as we've space for + if (nDump > 0) + { + nLen = sizeof(header.format) - 8; + } + + // read data + fread(&(header.format.fixed), nLen, 1, fptr); + + // swap byte order if necessary + _swap16((unsigned short &)header.format.fixed); // short int fixed; + _swap16((unsigned short &)header.format.channel_number); // short int channel_number; + _swap32((unsigned int &)header.format.sample_rate); // int sample_rate; + _swap32((unsigned int &)header.format.byte_rate); // int byte_rate; + _swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample; + _swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample; + + // if format_len is larger than expected, skip the extra data + if (nDump > 0) + { + fseek(fptr, nDump, SEEK_CUR); + } + + return 0; + } + else if (strcmp(label, dataStr) == 0) + { + // 'data' block + memcpy(header.data.data_field, dataStr, 4); + fread(&(header.data.data_len), sizeof(uint), 1, fptr); + + // swap byte order if necessary + _swap32((unsigned int &)header.data.data_len); + + return 1; + } + else + { + uint len, i; + uint temp; + // unknown block + + // read length + fread(&len, sizeof(len), 1, fptr); + // scan through the block + for (i = 0; i < len; i ++) + { + fread(&temp, 1, 1, fptr); + if (feof(fptr)) return -1; // unexpected eof + } + } + return 0; +} + + +int WavInFile::readWavHeaders() +{ + int res; + + memset(&header, 0, sizeof(header)); + + res = readRIFFBlock(); + if (res) return 1; + // read header blocks until data block is found + do + { + // read header blocks + res = readHeaderBlock(); + if (res < 0) return 1; // error in file structure + } while (res == 0); + // check that all required tags are legal + return checkCharTags(); +} + + +uint WavInFile::getNumChannels() const +{ + return header.format.channel_number; +} + + +uint WavInFile::getNumBits() const +{ + return header.format.bits_per_sample; +} + + +uint WavInFile::getBytesPerSample() const +{ + return getNumChannels() * getNumBits() / 8; +} + + +uint WavInFile::getSampleRate() const +{ + return header.format.sample_rate; +} + + + +uint WavInFile::getDataSizeInBytes() const +{ + return header.data.data_len; +} + + +uint WavInFile::getNumSamples() const +{ + return header.data.data_len / header.format.byte_per_sample; +} + + +uint WavInFile::getLengthMS() const +{ + uint numSamples; + uint sampleRate; + + numSamples = getNumSamples(); + sampleRate = getSampleRate(); + + assert(numSamples < UINT_MAX / 1000); + return (1000 * numSamples / sampleRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Class WavOutFile +// + +WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) +{ + bytesWritten = 0; + fptr = fopen(fileName, "wb"); + if (fptr == NULL) + { + string msg = "Error : Unable to open file \""; + msg += fileName; + msg += "\" for writing."; + //pmsg = msg.c_str; + throw runtime_error(msg); + } + + fillInHeader(sampleRate, bits, channels); + writeHeader(); +} + + + +WavOutFile::~WavOutFile() +{ + close(); +} + + + +void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) +{ + // fill in the 'riff' part.. + + // copy string 'RIFF' to riff_char + memcpy(&(header.riff.riff_char), riffStr, 4); + // package_len unknown so far + header.riff.package_len = 0; + // copy string 'WAVE' to wave + memcpy(&(header.riff.wave), waveStr, 4); + + + // fill in the 'format' part.. + + // copy string 'fmt ' to fmt + memcpy(&(header.format.fmt), fmtStr, 4); + + header.format.format_len = 0x10; + header.format.fixed = 1; + header.format.channel_number = (short)channels; + header.format.sample_rate = sampleRate; + header.format.bits_per_sample = (short)bits; + header.format.byte_per_sample = (short)(bits * channels / 8); + header.format.byte_rate = header.format.byte_per_sample * sampleRate; + header.format.sample_rate = sampleRate; + + // fill in the 'data' part.. + + // copy string 'data' to data_field + memcpy(&(header.data.data_field), dataStr, 4); + // data_len unknown so far + header.data.data_len = 0; +} + + +void WavOutFile::finishHeader() +{ + // supplement the file length into the header structure + header.riff.package_len = bytesWritten + 36; + header.data.data_len = bytesWritten; + + writeHeader(); +} + + + +void WavOutFile::writeHeader() +{ + WavHeader hdrTemp; + + // swap byte order if necessary + hdrTemp = header; + _swap32((unsigned int &)hdrTemp.riff.package_len); + _swap32((unsigned int &)hdrTemp.format.format_len); + _swap16((unsigned short &)hdrTemp.format.fixed); + _swap16((unsigned short &)hdrTemp.format.channel_number); + _swap32((unsigned int &)hdrTemp.format.sample_rate); + _swap32((unsigned int &)hdrTemp.format.byte_rate); + _swap16((unsigned short &)hdrTemp.format.byte_per_sample); + _swap16((unsigned short &)hdrTemp.format.bits_per_sample); + _swap32((unsigned int &)hdrTemp.data.data_len); + + // write the supplemented header in the beginning of the file + fseek(fptr, 0, SEEK_SET); + fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); + // jump back to the end of the file + fseek(fptr, 0, SEEK_END); +} + + + +void WavOutFile::close() +{ + finishHeader(); + fclose(fptr); + fptr = NULL; +} + + +void WavOutFile::write(const char *buffer, int numElems) +{ + int res; + + if (header.format.bits_per_sample != 8) + { + throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples."); + } + assert(sizeof(char) == 1); + + res = fwrite(buffer, 1, numElems, fptr); + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + + bytesWritten += numElems; +} + + +void WavOutFile::write(const short *buffer, int numElems) +{ + int res; + + // 16 bit samples + if (numElems < 1) return; // nothing to do + + if (header.format.bits_per_sample == 8) + { + int i; + char *temp = new char[numElems]; + // convert from 16bit format to 8bit format + for (i = 0; i < numElems; i ++) + { + temp[i] = buffer[i] >> 8; + } + // write in 8bit format + write(temp, numElems); + delete[] temp; + } + else + { + // 16bit format + unsigned short *pTemp = new unsigned short[numElems]; + + assert(header.format.bits_per_sample == 16); + + // allocate temp buffer to swap byte order if necessary + memcpy(pTemp, buffer, numElems * 2); + _swap16Buffer(pTemp, numElems); + + res = fwrite(pTemp, 2, numElems, fptr); + + delete[] pTemp; + + if (res != numElems) + { + throw runtime_error("Error while writing to a wav file."); + } + bytesWritten += 2 * numElems; + } +} + + +void WavOutFile::write(const float *buffer, int numElems) +{ + int i; + short *temp = new short[numElems]; + int iTemp; + + // convert to 16 bit integer + for (i = 0; i < numElems; i ++) + { + // convert to integer + iTemp = (int)(32768.0f * buffer[i]); + + // saturate + if (iTemp < -32768) iTemp = -32768; + if (iTemp > 32767) iTemp = 32767; + temp[i] = (short)iTemp; + } + + write(temp, numElems); + + delete[] temp; +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/WavFile.h b/plugins/zerospu2/3rdparty/SoundTouch/WavFile.h new file mode 100644 index 0000000000..dd239034d2 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/WavFile.h @@ -0,0 +1,253 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Classes for easy reading & writing of WAV sound files. +/// +/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly +/// parse the WAV files with such processors. +/// +/// Admittingly, more complete WAV reader routines may exist in public domain, but +/// the reason for 'yet another' one is that those generic WAV reader libraries are +/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. +/// something that's not already larger than rest of the SoundTouch/SoundStretch program... +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.7 $ +// +// $Id: WavFile.h,v 1.7 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef WAVFILE_H +#define WAVFILE_H + +#include + +#ifndef uint +typedef unsigned int uint; +#endif + + +/// WAV audio file 'riff' section header +typedef struct +{ + char riff_char[4]; + int package_len; + char wave[4]; +} WavRiff; + +/// WAV audio file 'format' section header +typedef struct +{ + char fmt[4]; + int format_len; + short fixed; + short channel_number; + int sample_rate; + int byte_rate; + short byte_per_sample; + short bits_per_sample; +} WavFormat; + +/// WAV audio file 'data' section header +typedef struct +{ + char data_field[4]; + uint data_len; +} WavData; + + +/// WAV audio file header +typedef struct +{ + WavRiff riff; + WavFormat format; + WavData data; +} WavHeader; + + +/// Class for reading WAV audio files. +class WavInFile +{ +private: + /// File pointer. + FILE *fptr; + + /// Counter of how many bytes of sample data have been read from the file. + uint dataRead; + + /// WAV header information + WavHeader header; + + /// Read WAV file headers. + /// \return zero if all ok, nonzero if file format is invalid. + int readWavHeaders(); + + /// Checks WAV file header tags. + /// \return zero if all ok, nonzero if file format is invalid. + int checkCharTags(); + + /// Reads a single WAV file header block. + /// \return zero if all ok, nonzero if file format is invalid. + int readHeaderBlock(); + + /// Reads WAV file 'riff' block + int readRIFFBlock(); + +public: + /// Constructor: Opens the given WAV file. If the file can't be opened, + /// throws 'runtime_error' exception. + WavInFile(const char *filename); + + /// Destructor: Closes the file. + ~WavInFile(); + + /// Close the file. Notice that file is automatically closed also when the + /// class instance is deleted. + void close(); + + /// Rewind to beginning of the file + void rewind(); + + /// Get sample rate. + uint getSampleRate() const; + + /// Get number of bits per sample, i.e. 8 or 16. + uint getNumBits() const; + + /// Get sample data size in bytes. Ahem, this should return same information as + /// 'getBytesPerSample'... + uint getDataSizeInBytes() const; + + /// Get total number of samples in file. + uint getNumSamples() const; + + /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) + uint getBytesPerSample() const; + + /// Get number of audio channels in the file (1=mono, 2=stereo) + uint getNumChannels() const; + + /// Get the audio file length in milliseconds + uint getLengthMS() const; + + /// Reads audio samples from the WAV file. This routine works only for 8 bit samples. + /// Reads given number of elements from the file or if end-of-file reached, as many + /// elements as are left in the file. + /// + /// \return Number of 8-bit integers read from the file. + int read(char *buffer, int maxElems); + + /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number + /// of elements from the file or if end-of-file reached, as many elements as are + /// left in the file. + /// + /// \return Number of 16-bit integers read from the file. + int read(short *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Reads audio samples from the WAV file to floating point format, converting + /// sample values to range [-1,1[. Reads given number of elements from the file + /// or if end-of-file reached, as many elements as are left in the file. + /// + /// \return Number of elements read from the file. + int read(float *buffer, ///< Pointer to buffer where to read data. + int maxElems ///< Size of 'buffer' array (number of array elements). + ); + + /// Check end-of-file. + /// + /// \return Nonzero if end-of-file reached. + int eof() const; +}; + + + +/// Class for writing WAV audio files. +class WavOutFile +{ +private: + /// Pointer to the WAV file + FILE *fptr; + + /// WAV file header data. + WavHeader header; + + /// Counter of how many bytes have been written to the file so far. + int bytesWritten; + + /// Fills in WAV file header information. + void fillInHeader(const uint sampleRate, const uint bits, const uint channels); + + /// Finishes the WAV file header by supplementing information of amount of + /// data written to file etc + void finishHeader(); + + /// Writes the WAV file header. + void writeHeader(); + +public: + /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception + /// if file creation fails. + WavOutFile(const char *fileName, ///< Filename + int sampleRate, ///< Sample rate (e.g. 44100 etc) + int bits, ///< Bits per sample (8 or 16 bits) + int channels ///< Number of channels (1=mono, 2=stereo) + ); + + /// Destructor: Finalizes & closes the WAV file. + ~WavOutFile(); + + /// Write data to WAV file. This function works only with 8bit samples. + /// Throws a 'runtime_error' exception if writing to file fails. + void write(const char *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file. Throws a 'runtime_error' exception if writing to + /// file fails. + void write(const short *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Write data to WAV file in floating point format, saturating sample values to range + /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. + void write(const float *buffer, ///< Pointer to sample data buffer. + int numElems ///< How many array items are to be written to file. + ); + + /// Finalize & close the WAV file. Automatically supplements the WAV file header + /// information according to written data etc. + /// + /// Notice that file is automatically closed also when the class instance is deleted. + void close(); +}; + +#endif diff --git a/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect.h b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect.h new file mode 100644 index 0000000000..568817f17b --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect.h @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A header file for detecting the Intel MMX instructions set extension. +/// +/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the +/// routine implementations for x86 Windows, x86 gnu version and non-x86 +/// platforms, respectively. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.4 $ +// +// $Id: cpu_detect.h,v 1.4 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _CPU_DETECT_H_ +#define _CPU_DETECT_H_ + +#include "STTypes.h" + +#define SUPPORT_MMX 0x0001 +#define SUPPORT_3DNOW 0x0002 +#define SUPPORT_ALTIVEC 0x0004 +#define SUPPORT_SSE 0x0008 +#define SUPPORT_SSE2 0x0010 + +/// Checks which instruction set extensions are supported by the CPU. +/// +/// \return A bitmask of supported extensions, see SUPPORT_... defines. +uint detectCPUextensions(void); + +/// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint wDisableMask); + +#endif // _CPU_DETECT_H_ diff --git a/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp new file mode 100644 index 0000000000..75bd771099 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp @@ -0,0 +1,138 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// gcc version of the x86 CPU detect routine. +/// +/// This file is to be compiled on any platform with the GNU C compiler. +/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version +/// of this file. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.6 $ +// +// $Id: cpu_detect_x86_gcc.cpp,v 1.6 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "cpu_detect.h" + +#ifndef __GNUC__ +#error wrong platform - this source code file is for the GNU C compiler. +#endif + +using namespace std; + +#include +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ +#ifndef __i386__ + return 0; // always disable extensions on non-x86 platforms. +#else + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + asm volatile( + "\n\txor %%esi, %%esi" // clear %%esi = result register + // check if 'cpuid' instructions is available by toggling eflags bit 21 + + "\n\tpushf" // save eflags to stack + "\n\tpop %%eax" // load eax from stack (with eflags) + "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx + "\n\txor $0x00200000, %%eax" // toggle bit 21 + "\n\tpush %%eax" // store toggled eflags to stack + "\n\tpopf" // load eflags from stack + "\n\tpushf" // save updated eflags to stack + "\n\tpop %%eax" // load from stack + "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx + "\n\tcmp %%ecx, %%eax" // compare to original eflags values + "\n\tjz end" // jumps to 'end' if cpuid not present + + // cpuid instruction available, test for presence of mmx instructions + + "\n\tmovl $1, %%eax" + "\n\tcpuid" +// movl $0x00800000, %edx // force enable MMX + "\n\ttest $0x00800000, %%edx" + "\n\tjz end" // branch if MMX not available + + "\n\tor $0x01, %%esi" // otherwise add MMX support bit + + "\n\ttest $0x02000000, %%edx" + "\n\tjz test3DNow" // branch if SSE not available + + "\n\tor $0x08, %%esi" // otherwise add SSE support bit + + "\n\ttest3DNow:" + // test for precense of AMD extensions + "\n\tmov $0x80000000, %%eax" + "\n\tcpuid" + "\n\tcmp $0x80000000, %%eax" + "\n\tjbe end" // branch if no AMD extensions detected + + // test for precense of 3DNow! extension + "\n\tmov $0x80000001, %%eax" + "\n\tcpuid" + "\n\ttest $0x80000000, %%edx" + "\n\tjz end" // branch if 3DNow! not detected + + "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit + + "\n\tend:" + + "\n\tmov %%esi, %0" + + : "=r" (res) + : /* no inputs */ + : "%edx", "%eax", "%ecx", "%esi" ); + + return res & ~_dwDisabledISA; +#endif +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_win.cpp b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_win.cpp new file mode 100644 index 0000000000..d8f9e58dd0 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/cpu_detect_x86_win.cpp @@ -0,0 +1,126 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Win32 version of the x86 CPU detect routine. +/// +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version +/// for all GNU platforms. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.10 $ +// +// $Id: cpu_detect_x86_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" + +#ifndef _WIN32 +#error wrong platform - this source code file is exclusively for Win32 platform +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ + uint res = 0; + + if (_dwDisabledISA == 0xffffffff) return 0; + + _asm + { + ; check if 'cpuid' instructions is available by toggling eflags bit 21 + ; + xor esi, esi ; clear esi = result register + + pushfd ; save eflags to stack + pop eax ; load eax from stack (with eflags) + mov ecx, eax ; save the original eflags values to ecx + xor eax, 0x00200000 ; toggle bit 21 + push eax ; store toggled eflags to stack + popfd ; load eflags from stack + pushfd ; save updated eflags to stack + pop eax ; load from stack + xor edx, edx ; clear edx for defaulting no mmx + cmp eax, ecx ; compare to original eflags values + jz end ; jumps to 'end' if cpuid not present + + ; cpuid instruction available, test for presence of mmx instructions + mov eax, 1 + cpuid + test edx, 0x00800000 + jz end ; branch if MMX not available + + or esi, SUPPORT_MMX ; otherwise add MMX support bit + + test edx, 0x02000000 + jz test3DNow ; branch if SSE not available + + or esi, SUPPORT_SSE ; otherwise add SSE support bit + + test3DNow: + ; test for precense of AMD extensions + mov eax, 0x80000000 + cpuid + cmp eax, 0x80000000 + jbe end ; branch if no AMD extensions detected + + ; test for precense of 3DNow! extension + mov eax, 0x80000001 + cpuid + test edx, 0x80000000 + jz end ; branch if 3DNow! not detected + + or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit + + end: + + mov res, esi + } + + return res & ~_dwDisabledISA; +} diff --git a/plugins/zerospu2/3rdparty/SoundTouch/mmx_optimized.cpp b/plugins/zerospu2/3rdparty/SoundTouch/mmx_optimized.cpp new file mode 100644 index 0000000000..f5afb595a5 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/mmx_optimized.cpp @@ -0,0 +1,305 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// MMX optimized routines. All MMX optimized functions have been gathered into +/// this single source code file, regardless to their class or original source +/// code file, in order to ease porting the library to other compiler and +/// processor platforms. +/// +/// The MMX-optimizations are programmed using MMX compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support compiler intrinsic syntax. The update +/// is available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/06 18:52:43 $ +// File revision : $Revision: 1.1 $ +// +// $Id: mmx_optimized.cpp,v 1.1 2006/02/06 18:52:43 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "STTypes.h" + +#ifdef ALLOW_MMX +// MMX routines available only with integer sample type + +#if !(_WIN32 || __i386__ || __x86_64__) +#error "wrong platform - this source code file is exclusively for x86 platforms" +#endif + +using namespace soundtouch; + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'TDStretchMMX' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include +#include + + +// Calculates cross correlation of two buffers +long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const +{ + const __m64 *pVec1, *pVec2; + __m64 shifter; + __m64 accu; + long corr; + uint i; + + pVec1 = (__m64*)pV1; + pVec2 = (__m64*)pV2; + + shifter = _m_from_int(overlapDividerBits); + accu = _mm_setzero_si64(); + + // Process 4 parallel sets of 2 * stereo samples each during each + // round to improve CPU-level parallellization. + for (i = 0; i < overlapLength / 8; i ++) + { + __m64 temp; + + // dictionary of instructions: + // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] + // _mm_add_pi32 : 2*32bit add + // _m_psrad : 32bit right-shift + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), + _mm_madd_pi16(pVec1[1], pVec2[1])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), + _mm_madd_pi16(pVec1[3], pVec2[3])); + accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); + + pVec1 += 4; + pVec2 += 4; + } + + // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 + // and finally store the result into the variable "corr" + + accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); + corr = _m_to_int(accu); + + // Clear MMS state + _m_empty(); + + return corr; + // Note: Warning about the missing EMMS instruction is harmless + // as it'll be called elsewhere. +} + + + +void TDStretchMMX::clearCrossCorrState() +{ + // Clear MMS state + _m_empty(); + //_asm EMMS; +} + + + +// MMX-optimized version of the function overlapStereo +void TDStretchMMX::overlapStereo(short *output, const short *input) const +{ + const __m64 *pVinput, *pVMidBuf; + __m64 *pVdest; + __m64 mix1, mix2, adder, shifter; + uint i; + + pVinput = (const __m64*)input; + pVMidBuf = (const __m64*)pMidBuffer; + pVdest = (__m64*)output; + + // mix1 = mixer values for 1st stereo sample + // mix1 = mixer values for 2nd stereo sample + // adder = adder for updating mixer values after each round + + mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); + adder = _mm_set_pi16(1, -1, 1, -1); + mix2 = _mm_add_pi16(mix1, adder); + adder = _mm_add_pi16(adder, adder); + + shifter = _m_from_int(overlapDividerBits); + + for (i = 0; i < overlapLength / 4; i ++) + { + __m64 temp1, temp2; + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r + temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + // --- second round begins here --- + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r + temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + pVinput += 2; + pVMidBuf += 2; + pVdest += 2; + } + + _m_empty(); // clear MMS state +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + + +FIRFilterMMX::FIRFilterMMX() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterMMX::~FIRFilterMMX() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for MMX routine +void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new short[2 * newLength + 8]; + filterCoeffsAlign = (short *)(((ulongptr)filterCoeffsUnalign + 15) & -16); + + // rearrange the filter coefficients for mmx routines + for (i = 0;i < length; i += 4) + { + filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; + filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; + + filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; + filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; + } +} + + + +// mmx-optimized version of the filter routine for stereo sound +uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, const uint numSamples) const +{ + // Create stack copies of the needed member variables for asm routines : + uint i, j; + __m64 *pVdest = (__m64*)dest; + + if (length < 2) return 0; + + for (i = 0; i < numSamples / 2; i ++) + { + __m64 accu1; + __m64 accu2; + const __m64 *pVsrc = (const __m64*)src; + const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; + + accu1 = accu2 = _mm_setzero_si64(); + for (j = 0; j < lengthDiv8 * 2; j ++) + { + __m64 temp1, temp2; + + temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 + temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 + + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0 + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1 + + temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2 + + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0 + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1 + + // accu1 += l2*f2+l0*f0 r2*f2+r0*f0 + // += l3*f3+l1*f1 r3*f3+r1*f1 + + // accu2 += l3*f2+l1*f0 r3*f2+r1*f0 + // l4*f3+l2*f1 r4*f3+r2*f1 + + pVfilter += 2; + pVsrc += 2; + } + // accu >>= resultDivFactor + accu1 = _mm_srai_pi32(accu1, resultDivFactor); + accu2 = _mm_srai_pi32(accu2, resultDivFactor); + + // pack 2*2*32bits => 4*16 bits + pVdest[0] = _mm_packs_pi32(accu1, accu2); + src += 4; + pVdest ++; + } + + _m_empty(); // clear emms state + + return (numSamples & 0xfffffffe) - length; +} + +#endif // ALLOW_MMX diff --git a/plugins/zerospu2/3rdparty/SoundTouch/sse_optimized.cpp b/plugins/zerospu2/3rdparty/SoundTouch/sse_optimized.cpp new file mode 100644 index 0000000000..57598d78d7 --- /dev/null +++ b/plugins/zerospu2/3rdparty/SoundTouch/sse_optimized.cpp @@ -0,0 +1,484 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE +/// optimized functions have been gathered into this single source +/// code file, regardless to their class or original source code file, in order +/// to ease porting the library to other compiler and processor platforms. +/// +/// The SSE-optimizations are programmed using SSE compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support SSE instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2006/02/05 16:44:06 $ +// File revision : $Revision: 1.2 $ +// +// $Id: sse_optimized.cpp,v 1.2 2006/02/05 16:44:06 Olli Exp $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +using namespace soundtouch; + +#ifdef ALLOW_SSE + +// SSE routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'TDStretchSSE' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include + +// Calculates cross correlation of two buffers +double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const +{ + uint i; + __m128 vSum, *pVec2; + + // Note. It means a major slow-down if the routine needs to tolerate + // unaligned __m128 memory accesses. It's way faster if we can skip + // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. + // This can mean up to ~ 10-fold difference (incl. part of which is + // due to skipping every second round for stereo sound though). + // + // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided + // for choosing if this little cheating is allowed. + +#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION + // Little cheating allowed, return valid correlation only for + // aligned locations, meaning every second round for stereo sound. + + #define _MM_LOAD _mm_load_ps + + if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations + +#else + // No cheating allowed, use unaligned load & take the resulting + // performance hit. + #define _MM_LOAD _mm_loadu_ps +#endif + + // ensure overlapLength is divisible by 8 + assert((overlapLength % 8) == 0); + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. + pVec2 = (__m128*)pV2; + vSum = _mm_setzero_ps(); + + // Unroll the loop by factor of 4 * 4 operations + for (i = 0; i < overlapLength / 8; i ++) + { + // vSum += pV1[0..3] * pV2[0..3] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1),pVec2[0])); + + // vSum += pV1[4..7] * pV2[4..7] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 4), pVec2[1])); + + // vSum += pV1[8..11] * pV2[8..11] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 8), pVec2[2])); + + // vSum += pV1[12..15] * pV2[12..15] + vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 12), pVec2[3])); + + pV1 += 16; + pVec2 += 4; + } + + // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] + float *pvSum = (float*)&vSum; + return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]); + + /* This is approximately corresponding routine in C-language: + double corr; + uint i; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + corr = 0.0; + for (i = 0; i < overlapLength / 8; i ++) + { + corr += pV1[0] * pV2[0] + + pV1[1] * pV2[1] + + pV1[2] * pV2[2] + + pV1[3] * pV2[3] + + pV1[4] * pV2[4] + + pV1[5] * pV2[5] + + pV1[6] * pV2[6] + + pV1[7] * pV2[7] + + pV1[8] * pV2[8] + + pV1[9] * pV2[9] + + pV1[10] * pV2[10] + + pV1[11] * pV2[11] + + pV1[12] * pV2[12] + + pV1[13] * pV2[13] + + pV1[14] * pV2[14] + + pV1[15] * pV2[15]; + + pV1 += 16; + pV2 += 16; + } + */ + + /* This is corresponding routine in assembler. This may be teeny-weeny bit faster + than intrinsic version, but more difficult to maintain & get compiled on multiple + platforms. + + uint overlapLengthLocal = overlapLength; + float corr; + + _asm + { + // Very important note: data in 'pV2' _must_ be aligned to + // 16-byte boundary! + + // give prefetch hints to CPU of what data are to be needed soonish + // give more aggressive hints on pV1 as that changes while pV2 stays + // same between runs + prefetcht0 [pV1] + prefetcht0 [pV2] + prefetcht0 [pV1 + 32] + + mov eax, dword ptr pV1 + mov ebx, dword ptr pV2 + + xorps xmm0, xmm0 + + mov ecx, overlapLengthLocal + shr ecx, 3 // div by eight + + loop1: + prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish + movups xmm1, [eax] + mulps xmm1, [ebx] + addps xmm0, xmm1 + + movups xmm2, [eax + 16] + mulps xmm2, [ebx + 16] + addps xmm0, xmm2 + + prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm3, [eax + 32] + mulps xmm3, [ebx + 32] + addps xmm0, xmm3 + + movups xmm4, [eax + 48] + mulps xmm4, [ebx + 48] + addps xmm0, xmm4 + + add eax, 64 + add ebx, 64 + + dec ecx + jnz loop1 + + // add the four floats of xmm0 together and return the result. + + movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1 + addps xmm1, xmm0 + movaps xmm2, xmm1 + shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2 + addss xmm2, xmm1 + movss corr, xmm2 + } + + return (double)corr; + */ +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilterSSE::FIRFilterSSE() : FIRFilter() +{ + filterCoeffsUnalign = NULL; +} + + +FIRFilterSSE::~FIRFilterSSE() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for SSE routine +void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for 3DNow! + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & -16); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + + +// SSE-optimized version of the filter routine for stereo sound +uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const +{ + int count = (numSamples - length) & -2; + int j; + + assert(count % 2 == 0); + + if (count < 2) return 0; + + assert((length % 8) == 0); + assert(((unsigned long)filterCoeffsAlign) % 16 == 0); + + // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' + for (j = 0; j < count; j += 2) + { + const float *pSrc; + const __m128 *pFil; + __m128 sum1, sum2; + uint i; + + pSrc = source; // source audio data + pFil = (__m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients + // are aligned to 16-byte boundary + sum1 = sum2 = _mm_setzero_ps(); + + for (i = 0; i < length / 8; i ++) + { + // Unroll loop for efficiency & calculate filter for 2*2 stereo samples + // at each pass + + // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset + // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); + + pSrc += 16; + pFil += 4; + } + + // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + // post-shuffle & add the filtered values and store to dest. + _mm_storeu_ps(dest, _mm_add_ps( + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 + )); + source += 4; + dest += 4; + } + + // Ideas for further improvement: + // 1. If it could be guaranteed that 'source' were always aligned to 16-byte + // boundary, a faster aligned '_mm_load_ps' instruction could be used. + // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte + // boundary, a faster '_mm_store_ps' instruction could be used. + + return (uint)count; + + /* original routine in C-language. please notice the C-version has differently + organized coefficients though. + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + const float *pFil; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + pFil = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * pFil[0] + + ptr[2] * pFil[2] + + ptr[4] * pFil[4] + + ptr[6] * pFil[6]; + + sumr1 += ptr[1] * pFil[1] + + ptr[3] * pFil[3] + + ptr[5] * pFil[5] + + ptr[7] * pFil[7]; + + suml2 += ptr[8] * pFil[0] + + ptr[10] * pFil[2] + + ptr[12] * pFil[4] + + ptr[14] * pFil[6]; + + sumr2 += ptr[9] * pFil[1] + + ptr[11] * pFil[3] + + ptr[13] * pFil[5] + + ptr[15] * pFil[7]; + + ptr += 16; + pFil += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + */ + + + /* Similar routine in assembly, again obsoleted due to maintainability + _asm + { + // Very important note: data in 'src' _must_ be aligned to + // 16-byte boundary! + mov edx, count + mov ebx, dword ptr src + mov eax, dword ptr dest + shr edx, 1 + + loop1: + // "outer loop" : during each round 2*2 output samples are calculated + + // give prefetch hints to CPU of what data are to be needed soonish + prefetcht0 [ebx] + prefetcht0 [filterCoeffsLocal] + + mov esi, ebx + mov edi, filterCoeffsLocal + xorps xmm0, xmm0 + xorps xmm1, xmm1 + mov ecx, lengthLocal + + loop2: + // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples + prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm2, [esi] // possibly unaligned load + movups xmm3, [esi + 8] // possibly unaligned load + mulps xmm2, [edi] + mulps xmm3, [edi] + addps xmm0, xmm2 + addps xmm1, xmm3 + + movups xmm4, [esi + 16] // possibly unaligned load + movups xmm5, [esi + 24] // possibly unaligned load + mulps xmm4, [edi + 16] + mulps xmm5, [edi + 16] + addps xmm0, xmm4 + addps xmm1, xmm5 + + prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish + prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish + + movups xmm6, [esi + 32] // possibly unaligned load + movups xmm7, [esi + 40] // possibly unaligned load + mulps xmm6, [edi + 32] + mulps xmm7, [edi + 32] + addps xmm0, xmm6 + addps xmm1, xmm7 + + movups xmm4, [esi + 48] // possibly unaligned load + movups xmm5, [esi + 56] // possibly unaligned load + mulps xmm4, [edi + 48] + mulps xmm5, [edi + 48] + addps xmm0, xmm4 + addps xmm1, xmm5 + + add esi, 64 + add edi, 64 + dec ecx + jnz loop2 + + // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2 + movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2 + shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0 + addps xmm0, xmm2 + + movaps [eax], xmm0 + add ebx, 16 + add eax, 16 + + dec edx + jnz loop1 + } + */ +} + +#endif // ALLOW_SSE diff --git a/plugins/zerospu2/Linux/Alsa.cpp b/plugins/zerospu2/Linux/Alsa.cpp new file mode 100644 index 0000000000..c2d2321eed --- /dev/null +++ b/plugins/zerospu2/Linux/Alsa.cpp @@ -0,0 +1,155 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 + */ + + // Modified by arcum42@gmail.com + + #ifndef ZEROSPU2_OSS + +// ALSA +#include + +#define ALSA_MEM_DEF +#include "Linux.h" + +static snd_pcm_t *handle = NULL; +static snd_pcm_uframes_t buffer_size; + +int AlsaSetupSound() +{ + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + snd_pcm_status_t *status; + unsigned int pspeed = SAMPLE_RATE; + int pchannels = 2; + snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; + unsigned int buffer_time = SOUNDSIZE; + unsigned int period_time= buffer_time / 4; + int err; + + err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); + if(err < 0) { + printf("Audio open error: %s\n", snd_strerror(err)); + return -1; + } + + err = snd_pcm_nonblock(handle, 0); + if(err < 0) { + printf("Can't set blocking moded: %s\n", snd_strerror(err)); + return -1; + } + + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_sw_params_alloca(&swparams); + + err = snd_pcm_hw_params_any(handle, hwparams); + if (err < 0) { + printf("Broken configuration for this PCM: %s\n", snd_strerror(err)); + return -1; + } + + err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); + if (err < 0) { + printf("Access type not available: %s\n", snd_strerror(err)); + return -1; + } + + err = snd_pcm_hw_params_set_format(handle, hwparams, format); + if (err < 0) { + printf("Sample format not available: %s\n", snd_strerror(err)); + return -1; + } + + err = snd_pcm_hw_params_set_channels(handle, hwparams, pchannels); + if (err < 0) { + printf("Channels count not available: %s\n", snd_strerror(err)); + return -1; + } + err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0); + if (err < 0) { + printf("Rate not available: %s\n", snd_strerror(err)); + return -1; + } + + err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); + if(err < 0) { + printf("Buffer time error: %s\n", snd_strerror(err)); + return -1; + } + + err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); + if (err < 0) { + printf("Period time error: %s\n", snd_strerror(err)); + return -1; + } + + err = snd_pcm_hw_params(handle, hwparams); + if (err < 0) { + printf("Unable to install hw params: %s\n", snd_strerror(err)); + return -1; + } + + snd_pcm_status_alloca(&status); + err = snd_pcm_status(handle, status); + if(err < 0) { + printf("Unable to get status: %s\n", snd_strerror(err)); + return -1; + } + + buffer_size=snd_pcm_status_get_avail(status); + + return 0; +} + +void AlsaRemoveSound() +{ + if(handle != NULL) { + snd_pcm_drop(handle); + snd_pcm_close(handle); + handle = NULL; + } +} + +int AlsaSoundGetBytesBuffered() +{ + int l; + + // failed to open? + if(handle == NULL) return SOUNDSIZE; + + l = snd_pcm_avail_update(handle); + + if (l<0) + return 0; + else if (l no? wait + else + l=0; // -> else go on + + return l; +} + +void AlsaSoundFeedVoiceData(unsigned char* pSound,long lBytes) +{ + if (handle == NULL) return; + + if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN) + snd_pcm_prepare(handle); + snd_pcm_writei(handle,pSound, lBytes/4); +} + +#endif \ No newline at end of file diff --git a/plugins/zerospu2/Linux/Linux.cpp b/plugins/zerospu2/Linux/Linux.cpp new file mode 100644 index 0000000000..51a44e04ac --- /dev/null +++ b/plugins/zerospu2/Linux/Linux.cpp @@ -0,0 +1,198 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 + */ + + // Modified by arcum42@gmail.com + +#include + +extern "C" { +#include "interface.h" +#include "support.h" +#include "callbacks.h" +} + +#include "zerospu2.h" +#include "Linux.h" + +// This is a bit ugly. I'll see if I can work out a better way to do this later. +int SetupSound() +{ +#ifdef ZEROSPU2_OSS + return OSSSetupSound(); +#else + return AlsaSetupSound(); +#endif +} +void RemoveSound() +{ +#ifdef ZEROSPU2_OSS + OSSRemoveSound(); +#else + AlsaRemoveSound(); +#endif +} +int SoundGetBytesBuffered() +{ +#ifdef ZEROSPU2_OSS + return OSSSoundGetBytesBuffered(); +#else + return AlsaSoundGetBytesBuffered(); +#endif +} +void SoundFeedVoiceData(unsigned char* pSound,long lBytes) +{ +#ifdef ZEROSPU2_OSS + OSSSoundFeedVoiceData(pSound, lBytes); +#else + AlsaSoundFeedVoiceData(pSound, lBytes); +#endif +} + +GtkWidget *MsgDlg, *ConfDlg; + +void OnMsg_Ok() { + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void SysMessage(char *fmt, ...) { + GtkWidget *Ok,*Txt; + GtkWidget *Box,*Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "SPU2null Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +void CALLBACK SPU2configure() +{ + LOG_CALLBACK("SPU2configure()\n"); + ConfDlg = create_Config(); + LoadConfig(); + set_checked(ConfDlg, "timescalingbutton", (conf.options & OPTION_TIMESTRETCH)); + set_checked(ConfDlg, "realtimebutton", (conf.options & OPTION_REALTIME)); + set_checked(ConfDlg, "recordingbutton", (conf.options & OPTION_RECORDING)); + set_checked(ConfDlg, "mutebutton", (conf.options & OPTION_MUTE)); + set_checked(ConfDlg, "loggingbutton", (conf.Log)); + + gtk_widget_show_all(ConfDlg); + gtk_main(); +} + + +void on_Conf_Ok (GtkButton *button, gpointer user_data) +{ + conf.options = 0; + + if (is_checked(ConfDlg, "realtimebutton")) + conf.options |= OPTION_REALTIME; + if (is_checked(ConfDlg, "timescalingbutton")) + conf.options |= OPTION_TIMESTRETCH; + if (is_checked(ConfDlg, "recordingbutton")) + conf.options |= OPTION_RECORDING; + if (is_checked(ConfDlg, "mutebutton")) + conf.options |= OPTION_MUTE; + conf.Log = is_checked(ConfDlg, "loggingbutton"); + SaveConfig(); + gtk_widget_destroy(ConfDlg); + gtk_main_quit(); +} + + +void on_Conf_Cancel (GtkButton *button, gpointer user_data) +{ + gtk_widget_destroy(ConfDlg); + gtk_main_quit(); + +} + +extern char *libraryName; +extern string s_strIniPath; + +void CALLBACK SPU2about() +{ + LOG_CALLBACK("SPU2about()\n"); + SysMessage("%s %d.%d\ndeveloper: zerofrog", libraryName, SPU2_VERSION, SPU2_BUILD); +} + +void SaveConfig() { + FILE *f; + char cfg[255]; + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg,"w"); + if (f == NULL) { + printf("Failed to open %s\n", s_strIniPath.c_str()); + return; + } + fprintf(f, "log = %d\n", conf.Log); + fprintf(f, "options = %d\n", conf.options); + fclose(f); +} + +void LoadConfig() { + FILE *f; + char cfg[255]; + + memset(&conf, 0, sizeof(conf)); + + strcpy(cfg, s_strIniPath.c_str()); + f = fopen(cfg, "r"); + if (f == NULL) { + printf("Failed to open %s\n", s_strIniPath.c_str()); + conf.Log = 0; + conf.options = 0; + SaveConfig();//save and return + return; + } + fscanf(f, "log = %d\n", &conf.Log); + fscanf(f, "options = %d\n", &conf.options); + fclose(f); +} diff --git a/plugins/zerospu2/Linux/Linux.h b/plugins/zerospu2/Linux/Linux.h new file mode 100644 index 0000000000..489b1ace63 --- /dev/null +++ b/plugins/zerospu2/Linux/Linux.h @@ -0,0 +1,75 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 + */ + + // Modified by arcum42@gmail.com + + #ifndef __LINUX_H__ + #define __LINUX_H__ + +#include +#include + +#include +#include +#include +#include + +#include + +// Make it easier to check and set checkmarks in the gui +#define is_checked(main_widget, widget_name) (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)))) +#define set_checked(main_widget,widget_name, state) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(lookup_widget(main_widget, widget_name)), state) + +// Alsa & OSS defines +#ifdef ZEROSPU2_OSS + +#define OSS_MODE_STEREO 1 +#define SOUNDSIZE 76800 + +// Pull in from OSS.cpp +extern int OSSSetupSound(); +extern void OSSRemoveSound(); +extern int OSSSoundGetBytesBuffered(); +extern void OSSSoundFeedVoiceData(unsigned char* pSound,long lBytes); + +#else + +#define ALSA_PCM_NEW_HW_PARAMS_API +#define ALSA_PCM_NEW_SW_PARAMS_API + +#ifdef ALSA_MEM_DEF +#define ALSA_MEM_EXTERN +#else +#define ALSA_MEM_EXTERN extern +#endif + +#define SOUNDSIZE 500000 + +// Pull in from Alsa.cpp +extern int AlsaSetupSound(); +extern void AlsaRemoveSound(); +extern int AlsaSoundGetBytesBuffered(); +extern void AlsaSoundFeedVoiceData(unsigned char* pSound,long lBytes); +#endif + +extern int SetupSound(); +extern void RemoveSound(); +extern int SoundGetBytesBuffered(); +extern void SoundFeedVoiceData(unsigned char* pSound,long lBytes); + +#endif // __LINUX_H__ \ No newline at end of file diff --git a/plugins/zerospu2/Linux/OSS.cpp b/plugins/zerospu2/Linux/OSS.cpp new file mode 100644 index 0000000000..34bcfece8e --- /dev/null +++ b/plugins/zerospu2/Linux/OSS.cpp @@ -0,0 +1,121 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 + */ + + // Modified by arcum42@gmail.com + +#ifdef ZEROSPU2_OSS + +#include "Linux.h" + +static int oss_audio_fd = -1; +extern int errno; + +// use OSS for sound +int OSSSetupSound() +{ + int pspeed = SAMPLE_RATE; + int pstereo; + int format; + int fragsize = 0; + int myfrag; + int oss_speed, oss_stereo; + int err; + + pstereo=OSS_MODE_STEREO; + + oss_speed = pspeed; + oss_stereo = pstereo; + + oss_audio_fd=open("/dev/dsp",O_WRONLY,0); + if (oss_audio_fd == -1) { + printf("Sound device not available!\n"); + return -1; + } + + err= ioctl(oss_audio_fd,SNDCTL_DSP_RESET,0); + if (err == -1) { + printf("Sound reset failed\n"); + return -1; + } + + // we use 64 fragments with 1024 bytes each + fragsize = 10; + myfrag = (63 << 16) | fragsize; + err = ioctl(oss_audio_fd,SNDCTL_DSP_SETFRAGMENT,&myfrag); + if (err == -1) { + printf("Sound set fragment failed!\n"); + return -1; + } + + format = AFMT_S16_LE; + err = ioctl(oss_audio_fd,SNDCTL_DSP_SETFMT,&format); + if ((err == -1) || (format!=AFMT_S16_LE)) { + printf("Sound format not supported!\n"); + return -1; + } + + err = ioctl(oss_audio_fd,SNDCTL_DSP_STEREO,&oss_stereo); + if (err == -1) { + printf("Stereo mode not supported!\n"); + return -1; + } + + err = ioctl(oss_audio_fd,SNDCTL_DSP_SPEED,&oss_speed); + if ((err == -1) || (oss_speed!=pspeed) { + printf("Sound frequency not supported\n"); + return -1; + } + + return 0; +} + +// REMOVE SOUND +void OSSRemoveSound() +{ + if(oss_audio_fd != -1 ) { + close(oss_audio_fd); + oss_audio_fd = -1; + } +} + +int OSSSoundGetBytesBuffered() +{ + audio_buf_info info; + unsigned long l; + + if(oss_audio_fd == -1) + return SOUNDSIZE; + if(ioctl(oss_audio_fd,SNDCTL_DSP_GETOSPACE,&info)==-1) + return 0; + else { + // can we write in at least the half of fragments? + if(info.fragments<(info.fragstotal>>1)) + return SOUNDSIZE; + } + + return 0; +} + +// FEED SOUND DATA +void OSSSoundFeedVoiceData(unsigned char* pSound,long lBytes) +{ + if(oss_audio_fd == -1) return; + write(oss_audio_fd,pSound,lBytes); +} + +#endif \ No newline at end of file diff --git a/plugins/zerospu2/Linux/buildgui.sh b/plugins/zerospu2/Linux/buildgui.sh new file mode 100644 index 0000000000..f7627e9d8a --- /dev/null +++ b/plugins/zerospu2/Linux/buildgui.sh @@ -0,0 +1,9 @@ +# builds the GUI C classes +mkdir temp +cp zerospu2.glade temp/ +cd temp +glade-2 --write-source zerospu2.glade +rm src/main.c +cp src/*.h src/*.c ../ +cd .. +/bin/rm -rf temp diff --git a/plugins/zerospu2/Linux/callbacks.c b/plugins/zerospu2/Linux/callbacks.c new file mode 100644 index 0000000000..1404beee8b --- /dev/null +++ b/plugins/zerospu2/Linux/callbacks.c @@ -0,0 +1,26 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + + +void +on_Conf_Ok (GtkButton *button, + gpointer user_data) +{ + +} + + +void +on_Conf_Cancel (GtkButton *button, + gpointer user_data) +{ + +} + diff --git a/plugins/zerospu2/Linux/callbacks.h b/plugins/zerospu2/Linux/callbacks.h new file mode 100644 index 0000000000..31d1ca7051 --- /dev/null +++ b/plugins/zerospu2/Linux/callbacks.h @@ -0,0 +1,10 @@ +#include + + +void +on_Conf_Ok (GtkButton *button, + gpointer user_data); + +void +on_Conf_Cancel (GtkButton *button, + gpointer user_data); diff --git a/plugins/zerospu2/Linux/interface.c b/plugins/zerospu2/Linux/interface.c new file mode 100644 index 0000000000..451d7e3846 --- /dev/null +++ b/plugins/zerospu2/Linux/interface.c @@ -0,0 +1,130 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +#define GLADE_HOOKUP_OBJECT(component,widget,name) \ + g_object_set_data_full (G_OBJECT (component), name, \ + gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) + +#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ + g_object_set_data (G_OBJECT (component), name, widget) + +GtkWidget* +create_About (void) +{ + GtkWidget *About; + /* TRANSLATORS: Replace this string with your names, one name per line. */ + gchar *translators = _("translator-credits"); + + About = gtk_about_dialog_new (); + gtk_container_set_border_width (GTK_CONTAINER (About), 5); + gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (About), VERSION); + gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (About), _("ZeroSPU2")); + gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (About), translators); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (About, About, "About"); + + return About; +} + +GtkWidget* +create_Config (void) +{ + GtkWidget *Config; + GtkWidget *dialog_vbox1; + GtkWidget *vbox1; + GtkWidget *timescalingbutton; + GtkWidget *realtimebutton; + GtkWidget *recordingbutton; + GtkWidget *mutebutton; + GtkWidget *loggingbutton; + GtkWidget *dialog_action_area1; + GtkWidget *Conf_Ok; + GtkWidget *Conf_Cancel; + + Config = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (Config), _("ZeroSPU2 Config")); + gtk_window_set_type_hint (GTK_WINDOW (Config), GDK_WINDOW_TYPE_HINT_DIALOG); + + dialog_vbox1 = GTK_DIALOG (Config)->vbox; + gtk_widget_show (dialog_vbox1); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox1); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox1, TRUE, TRUE, 0); + + timescalingbutton = gtk_check_button_new_with_mnemonic (_("Time Scaling (recommended) \nSlows down or speeds up sound with respect to game's real speed. \nEnabling this produces higher quality sound with less cracking, but can reduce speed.")); + gtk_widget_show (timescalingbutton); + gtk_box_pack_start (GTK_BOX (vbox1), timescalingbutton, FALSE, FALSE, 0); + + realtimebutton = gtk_check_button_new_with_mnemonic (_("Real Time mode \nTries to reduce delays in music as much possible. \nUse when game is already fast and need sound tightly synchronized.\n(like in DDR, Guitar Hero, Guitaroo Man)")); + gtk_widget_show (realtimebutton); + gtk_box_pack_start (GTK_BOX (vbox1), realtimebutton, FALSE, FALSE, 0); + + recordingbutton = gtk_check_button_new_with_mnemonic (_("Recording - Saves the raw 16bit stereo wav data to zerospu2.wav. Timed to ps2 time.")); + gtk_widget_show (recordingbutton); + gtk_box_pack_start (GTK_BOX (vbox1), recordingbutton, FALSE, FALSE, 0); + + mutebutton = gtk_check_button_new_with_mnemonic (_("Mute - ZeroSPU2 will not output any sound (fast).")); + gtk_widget_show (mutebutton); + gtk_box_pack_start (GTK_BOX (vbox1), mutebutton, FALSE, FALSE, 0); + + loggingbutton = gtk_check_button_new_with_mnemonic (_("Enable logging(for development use only)")); + gtk_widget_show (loggingbutton); + gtk_box_pack_start (GTK_BOX (vbox1), loggingbutton, FALSE, FALSE, 0); + + dialog_action_area1 = GTK_DIALOG (Config)->action_area; + gtk_widget_show (dialog_action_area1); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); + + Conf_Ok = gtk_button_new_from_stock ("gtk-ok"); + gtk_widget_show (Conf_Ok); + gtk_dialog_add_action_widget (GTK_DIALOG (Config), Conf_Ok, GTK_RESPONSE_OK); + GTK_WIDGET_SET_FLAGS (Conf_Ok, GTK_CAN_DEFAULT); + + Conf_Cancel = gtk_button_new_from_stock ("gtk-cancel"); + gtk_widget_show (Conf_Cancel); + gtk_dialog_add_action_widget (GTK_DIALOG (Config), Conf_Cancel, GTK_RESPONSE_CANCEL); + GTK_WIDGET_SET_FLAGS (Conf_Cancel, GTK_CAN_DEFAULT); + + g_signal_connect ((gpointer) Conf_Ok, "clicked", + G_CALLBACK (on_Conf_Ok), + NULL); + g_signal_connect ((gpointer) Conf_Cancel, "clicked", + G_CALLBACK (on_Conf_Cancel), + NULL); + + /* Store pointers to all widgets, for use by lookup_widget(). */ + GLADE_HOOKUP_OBJECT_NO_REF (Config, Config, "Config"); + GLADE_HOOKUP_OBJECT_NO_REF (Config, dialog_vbox1, "dialog_vbox1"); + GLADE_HOOKUP_OBJECT (Config, vbox1, "vbox1"); + GLADE_HOOKUP_OBJECT (Config, timescalingbutton, "timescalingbutton"); + GLADE_HOOKUP_OBJECT (Config, realtimebutton, "realtimebutton"); + GLADE_HOOKUP_OBJECT (Config, recordingbutton, "recordingbutton"); + GLADE_HOOKUP_OBJECT (Config, mutebutton, "mutebutton"); + GLADE_HOOKUP_OBJECT (Config, loggingbutton, "loggingbutton"); + GLADE_HOOKUP_OBJECT_NO_REF (Config, dialog_action_area1, "dialog_action_area1"); + GLADE_HOOKUP_OBJECT (Config, Conf_Ok, "Conf_Ok"); + GLADE_HOOKUP_OBJECT (Config, Conf_Cancel, "Conf_Cancel"); + + return Config; +} + diff --git a/plugins/zerospu2/Linux/interface.h b/plugins/zerospu2/Linux/interface.h new file mode 100644 index 0000000000..cd7bb62f7d --- /dev/null +++ b/plugins/zerospu2/Linux/interface.h @@ -0,0 +1,6 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_About (void); +GtkWidget* create_Config (void); diff --git a/plugins/zerospu2/Linux/support.c b/plugins/zerospu2/Linux/support.c new file mode 100644 index 0000000000..00aff29822 --- /dev/null +++ b/plugins/zerospu2/Linux/support.c @@ -0,0 +1,144 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "support.h" + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (!parent) + parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey"); + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to find pixmap files. */ +static gchar* +find_pixmap_file (const gchar *filename) +{ + GList *elem; + + /* We step through each of the pixmaps directory to find it. */ + elem = pixmaps_directories; + while (elem) + { + gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data, + G_DIR_SEPARATOR_S, filename); + if (g_file_test (pathname, G_FILE_TEST_EXISTS)) + return pathname; + g_free (pathname); + elem = elem->next; + } + return NULL; +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *pathname = NULL; + GtkWidget *pixmap; + + if (!filename || !filename[0]) + return gtk_image_new (); + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return gtk_image_new (); + } + + pixmap = gtk_image_new_from_file (pathname); + g_free (pathname); + return pixmap; +} + +/* This is an internally used function to create pixmaps. */ +GdkPixbuf* +create_pixbuf (const gchar *filename) +{ + gchar *pathname = NULL; + GdkPixbuf *pixbuf; + GError *error = NULL; + + if (!filename || !filename[0]) + return NULL; + + pathname = find_pixmap_file (filename); + + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return NULL; + } + + pixbuf = gdk_pixbuf_new_from_file (pathname, &error); + if (!pixbuf) + { + fprintf (stderr, "Failed to load pixbuf file: %s: %s\n", + pathname, error->message); + g_error_free (error); + } + g_free (pathname); + return pixbuf; +} + +/* This is used to set ATK action descriptions. */ +void +glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description) +{ + gint n_actions, i; + + n_actions = atk_action_get_n_actions (action); + for (i = 0; i < n_actions; i++) + { + if (!strcmp (atk_action_get_name (action, i), action_name)) + atk_action_set_description (action, i, description); + } +} + diff --git a/plugins/zerospu2/Linux/support.h b/plugins/zerospu2/Linux/support.h new file mode 100644 index 0000000000..a32649e53c --- /dev/null +++ b/plugins/zerospu2/Linux/support.h @@ -0,0 +1,69 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# define Q_(String) g_strip_context ((String), gettext (String)) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define Q_(String) g_strip_context ((String), (String)) +# define N_(String) (String) +#endif + + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps used in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + +/* This is used to create the pixbufs used in the interface. */ +GdkPixbuf* create_pixbuf (const gchar *filename); + +/* This is used to set ATK action descriptions. */ +void glade_set_atk_action_description (AtkAction *action, + const gchar *action_name, + const gchar *description); + diff --git a/plugins/zerospu2/Linux/zerospu2.glade b/plugins/zerospu2/Linux/zerospu2.glade new file mode 100644 index 0000000000..ea14cc62a3 --- /dev/null +++ b/plugins/zerospu2/Linux/zerospu2.glade @@ -0,0 +1,195 @@ + + + + + + + 5 + True + False + ZeroSPU2 + False + translator-credits + + + + True + ZeroSPU2 Config + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + False + 0 + + + + True + True + Time Scaling (recommended) +Slows down or speeds up sound with respect to game's real speed. +Enabling this produces higher quality sound with less cracking, but can reduce speed. + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Real Time mode +Tries to reduce delays in music as much possible. +Use when game is already fast and need sound tightly synchronized. +(like in DDR, Guitar Hero, Guitaroo Man) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Recording - Saves the raw 16bit stereo wav data to zerospu2.wav. Timed to ps2 time. + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Mute - ZeroSPU2 will not output any sound (fast). + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Enable logging(for development use only) + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + + + diff --git a/plugins/zerospu2/Makefile.am b/plugins/zerospu2/Makefile.am new file mode 100644 index 0000000000..82265b2de5 --- /dev/null +++ b/plugins/zerospu2/Makefile.am @@ -0,0 +1,34 @@ +# Create a shared library libZeroSPU2 +AUTOMAKE_OPTIONS = foreign +noinst_LIBRARIES = libZeroSPU2.a +INCLUDES = -I@srcdir@/common -I@srcdir@/3rdparty + +libZeroSPU2_a_CXXFLAGS = $(shell pkg-config --cflags gtk+-2.0) +libZeroSPU2_a_CFLAGS = $(shell pkg-config --cflags gtk+-2.0) + +if X86_64 +libZeroSPU2_a_CXXFLAGS += -fPIC +libZeroSPU2_a_CFLAGS += -fPIC +endif + +# Create a shared object by faking an exe (thanks to ODE makefiles) +traplibdir=$(prefix) + +if DEBUGBUILD +preext=d +endif + +EXEEXT=$(preext)@so_ext@ + +traplib_PROGRAMS=libZeroSPU2 +libZeroSPU2_SOURCES= +libZeroSPU2_DEPENDENCIES = libZeroSPU2.a 3rdparty/SoundTouch/libSoundTouch.a +libZeroSPU2_LDFLAGS= @SHARED_LDFLAGS@ +libZeroSPU2_LDFLAGS+=-Wl,-soname,@ZEROSPU2_SONAME@ +libZeroSPU2_LDADD=$(libZeroSPU2_a_OBJECTS) 3rdparty/SoundTouch/libSoundTouch.a + +libZeroSPU2_a_SOURCES = zerospu2.cpp voices.cpp zerodma.cpp +libZeroSPU2_a_SOURCES += zerospu2.h reg.h misc.h +libZeroSPU2_a_SOURCES += Linux/interface.c Linux/Linux.cpp Linux/Alsa.cpp Linux/OSS.cpp Linux/support.c + +SUBDIRS = 3rdparty/SoundTouch diff --git a/plugins/zerospu2/Win32/Win32.cpp b/plugins/zerospu2/Win32/Win32.cpp new file mode 100644 index 0000000000..5be6fd72d2 --- /dev/null +++ b/plugins/zerospu2/Win32/Win32.cpp @@ -0,0 +1,180 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include +#include +#include + +#include "zerospu2.h" +#include "resource.h" + +extern HINSTANCE hInst; +///////// +// GUI // +///////// +HINSTANCE hInst; + +void SysMessage(char *fmt, ...) +{ + va_list list; + char tmp[512]; + + va_start(list,fmt); + vsprintf_s(tmp,fmt,list); + va_end(list); + + MessageBox(0, tmp, "SPU2NULL Msg", 0); +} + +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + + switch(uMsg) + { + case WM_INITDIALOG: + LoadConfig(); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + if( conf.options & OPTION_REALTIME) + CheckDlgButton(hW, IDC_REALTIME, TRUE); + if( conf.options & OPTION_TIMESTRETCH) + CheckDlgButton(hW, IDC_TIMESTRETCH, TRUE); + if( conf.options & OPTION_MUTE) + CheckDlgButton(hW, IDC_MUTESOUND, TRUE); + if( conf.options & OPTION_RECORDING) + CheckDlgButton(hW, IDC_SNDRECORDING, TRUE); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hW, TRUE); + return TRUE; + case IDOK: + conf.options = 0; + if (IsDlgButtonChecked(hW, IDC_LOGGING)) + conf.Log = 1; + else + conf.Log = 0; + + if (IsDlgButtonChecked(hW, IDC_REALTIME)) + conf.options |= OPTION_REALTIME; + if (IsDlgButtonChecked(hW, IDC_TIMESTRETCH)) + conf.options |= OPTION_TIMESTRETCH; + if (IsDlgButtonChecked(hW, IDC_MUTESOUND)) + conf.options |= OPTION_MUTE; + if (IsDlgButtonChecked(hW, IDC_SNDRECORDING)) + conf.options |= OPTION_RECORDING; + + SaveConfig(); + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDOK: + EndDialog(hW, FALSE); + return TRUE; + } + } + return FALSE; +} + +void CALLBACK SPU2configure() +{ + DialogBox(hInst, MAKEINTRESOURCE(IDD_CONFIG), GetActiveWindow(), (DLGPROC)ConfigureDlgProc); +} + +void CALLBACK SPU2about() +{ + DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUT), GetActiveWindow(), (DLGPROC)AboutDlgProc); +} + + // DLL INIT +BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) +{ + hInst = (HINSTANCE)hModule; + return TRUE; // very quick :) +} + +void SaveConfig() +{ + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return; + szTemp[0] = 0; // this modifies szInitFile also. + + strcat_s(szIniFile, "\\inis\\zerospu2.ini"); + sprintf_s(szValue,"%u",Conf1->Log); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + sprintf_s(szValue,"%u",Conf1->options); + WritePrivateProfileString("Interface", "Options",szValue,szIniFile); +} + +void LoadConfig() +{ + FILE *fp; + Config *Conf1 = &conf; + char *szTemp; + char szIniFile[256], szValue[256]; + + GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); + szTemp = strrchr(szIniFile, '\\'); + + if(!szTemp) return ; + szTemp[0] = 0; + + strcat_s(szIniFile, "\\inis\\zerospu2.ini"); + fopen_s(&fp, "inis\\zerospu2.ini","rt");//check if zerospu2.ini really exists + + if (!fp) + { + CreateDirectory("inis",NULL); + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + conf.options = OPTION_TIMESTRETCH; + SaveConfig();//save and return + return ; + } + fclose(fp); + + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); + Conf1->Log = strtoul(szValue, NULL, 10); + GetPrivateProfileString("Interface", "Options", NULL, szValue, 20, szIniFile); + Conf1->options = strtoul(szValue, NULL, 10); + return; + +} + diff --git a/plugins/zerospu2/Win32/ZeroSPU2.def b/plugins/zerospu2/Win32/ZeroSPU2.def new file mode 100644 index 0000000000..9d20b4a760 --- /dev/null +++ b/plugins/zerospu2/Win32/ZeroSPU2.def @@ -0,0 +1,33 @@ +; SPU2null.def : Declares the module parameters for the DLL. + +;LIBRARY "SPU2null" +;DESCRIPTION 'SPU2 Null Driver' + +EXPORTS + ; Explicit exports can go here + PS2EgetLibType @2 + PS2EgetLibName @3 + PS2EgetLibVersion2 @4 + SPU2init @5 + SPU2shutdown @6 + SPU2open @7 + SPU2close @8 + SPU2write @9 + SPU2read @10 + SPU2readDMA4Mem @11 + SPU2writeDMA4Mem @12 + SPU2readDMA7Mem @13 + SPU2writeDMA7Mem @14 + SPU2async @15 + SPU2interruptDMA4 @16 + SPU2interruptDMA7 @17 + SPU2freeze @18 + SPU2configure @21 + SPU2test @22 + SPU2about @23 + + SPU2ReadMemAddr @24 + SPU2WriteMemAddr @25 + SPU2irqCallback @26 + SPU2setDMABaseAddr @27 + SPU2setupRecording @28 \ No newline at end of file diff --git a/plugins/zerospu2/Win32/ZeroSPU2.rc b/plugins/zerospu2/Win32/ZeroSPU2.rc new file mode 100644 index 0000000000..0624af3bd5 --- /dev/null +++ b/plugins/zerospu2/Win32/ZeroSPU2.rc @@ -0,0 +1,136 @@ +// 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 (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#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 + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Greek resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ELL) +#ifdef _WIN32 +LANGUAGE LANG_GREEK, SUBLANG_DEFAULT +#pragma code_page(1253) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 212, 175 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + CONTROL "Time Scaling (recommended) - Slows down or speeds up sound with respect to game's real speed. Enabling this produces higher quality sound with less cracking, but can reduce speed.",IDC_TIMESTRETCH, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,7,198,37 + CONTROL "Real Time mode - tries to reduce delays in music as much possible. Use when game is already fast and need sound tightly synchronized (like in DDR, Guitar Hero, Guitaroo Man)",IDC_REALTIME, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,43,198,37 + CONTROL "Recording - Saves the raw 16bit stereo wav data to zerospu2.wav. Timed to ps2 time.",IDC_SNDRECORDING, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,87,198,15 + CONTROL "Mute - ZeroSPU2 will not output any sound (fast).",IDC_MUTESOUND, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,101,168,24 + CONTROL "Enable logging(for develop use only)",IDC_LOGGING, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,127,159,15 + DEFPUSHBUTTON "OK",IDOK,48,154,50,14 + PUSHBUTTON "Cancel",IDCANCEL,113,154,50,14 +END + +IDD_ABOUT DIALOGEX 0, 0, 177, 106 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About ZeroSPU2..." +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,65,85,50,14 + LTEXT "ZeroSPU2 driver v0.4.6",IDC_NAME,51,7,79,15 + LTEXT "Author: Zerofrog Additional coding: Refraction Based on SPU2 Null driver by Shadow and Linuzappz",IDC_STATIC,7,23,141,54 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 168 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 175 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Greek resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/zerospu2/Win32/ZeroSPU2_2008.vcproj b/plugins/zerospu2/Win32/ZeroSPU2_2008.vcproj new file mode 100644 index 0000000000..db80c99fc2 --- /dev/null +++ b/plugins/zerospu2/Win32/ZeroSPU2_2008.vcproj @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/zerospu2/Win32/dsound51.cpp b/plugins/zerospu2/Win32/dsound51.cpp new file mode 100644 index 0000000000..c852add397 --- /dev/null +++ b/plugins/zerospu2/Win32/dsound51.cpp @@ -0,0 +1,248 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include "zerospu2.h" +///////////////////////////////////// +// use DirectSound for the sound +#include + +//4*48*73 +#define SOUNDSIZE 76800 +HWND hWMain; + +LPDIRECTSOUND lpDS; +LPDIRECTSOUNDBUFFER lpDSBPRIMARY = NULL; +LPDIRECTSOUNDBUFFER lpDSBSECONDARY1 = NULL; +LPDIRECTSOUNDBUFFER lpDSBSECONDARY2 = NULL; +DSBUFFERDESC dsbd; +DSBUFFERDESC dsbdesc; +DSCAPS dscaps; +DSBCAPS dsbcaps; + +unsigned long LastWrite = 0xffffffff; +unsigned long LastWriteS = 0xffffffff; +unsigned long LastPlay = 0; + +int SetupSound() +{ + HRESULT dsval; + WAVEFORMATEX pcmwf; + + dsval = DirectSoundCreate(NULL,&lpDS,NULL); + if(dsval != DS_OK) + { + MessageBox(NULL,"DirectSoundCreate!","Error",MB_OK); + return -1; + } + + if(DS_OK != IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_PRIORITY)) + { + if(DS_OK != IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_NORMAL)) + { + MessageBox(NULL,"SetCooperativeLevel!","Error",MB_OK); + return -1; + } + } + + memset(&dsbd,0,sizeof(DSBUFFERDESC)); + dsbd.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbd.dwBufferBytes = 0; + dsbd.lpwfxFormat = NULL; + + dsval = IDirectSound_CreateSoundBuffer(lpDS,&dsbd,&lpDSBPRIMARY,NULL); + if(dsval != DS_OK) + { + MessageBox(NULL, "CreateSoundBuffer (Primary)", "Error",MB_OK); + return -1; + } + + memset(&pcmwf, 0, sizeof(WAVEFORMATEX)); + pcmwf.wFormatTag = WAVE_FORMAT_PCM; + + pcmwf.nChannels = 2; + pcmwf.nBlockAlign = 4; + + pcmwf.nSamplesPerSec = SAMPLE_RATE; + + pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; + pcmwf.wBitsPerSample = 16; + + dsval = IDirectSoundBuffer_SetFormat(lpDSBPRIMARY,&pcmwf); + if(dsval != DS_OK) + { + MessageBox(NULL, "SetFormat!", "Error",MB_OK); + return -1; + } + + dscaps.dwSize = sizeof(DSCAPS); + dsbcaps.dwSize = sizeof(DSBCAPS); + IDirectSound_GetCaps(lpDS,&dscaps); + IDirectSoundBuffer_GetCaps(lpDSBPRIMARY,&dsbcaps); + + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + // NT4 hack! sizeof(DSBUFFERDESC); + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_LOCHARDWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + dsbdesc.dwBufferBytes = SOUNDSIZE; + dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; + + dsval = IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); + if(dsval != DS_OK) + { + dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + dsval = IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); + if(dsval != DS_OK) + { + MessageBox(NULL,"CreateSoundBuffer (Secondary1)", "Error",MB_OK); + return -1; + } + } + + dsval = IDirectSoundBuffer_Play(lpDSBPRIMARY,0,0,DSBPLAY_LOOPING); + if(dsval != DS_OK) + { + MessageBox(NULL,"Play (Primary)","Error",MB_OK); + return -1; + } + + dsval = IDirectSoundBuffer_Play(lpDSBSECONDARY1,0,0,DSBPLAY_LOOPING); + if(dsval != DS_OK) + { + MessageBox(NULL,"Play (Secondary1)","Error",MB_OK); + return -1; + } + + // init some play vars + LastWrite = 0x00000000; + LastPlay = 0; + + return 0; +} + +void RemoveSound() +{ + int iRes; + + if (lpDSBSECONDARY1 != NULL) + { + IDirectSoundBuffer_Stop(lpDSBSECONDARY1); + iRes = IDirectSoundBuffer_Release(lpDSBSECONDARY1); + + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes = IDirectSoundBuffer_Release(lpDSBSECONDARY1); + + lpDSBSECONDARY1 = NULL; + } + + if (lpDSBPRIMARY != NULL) + { + IDirectSoundBuffer_Stop(lpDSBPRIMARY); + iRes = IDirectSoundBuffer_Release(lpDSBPRIMARY); + + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes = IDirectSoundBuffer_Release(lpDSBPRIMARY); + + lpDSBPRIMARY = NULL; + } + + if (lpDS!=NULL) + { + iRes = IDirectSound_Release(lpDS); + + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes = IDirectSound_Release(lpDS); + + lpDS = NULL; + } + +} + +int SoundGetBytesBuffered() +{ + unsigned long cplay,cwrite; + + if (LastWrite == 0xffffffff) return 0; + + IDirectSoundBuffer_GetCurrentPosition(lpDSBSECONDARY1,&cplay,&cwrite); + + if(cplay > SOUNDSIZE) return SOUNDSIZE; + if(cplay < LastWrite) return LastWrite - cplay; + + return (SOUNDSIZE - cplay) + LastWrite; +} + +void SoundFeedVoiceData(unsigned char* pSound,long lBytes) +{ + LPVOID lpvPtr1, lpvPtr2; + unsigned long dwBytes1,dwBytes2; + unsigned long *lpSS, *lpSD; + unsigned long dw,cplay,cwrite; + HRESULT hr; + unsigned long status; + + IDirectSoundBuffer_GetStatus(lpDSBSECONDARY1,&status); + if (status & DSBSTATUS_BUFFERLOST) + { + if (IDirectSoundBuffer_Restore(lpDSBSECONDARY1) != DS_OK) return; + IDirectSoundBuffer_Play(lpDSBSECONDARY1,0,0,DSBPLAY_LOOPING); + } + + IDirectSoundBuffer_GetCurrentPosition(lpDSBSECONDARY1,&cplay,&cwrite); + + if(LastWrite == 0xffffffff) LastWrite=cwrite; + + hr = IDirectSoundBuffer_Lock(lpDSBSECONDARY1,LastWrite,lBytes, + &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); + + if (hr != DS_OK) + { + LastWrite=0xffffffff; + return; + } + + lpSS = (unsigned long *)pSound; + lpSD = (unsigned long *)lpvPtr1; + dw = dwBytes1 >> 2; + + while(dw) + { + *lpSD++=*lpSS++; + dw--; + } + + if (lpvPtr2) + { + lpSD = (unsigned long *)lpvPtr2; + dw = dwBytes2 >> 2; + + while(dw) + { + *lpSD++ = *lpSS++; + dw--; + } + } + + IDirectSoundBuffer_Unlock(lpDSBSECONDARY1,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2); + LastWrite += lBytes; + if(LastWrite >= SOUNDSIZE) LastWrite -= SOUNDSIZE; + LastPlay = cplay; +} \ No newline at end of file diff --git a/plugins/zerospu2/Win32/resource.h b/plugins/zerospu2/Win32/resource.h new file mode 100644 index 0000000000..0e2681687e --- /dev/null +++ b/plugins/zerospu2/Win32/resource.h @@ -0,0 +1,28 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ZeroSPU2.rc +// +#define IDD_CONFDLG 101 +#define IDD_CONFIG 101 +#define IDD_ABOUT 103 +#define IDC_NAME 1000 +#define IDC_CHECK1 1007 +#define IDC_LOGGING 1007 +#define IDC_FFXHAC 1008 +#define IDC_FFXHACK 1008 +#define IDC_SNDRECORDING 1008 +#define IDC_RECORDING 1008 +#define IDC_REALTIME 1009 +#define IDC_TIMESTRETCH 1010 +#define IDC_MUTESOUND 1011 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/zerospu2/Win32/vsprops/pcsx2_plugin_common.vsprops b/plugins/zerospu2/Win32/vsprops/pcsx2_plugin_common.vsprops new file mode 100644 index 0000000000..086133a60a --- /dev/null +++ b/plugins/zerospu2/Win32/vsprops/pcsx2_plugin_common.vsprops @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/plugins/zerospu2/Win32/vsprops/postBuild.tmpl b/plugins/zerospu2/Win32/vsprops/postBuild.tmpl new file mode 100644 index 0000000000..b0f9fb472f --- /dev/null +++ b/plugins/zerospu2/Win32/vsprops/postBuild.tmpl @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%\%3-r$WCREV$$WCMODS?m:$%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/zerospu2/Win32/vsprops/postBuild.unknown b/plugins/zerospu2/Win32/vsprops/postBuild.unknown new file mode 100644 index 0000000000..360b05cad5 --- /dev/null +++ b/plugins/zerospu2/Win32/vsprops/postBuild.unknown @@ -0,0 +1,21 @@ +@echo off +rem +rem Usage: postBuild.cmd SourcePath DestDir DestFile DestExt +rem +rem SourcePath - $(TargetPath) - Fully qualified path of the generated target file. +rem DestDir - $(SolutionDir) - Directory of the destination, usually the same as the solution. +rem DestFile - Base filename of the target/dest, without extension! +rem DestExt - Extension of the target/dest! + +set pcsxoutdir=%2\bin\plugins +set pcsxoutname=%pcsxoutdir%%3%4 + +IF NOT EXIST %pcsxoutdir% ( + md %pcsxoutdir% +) + +copy /Y %1 %pcsxoutname% +if ERRORLEVEL 0 ( + echo Target copied to %pcsxoutname% +) +set ERRORLEVEL=0 diff --git a/plugins/zerospu2/Win32/vsprops/preBuild.cmd b/plugins/zerospu2/Win32/vsprops/preBuild.cmd new file mode 100644 index 0000000000..fea16bd143 --- /dev/null +++ b/plugins/zerospu2/Win32/vsprops/preBuild.cmd @@ -0,0 +1,20 @@ +@echo off + +rem Usage: preBuild.cmd ProjectSrcDir VspropsDir +rem +rem ProjectSrcDir - $(ProjectDir)\.. - Directory of project source code. +rem VspropsDir - $(PrjectDir)\vsprops - Directory of this script and its counterparts. + +SubWCRev.exe %1 %2\svnrev_template.h %1\svnrev.h +if not ERRORLEVEL 0 ( + echo Automatic revision update unavailable, using generic template instead. + echo You can safely ignore this message - see svnrev.h for details. + copy /Y %2\svnrev_unknown.h %1\svnrev.h + copy /Y %2\postBuild.unknown %2\postBuild.cmd +) else ( + SubWCRev.exe %1 %2\postBuild.tmpl %2\postBuild.cmd +) + +rem Clear the error level -- this allows compilation to continue if SubWCRev failed. + +set ERRORLEVEL=0 diff --git a/plugins/zerospu2/Win32/vsprops/svnrev_template.h b/plugins/zerospu2/Win32/vsprops/svnrev_template.h new file mode 100644 index 0000000000..afab6c4fd1 --- /dev/null +++ b/plugins/zerospu2/Win32/vsprops/svnrev_template.h @@ -0,0 +1,18 @@ +// svnrev_template.h --> svnrev.h +// +// This file acts as a template for the automatic SVN revision/version tag. +// It is used by the utility SubWCrev.exe to create an "svnrev.h" file for +// whichever project is being compiled (as indicated by command line options +// passed to SubWCRev.exe during the project's pre-build step). +// +// The SubWCRev.exe utility is part of TortoiseSVN and requires several DLLs +// installed by TortoiseSVN, so it will only be available if you have TortoiseSVN +// installed on your system. If you do not have it installed, a generic template +// is used instead (see svnrev_generic.h). Having TortoiseSVN is handy but not +// necessary. If you do not have it installed, everything will still compile +// fine except without the SVN revision tagged to the application/dll version. +// +// TortoiseSVN can be downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV $WCREV$ +#define SVN_MODS $WCMODS?1:0$ \ No newline at end of file diff --git a/plugins/zerospu2/Win32/vsprops/svnrev_unknown.h b/plugins/zerospu2/Win32/vsprops/svnrev_unknown.h new file mode 100644 index 0000000000..a2a3703186 --- /dev/null +++ b/plugins/zerospu2/Win32/vsprops/svnrev_unknown.h @@ -0,0 +1,23 @@ +// svnrev_genric.h --> svnrev.h +// +// This file acts as a placebo for people who do not have TortoiseSVN installed. +// It provides "empty" revision information to the Pcsx2 Playground projects in +// the absence of real revisions derived from the repository being built. +// +// This file does not affect application/dll builds in any significant manner, +// other than the lack of automatic revision tags inserted into the app (which +// is very convenient but hardly necessary). +// +// See svn_template.h for more information on how the process of revision +// templating works. +// +// If you would like to enable automatic revisin tagging, TortoiseSVN can be +// downloaded from http://tortoisesvn.tigris.org + +#define SVN_REV_UNKNOWN + +// The following defines are included so that code will still compile even if it +// doesn't check for the SVN_REV_UNKNOWN define. + +#define SVN_REV 0 +#define SVN_MODS "" \ No newline at end of file diff --git a/plugins/zerospu2/build.sh b/plugins/zerospu2/build.sh new file mode 100644 index 0000000000..39a9ef1384 --- /dev/null +++ b/plugins/zerospu2/build.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +curdir=`pwd` + +echo ----------------- +echo Building ZeroSPU2 +echo ----------------- + +if [ $# -gt 0 ] && [ $1 = "all" ] +then + +aclocal +automake -a +autoconf +./configure --prefix=${PCSX2PLUGINS} +make clean +make install + +else +make $@ +fi + +if [ $? -ne 0 ] +then +exit 1 +fi + +#cp libZeroSPU2*.so* ${PCSX2PLUGINS} diff --git a/plugins/zerospu2/common/PS2Edefs.h b/plugins/zerospu2/common/PS2Edefs.h new file mode 100644 index 0000000000..1f65fc02b9 --- /dev/null +++ b/plugins/zerospu2/common/PS2Edefs.h @@ -0,0 +1,885 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2EDEFS_H__ +#define __PS2EDEFS_H__ + +/* + * PS2E Definitions v0.6.2 (beta) + * + * Author: linuzappz@hotmail.com + * shadowpcsx2@yahoo.gr + * florinsasu@hotmail.com + */ + +/* + Notes: + * Since this is still beta things may change. + + * OSflags: + __LINUX__ (linux OS) + _WIN32 (win32 OS) + + * common return values (for ie. GSinit): + 0 - success + -1 - error + + * reserved keys: + F1 to F10 are reserved for the emulator + + * plugins should NOT change the current + working directory. + (on win32, add flag OFN_NOCHANGEDIR for + GetOpenFileName) + +*/ + +#include "PS2Etypes.h" + + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ + defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ + defined(USBdefs) || defined(FWdefs) +#define COMMONdefs +#endif + +// PS2EgetLibType returns (may be OR'd) +#define PS2E_LT_GS 0x01 +#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=- +#define PS2E_LT_SPU2 0x04 +#define PS2E_LT_CDVD 0x08 +#define PS2E_LT_DEV9 0x10 +#define PS2E_LT_USB 0x20 +#define PS2E_LT_FW 0x40 +#define PS2E_LT_SIO 0x80 + +// PS2EgetLibVersion2 (high 16 bits) +#define PS2E_GS_VERSION 0x0006 +#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=- +#define PS2E_SPU2_VERSION 0x0005 +#define PS2E_CDVD_VERSION 0x0005 +#define PS2E_DEV9_VERSION 0x0003 +#define PS2E_USB_VERSION 0x0003 +#define PS2E_FW_VERSION 0x0002 +#define PS2E_SIO_VERSION 0x0001 +#ifdef COMMONdefs + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion2(u32 type); +char* CALLBACK PS2EgetLibName(void); + +#endif + +// key values: +/* key values must be OS dependant: + win32: the VK_XXX will be used (WinUser) + linux: the XK_XXX will be used (XFree86) +*/ + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +// for 64bit compilers +typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1]; + +// plugin types +#define SIO_TYPE_PAD 0x00000001 +#define SIO_TYPE_MTAP 0x00000004 +#define SIO_TYPE_RM 0x00000040 +#define SIO_TYPE_MC 0x00000100 + +typedef int (CALLBACK * SIOchangeSlotCB)(int slot); + +typedef struct _cdvdSubQ { + u8 ctrl:4; // control and mode bits + u8 mode:4; // control and mode bits + u8 trackNum; // current track number (1 to 99) + u8 trackIndex; // current index within track (0 to 99) + u8 trackM; // current minute location on the disc (BCD encoded) + u8 trackS; // current sector location on the disc (BCD encoded) + u8 trackF; // current frame location on the disc (BCD encoded) + u8 pad; // unused + u8 discM; // current minute offset from first track (BCD encoded) + u8 discS; // current sector offset from first track (BCD encoded) + u8 discF; // current frame offset from first track (BCD encoded) +} cdvdSubQ; + +typedef struct _cdvdTD { // NOT bcd coded + u32 lsn; + u8 type; +} cdvdTD; + +typedef struct _cdvdTN { + u8 strack; //number of the first track (usually 1) + u8 etrack; //number of the last track +} cdvdTN; + +// CDVDreadTrack mode values: +#define CDVD_MODE_2352 0 // full 2352 bytes +#define CDVD_MODE_2340 1 // skip sync (12) bytes +#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes +#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq + +// CDVDgetDiskType returns: +#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc +#define CDVD_TYPE_DVDV 0xfe // DVD Video +#define CDVD_TYPE_CDDA 0xfd // Audio CD +#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD +#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio) +#define CDVD_TYPE_PS2CD 0x12 // PS2 CD +#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio) +#define CDVD_TYPE_PSCD 0x10 // PS CD +#define CDVD_TYPE_UNKNOWN 0x05 // Unknown +#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided +#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided +#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd +#define CDVD_TYPE_DETCT 0x01 // Detecting +#define CDVD_TYPE_NODISC 0x00 // No Disc + +// CDVDgetTrayStatus returns: +#define CDVD_TRAY_CLOSE 0x00 +#define CDVD_TRAY_OPEN 0x01 + +// cdvdTD.type (track types for cds) +#define CDVD_AUDIO_TRACK 0x01 +#define CDVD_MODE1_TRACK 0x41 +#define CDVD_MODE2_TRACK 0x61 + +#define CDVD_AUDIO_MASK 0x00 +#define CDVD_DATA_MASK 0x40 +// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel) + +typedef void (*DEV9callback)(int cycles); +typedef int (*DEV9handler)(void); + +typedef void (*USBcallback)(int cycles); +typedef int (*USBhandler)(void); + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +typedef struct _GSdriverInfo { + char name[8]; + void *common; +} GSdriverInfo; + +#ifdef _WINDOWS_ +typedef struct _winInfo { // unsupported values must be set to zero + HWND hWnd; + HMENU hMenu; + HWND hStatusWnd; +} winInfo; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* GS plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef GSdefs + +// basic funcs + +s32 CALLBACK GSinit(); +s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread); +void CALLBACK GSclose(); +void CALLBACK GSshutdown(); +void CALLBACK GSvsync(int field); +void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr); +void CALLBACK GSgifTransfer2(u32 *pMem, u32 size); +void CALLBACK GSgifTransfer3(u32 *pMem, u32 size); +void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits) +void CALLBACK GSgifSoftReset(u32 mask); +void CALLBACK GSreadFIFO(u64 *mem); +void CALLBACK GSreadFIFO2(u64 *mem, int qwc); + +// extended funcs + +// GSkeyEvent gets called when there is a keyEvent from the PAD plugin +void CALLBACK GSkeyEvent(keyEvent *ev); +void CALLBACK GSchangeSaveState(int, const char* filename); +void CALLBACK GSmakeSnapshot(char *path); +void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg); +void CALLBACK GSirqCallback(void (*callback)()); +void CALLBACK GSprintf(int timeout, char *fmt, ...); +void CALLBACK GSsetBaseMem(void*); +void CALLBACK GSsetGameCRC(int crc, int gameoptions); + +// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done +void CALLBACK GSsetFrameSkip(int frameskip); + +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK GSsetupRecording(int start, void* pData); + +void CALLBACK GSreset(); +void CALLBACK GSwriteCSR(u32 value); +void CALLBACK GSgetDriverInfo(GSdriverInfo *info); +#ifdef _WIN32 +s32 CALLBACK GSsetWindowInfo(winInfo *info); +#endif +s32 CALLBACK GSfreeze(int mode, freezeData *data); +void CALLBACK GSconfigure(); +void CALLBACK GSabout(); +s32 CALLBACK GStest(); + +#endif + +/* PAD plugin API -=[ OBSOLETE ]=- */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef PADdefs + +// basic funcs + +s32 CALLBACK PADinit(u32 flags); +s32 CALLBACK PADopen(void *pDsp); +void CALLBACK PADclose(); +void CALLBACK PADshutdown(); +// PADkeyEvent is called every vsync (return NULL if no event) +keyEvent* CALLBACK PADkeyEvent(); +u8 CALLBACK PADstartPoll(int pad); +u8 CALLBACK PADpoll(u8 value); +// returns: 1 if supported pad1 +// 2 if supported pad2 +// 3 if both are supported +u32 CALLBACK PADquery(); + +// call to give a hint to the PAD plugin to query for the keyboard state. A +// good plugin will query the OS for keyboard state ONLY in this function. +// This function is necessary when multithreading because otherwise +// the PAD plugin can get into deadlocks with the thread that really owns +// the window (and input). Note that PADupdate can be called from a different +// thread than the other functions, so mutex or other multithreading primitives +// have to be added to maintain data integrity. +void CALLBACK PADupdate(int pad); + +// extended funcs + +void CALLBACK PADgsDriverInfo(GSdriverInfo *info); +void CALLBACK PADconfigure(); +void CALLBACK PADabout(); +s32 CALLBACK PADtest(); + +#endif + +/* SIO plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SIOdefs + +// basic funcs + +s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f); +s32 CALLBACK SIOopen(void *pDsp); +void CALLBACK SIOclose(); +void CALLBACK SIOshutdown(); +u8 CALLBACK SIOstartPoll(u8 value); +u8 CALLBACK SIOpoll(u8 value); +// returns: SIO_TYPE_{PAD,MTAP,RM,MC} +u32 CALLBACK SIOquery(); + +// extended funcs + +void CALLBACK SIOconfigure(); +void CALLBACK SIOabout(); +s32 CALLBACK SIOtest(); + +#endif + +/* SPU2 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef SPU2defs + +// basic funcs + +s32 CALLBACK SPU2init(); +s32 CALLBACK SPU2open(void *pDsp); +void CALLBACK SPU2close(); +void CALLBACK SPU2shutdown(); +void CALLBACK SPU2write(u32 mem, u16 value); +u16 CALLBACK SPU2read(u32 mem); +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2writeDMA4Mem(u16 *pMem, int size); +void CALLBACK SPU2interruptDMA4(); +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size); +void CALLBACK SPU2writeDMA7Mem(u16 *pMem, int size); + +// all addresses passed by dma will be pointers to the array starting at baseaddr +// This function is necessary to successfully save and reload the spu2 state +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr); + +void CALLBACK SPU2interruptDMA7(); +u32 CALLBACK SPU2ReadMemAddr(int core); +void CALLBACK SPU2WriteMemAddr(int core,u32 value); +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); + +// extended funcs +// if start is 1, starts recording spu2 data, else stops +// returns a non zero value if successful +// for now, pData is not used +int CALLBACK SPU2setupRecording(int start, void* pData); + +void CALLBACK SPU2setClockPtr(u32* ptr); +void CALLBACK SPU2setTimeStretcher(short int enable); + +void CALLBACK SPU2async(u32 cycles); +s32 CALLBACK SPU2freeze(int mode, freezeData *data); +void CALLBACK SPU2configure(); +void CALLBACK SPU2about(); +s32 CALLBACK SPU2test(); + +#endif + +/* CDVD plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef CDVDdefs + +// basic funcs + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(const char* pTitleFilename); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(u32 lsn, int mode); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); + +s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data) +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information +s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type +s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc +s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx +s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx +s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray +s32 CALLBACK CDVDctrlTrayClose(); //close disc tray + +// extended funcs + +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); +void CALLBACK CDVDnewDiskCB(void (*callback)()); + +#endif + +/* DEV9 plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef DEV9defs + +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK DEV9init(); +s32 CALLBACK DEV9open(void *pDsp); +void CALLBACK DEV9close(); +void CALLBACK DEV9shutdown(); +u8 CALLBACK DEV9read8(u32 addr); +u16 CALLBACK DEV9read16(u32 addr); +u32 CALLBACK DEV9read32(u32 addr); +void CALLBACK DEV9write8(u32 addr, u8 value); +void CALLBACK DEV9write16(u32 addr, u16 value); +void CALLBACK DEV9write32(u32 addr, u32 value); +void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size); +void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size); +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK DEV9irqCallback(DEV9callback callback); +DEV9handler CALLBACK DEV9irqHandler(void); + +// extended funcs + +s32 CALLBACK DEV9freeze(int mode, freezeData *data); +void CALLBACK DEV9configure(); +void CALLBACK DEV9about(); +s32 CALLBACK DEV9test(); + +#endif + +/* USB plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef USBdefs + +// basic funcs + +s32 CALLBACK USBinit(); +s32 CALLBACK USBopen(void *pDsp); +void CALLBACK USBclose(); +void CALLBACK USBshutdown(); +u8 CALLBACK USBread8(u32 addr); +u16 CALLBACK USBread16(u32 addr); +u32 CALLBACK USBread32(u32 addr); +void CALLBACK USBwrite8(u32 addr, u8 value); +void CALLBACK USBwrite16(u32 addr, u16 value); +void CALLBACK USBwrite32(u32 addr, u32 value); +void CALLBACK USBasync(u32 cycles); + +// cycles = IOP cycles before calling callback, +// if callback returns 1 the irq is triggered, else not +void CALLBACK USBirqCallback(USBcallback callback); +USBhandler CALLBACK USBirqHandler(void); +void CALLBACK USBsetRAM(void *mem); + +// extended funcs + +s32 CALLBACK USBfreeze(int mode, freezeData *data); +void CALLBACK USBconfigure(); +void CALLBACK USBabout(); +s32 CALLBACK USBtest(); + +#endif + +/* FW plugin API */ + +// if this file is included with this define +// the next api will not be skipped by the compiler +#ifdef FWdefs +// basic funcs + +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +s32 CALLBACK FWinit(); +s32 CALLBACK FWopen(void *pDsp); +void CALLBACK FWclose(); +void CALLBACK FWshutdown(); +u32 CALLBACK FWread32(u32 addr); +void CALLBACK FWwrite32(u32 addr, u32 value); +void CALLBACK FWirqCallback(void (*callback)()); + +// extended funcs + +s32 CALLBACK FWfreeze(int mode, freezeData *data); +void CALLBACK FWconfigure(); +void CALLBACK FWabout(); +s32 CALLBACK FWtest(); +#endif + +// might be useful for emulators +#ifdef PLUGINtypedefs + +typedef u32 (CALLBACK* _PS2EgetLibType)(void); +typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type); +typedef char*(CALLBACK* _PS2EgetLibName)(void); + +// GS +// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _GSinit)(); +typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread); +typedef void (CALLBACK* _GSclose)(); +typedef void (CALLBACK* _GSshutdown)(); +typedef void (CALLBACK* _GSvsync)(int field); +typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr); +typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size); +typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits) +typedef void (CALLBACK* _GSgifSoftReset)(u32 mask); +typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); +typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); + +typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev); +typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); +typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); +typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); +typedef void (CALLBACK* _GSsetBaseMem)(void*); +typedef void (CALLBACK* _GSsetGameCRC)(int, int); +typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); +typedef int (CALLBACK* _GSsetupRecording)(int, void*); +typedef void (CALLBACK* _GSreset)(); +typedef void (CALLBACK* _GSwriteCSR)(u32 value); +typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); +#ifdef _WINDOWS_ +typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info); +#endif +typedef void (CALLBACK* _GSmakeSnapshot)(const char *path); +typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); +typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _GSconfigure)(); +typedef s32 (CALLBACK* _GStest)(); +typedef void (CALLBACK* _GSabout)(); + +// PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); +typedef s32 (CALLBACK* _PADopen)(void *pDsp); +typedef void (CALLBACK* _PADclose)(); +typedef void (CALLBACK* _PADshutdown)(); +typedef keyEvent* (CALLBACK* _PADkeyEvent)(); +typedef u8 (CALLBACK* _PADstartPoll)(int pad); +typedef u8 (CALLBACK* _PADpoll)(u8 value); +typedef u32 (CALLBACK* _PADquery)(); +typedef void (CALLBACK* _PADupdate)(int pad); + +typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info); +typedef void (CALLBACK* _PADconfigure)(); +typedef s32 (CALLBACK* _PADtest)(); +typedef void (CALLBACK* _PADabout)(); + +// SIO +typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f); +typedef s32 (CALLBACK* _SIOopen)(void *pDsp); +typedef void (CALLBACK* _SIOclose)(); +typedef void (CALLBACK* _SIOshutdown)(); +typedef u8 (CALLBACK* _SIOstartPoll)(u8 value); +typedef u8 (CALLBACK* _SIOpoll)(u8 value); +typedef u32 (CALLBACK* _SIOquery)(); + +typedef void (CALLBACK* _SIOconfigure)(); +typedef s32 (CALLBACK* _SIOtest)(); +typedef void (CALLBACK* _SIOabout)(); + +// SPU2 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _SPU2init)(); +typedef s32 (CALLBACK* _SPU2open)(void *pDsp); +typedef void (CALLBACK* _SPU2close)(); +typedef void (CALLBACK* _SPU2shutdown)(); +typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value); +typedef u16 (CALLBACK* _SPU2read)(u32 mem); +typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2interruptDMA4)(); +typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size); +typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr); +typedef void (CALLBACK* _SPU2interruptDMA7)(); +typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()); +typedef int (CALLBACK* _SPU2setupRecording)(int, void*); + +typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr); +typedef void (CALLBACK* _SPU2setTimeStretcher)(short int enable); + +typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core); +typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value); +typedef void (CALLBACK* _SPU2async)(u32 cycles); +typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _SPU2configure)(); +typedef s32 (CALLBACK* _SPU2test)(); +typedef void (CALLBACK* _SPU2about)(); + + +// CDVD +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _CDVDinit)(); +typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename); +typedef void (CALLBACK* _CDVDclose)(); +typedef void (CALLBACK* _CDVDshutdown)(); +typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode); +typedef u8* (CALLBACK* _CDVDgetBuffer)(); +typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq); +typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer); +typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer); +typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc); +typedef s32 (CALLBACK* _CDVDgetDiskType)(); +typedef s32 (CALLBACK* _CDVDgetTrayStatus)(); +typedef s32 (CALLBACK* _CDVDctrlTrayOpen)(); +typedef s32 (CALLBACK* _CDVDctrlTrayClose)(); + +typedef void (CALLBACK* _CDVDconfigure)(); +typedef s32 (CALLBACK* _CDVDtest)(); +typedef void (CALLBACK* _CDVDabout)(); +typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)()); + +// DEV9 +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _DEV9init)(); +typedef s32 (CALLBACK* _DEV9open)(void *pDsp); +typedef void (CALLBACK* _DEV9close)(); +typedef void (CALLBACK* _DEV9shutdown)(); +typedef u8 (CALLBACK* _DEV9read8)(u32 mem); +typedef u16 (CALLBACK* _DEV9read16)(u32 mem); +typedef u32 (CALLBACK* _DEV9read32)(u32 mem); +typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value); +typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value); +typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value); +typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size); +typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback); +typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void); + +typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data); +typedef void (CALLBACK* _DEV9configure)(); +typedef s32 (CALLBACK* _DEV9test)(); +typedef void (CALLBACK* _DEV9about)(); + +// USB +// NOTE: The read/write functions CANNOT use XMM/MMX regs +// If you want to use them, need to save and restore current ones +typedef s32 (CALLBACK* _USBinit)(); +typedef s32 (CALLBACK* _USBopen)(void *pDsp); +typedef void (CALLBACK* _USBclose)(); +typedef void (CALLBACK* _USBshutdown)(); +typedef u8 (CALLBACK* _USBread8)(u32 mem); +typedef u16 (CALLBACK* _USBread16)(u32 mem); +typedef u32 (CALLBACK* _USBread32)(u32 mem); +typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value); +typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value); +typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _USBasync)(u32 cycles); + + +typedef void (CALLBACK* _USBirqCallback)(USBcallback callback); +typedef USBhandler (CALLBACK* _USBirqHandler)(void); +typedef void (CALLBACK* _USBsetRAM)(void *mem); + +typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _USBconfigure)(); +typedef s32 (CALLBACK* _USBtest)(); +typedef void (CALLBACK* _USBabout)(); + +//FW +typedef s32 (CALLBACK* _FWinit)(); +typedef s32 (CALLBACK* _FWopen)(void *pDsp); +typedef void (CALLBACK* _FWclose)(); +typedef void (CALLBACK* _FWshutdown)(); +typedef u32 (CALLBACK* _FWread32)(u32 mem); +typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value); +typedef void (CALLBACK* _FWirqCallback)(void (*callback)()); + +typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data); +typedef void (CALLBACK* _FWconfigure)(); +typedef s32 (CALLBACK* _FWtest)(); +typedef void (CALLBACK* _FWabout)(); + +#endif + +#ifdef PLUGINfuncs + +// GS +extern _GSinit GSinit; +extern _GSopen GSopen; +extern _GSclose GSclose; +extern _GSshutdown GSshutdown; +extern _GSvsync GSvsync; +extern _GSgifTransfer1 GSgifTransfer1; +extern _GSgifTransfer2 GSgifTransfer2; +extern _GSgifTransfer3 GSgifTransfer3; +extern _GSgetLastTag GSgetLastTag; +extern _GSgifSoftReset GSgifSoftReset; +extern _GSreadFIFO GSreadFIFO; +extern _GSreadFIFO2 GSreadFIFO2; + +extern _GSkeyEvent GSkeyEvent; +extern _GSchangeSaveState GSchangeSaveState; +extern _GSmakeSnapshot GSmakeSnapshot; +extern _GSmakeSnapshot2 GSmakeSnapshot2; +extern _GSirqCallback GSirqCallback; +extern _GSprintf GSprintf; +extern _GSsetBaseMem GSsetBaseMem; +extern _GSsetGameCRC GSsetGameCRC; +extern _GSsetFrameSkip GSsetFrameSkip; +extern _GSsetupRecording GSsetupRecording; +extern _GSreset GSreset; +extern _GSwriteCSR GSwriteCSR; +extern _GSgetDriverInfo GSgetDriverInfo; +#ifdef _WINDOWS_ +extern _GSsetWindowInfo GSsetWindowInfo; +#endif +extern _GSfreeze GSfreeze; +extern _GSconfigure GSconfigure; +extern _GStest GStest; +extern _GSabout GSabout; + +// PAD1 +extern _PADinit PAD1init; +extern _PADopen PAD1open; +extern _PADclose PAD1close; +extern _PADshutdown PAD1shutdown; +extern _PADkeyEvent PAD1keyEvent; +extern _PADstartPoll PAD1startPoll; +extern _PADpoll PAD1poll; +extern _PADquery PAD1query; +extern _PADupdate PAD1update; + +extern _PADgsDriverInfo PAD1gsDriverInfo; +extern _PADconfigure PAD1configure; +extern _PADtest PAD1test; +extern _PADabout PAD1about; + +// PAD2 +extern _PADinit PAD2init; +extern _PADopen PAD2open; +extern _PADclose PAD2close; +extern _PADshutdown PAD2shutdown; +extern _PADkeyEvent PAD2keyEvent; +extern _PADstartPoll PAD2startPoll; +extern _PADpoll PAD2poll; +extern _PADquery PAD2query; +extern _PADupdate PAD2update; + +extern _PADgsDriverInfo PAD2gsDriverInfo; +extern _PADconfigure PAD2configure; +extern _PADtest PAD2test; +extern _PADabout PAD2about; + +// SIO[2] +extern _SIOinit SIOinit[2][9]; +extern _SIOopen SIOopen[2][9]; +extern _SIOclose SIOclose[2][9]; +extern _SIOshutdown SIOshutdown[2][9]; +extern _SIOstartPoll SIOstartPoll[2][9]; +extern _SIOpoll SIOpoll[2][9]; +extern _SIOquery SIOquery[2][9]; + +extern _SIOconfigure SIOconfigure[2][9]; +extern _SIOtest SIOtest[2][9]; +extern _SIOabout SIOabout[2][9]; + +// SPU2 +extern _SPU2init SPU2init; +extern _SPU2open SPU2open; +extern _SPU2close SPU2close; +extern _SPU2shutdown SPU2shutdown; +extern _SPU2write SPU2write; +extern _SPU2read SPU2read; +extern _SPU2readDMA4Mem SPU2readDMA4Mem; +extern _SPU2writeDMA4Mem SPU2writeDMA4Mem; +extern _SPU2interruptDMA4 SPU2interruptDMA4; +extern _SPU2readDMA7Mem SPU2readDMA7Mem; +extern _SPU2writeDMA7Mem SPU2writeDMA7Mem; +extern _SPU2setDMABaseAddr SPU2setDMABaseAddr; +extern _SPU2interruptDMA7 SPU2interruptDMA7; +extern _SPU2ReadMemAddr SPU2ReadMemAddr; +extern _SPU2setupRecording SPU2setupRecording; +extern _SPU2WriteMemAddr SPU2WriteMemAddr; +extern _SPU2irqCallback SPU2irqCallback; + +extern _SPU2setClockPtr SPU2setClockPtr; +extern _SPU2setTimeStretcher SPU2setTimeStretcher; + +extern _SPU2async SPU2async; +extern _SPU2freeze SPU2freeze; +extern _SPU2configure SPU2configure; +extern _SPU2test SPU2test; +extern _SPU2about SPU2about; + +// CDVD +extern _CDVDinit CDVDinit; +extern _CDVDopen CDVDopen; +extern _CDVDclose CDVDclose; +extern _CDVDshutdown CDVDshutdown; +extern _CDVDreadTrack CDVDreadTrack; +extern _CDVDgetBuffer CDVDgetBuffer; +extern _CDVDreadSubQ CDVDreadSubQ; +extern _CDVDgetTN CDVDgetTN; +extern _CDVDgetTD CDVDgetTD; +extern _CDVDgetTOC CDVDgetTOC; +extern _CDVDgetDiskType CDVDgetDiskType; +extern _CDVDgetTrayStatus CDVDgetTrayStatus; +extern _CDVDctrlTrayOpen CDVDctrlTrayOpen; +extern _CDVDctrlTrayClose CDVDctrlTrayClose; + +extern _CDVDconfigure CDVDconfigure; +extern _CDVDtest CDVDtest; +extern _CDVDabout CDVDabout; +extern _CDVDnewDiskCB CDVDnewDiskCB; + +// DEV9 +extern _DEV9init DEV9init; +extern _DEV9open DEV9open; +extern _DEV9close DEV9close; +extern _DEV9shutdown DEV9shutdown; +extern _DEV9read8 DEV9read8; +extern _DEV9read16 DEV9read16; +extern _DEV9read32 DEV9read32; +extern _DEV9write8 DEV9write8; +extern _DEV9write16 DEV9write16; +extern _DEV9write32 DEV9write32; +extern _DEV9readDMA8Mem DEV9readDMA8Mem; +extern _DEV9writeDMA8Mem DEV9writeDMA8Mem; +extern _DEV9irqCallback DEV9irqCallback; +extern _DEV9irqHandler DEV9irqHandler; + +extern _DEV9configure DEV9configure; +extern _DEV9freeze DEV9freeze; +extern _DEV9test DEV9test; +extern _DEV9about DEV9about; + +// USB +extern _USBinit USBinit; +extern _USBopen USBopen; +extern _USBclose USBclose; +extern _USBshutdown USBshutdown; +extern _USBread8 USBread8; +extern _USBread16 USBread16; +extern _USBread32 USBread32; +extern _USBwrite8 USBwrite8; +extern _USBwrite16 USBwrite16; +extern _USBwrite32 USBwrite32; +extern _USBasync USBasync; + +extern _USBirqCallback USBirqCallback; +extern _USBirqHandler USBirqHandler; +extern _USBsetRAM USBsetRAM; + +extern _USBconfigure USBconfigure; +extern _USBfreeze USBfreeze; +extern _USBtest USBtest; +extern _USBabout USBabout; + +// FW +extern _FWinit FWinit; +extern _FWopen FWopen; +extern _FWclose FWclose; +extern _FWshutdown FWshutdown; +extern _FWread32 FWread32; +extern _FWwrite32 FWwrite32; +extern _FWirqCallback FWirqCallback; + +extern _FWconfigure FWconfigure; +extern _FWfreeze FWfreeze; +extern _FWtest FWtest; +extern _FWabout FWabout; +#endif + +#ifdef __cplusplus +} // End extern "C" +#endif + +#endif /* __PS2EDEFS_H__ */ diff --git a/plugins/zerospu2/common/PS2Etypes.h b/plugins/zerospu2/common/PS2Etypes.h new file mode 100644 index 0000000000..59be1c3de4 --- /dev/null +++ b/plugins/zerospu2/common/PS2Etypes.h @@ -0,0 +1,219 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef __PS2ETYPES_H__ +#define __PS2ETYPES_H__ + +#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case +#define __LINUX__ +#endif + +#ifdef __CYGWIN__ +#define __LINUX__ +#endif + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifdef __LINUX__ +#define CALLBACK +#else +#define CALLBACK __stdcall +#endif + + +// jASSUME - give hints to the optimizer +// This is primarily useful for the default case switch optimizer, which enables VC to +// generate more compact switches. + +#ifdef NDEBUG +# define jBREAKPOINT() ((void) 0) +# ifdef _MSC_VER +# define jASSUME(exp) (__assume(exp)) +# else +# define jASSUME(exp) ((void) sizeof(exp)) +# endif +#else +# if defined(_MSC_VER) +# define jBREAKPOINT() do { __asm int 3 } while(0) +# else +# define jBREAKPOINT() ((void) *(volatile char *) 0) +# endif +# define jASSUME(exp) if(exp) ; else jBREAKPOINT() +#endif + +// disable the default case in a switch +#define jNO_DEFAULT \ +{ \ + break; \ + \ +default: \ + jASSUME(0); \ + break; \ +} + + +// Basic types +#if defined(_MSC_VER) + +typedef __int8 s8; +typedef __int16 s16; +typedef __int32 s32; +typedef __int64 s64; + +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; + +typedef unsigned int uint; + +#define PCSX2_ALIGNED(alig,x) __declspec(align(alig)) x +#define PCSX2_ALIGNED16(x) __declspec(align(16)) x +#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x + +#define __naked __declspec(naked) + +#else // _MSC_VER + +#ifdef __LINUX__ + +#ifdef HAVE_STDINT_H +#include "stdint.h" + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uintptr_t uptr; +typedef intptr_t sptr; + +#else // HAVE_STDINT_H + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#endif // HAVE_STDINT_H + +typedef unsigned int uint; + +#define LONG long +typedef union _LARGE_INTEGER +{ + long long QuadPart; +} LARGE_INTEGER; + +#define __fastcall __attribute__((fastcall)) +#define __unused __attribute__((unused)) +#define _inline __inline__ __attribute__((unused)) +#define __forceinline __attribute__((always_inline,unused)) +#define __naked // GCC lacks the naked specifier + +#endif // __LINUX__ + +#define PCSX2_ALIGNED(alig,x) x __attribute((aligned(alig))) +#define PCSX2_ALIGNED16(x) x __attribute((aligned(16))) + +#define PCSX2_ALIGNED16_DECL(x) x + +#endif // _MSC_VER + +#if !defined(__LINUX__) || !defined(HAVE_STDINT_H) +#if defined(__x86_64__) +typedef u64 uptr; +typedef s64 sptr; +#else +typedef u32 uptr; +typedef s32 sptr; +#endif +#endif + +// A rough-and-ready cross platform 128-bit datatype, Non-SSE style. +#ifdef __cplusplus +struct u128 +{ + u64 lo; + u64 hi; + + // Implicit conversion from u64 + u128( u64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + u128( u32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +struct s128 +{ + s64 lo; + s64 hi; + + // Implicit conversion from u64 + s128( s64 src ) : + lo( src ) + , hi( 0 ) {} + + // Implicit conversion from u32 + s128( s32 src ) : + lo( src ) + , hi( 0 ) {} +}; + +#else + +typedef union _u128_t +{ + u64 lo; + u64 hi; +} u128; + +typedef union _s128_t +{ + s64 lo; + s64 hi; +} s128; + +#endif + +typedef struct { + int size; + s8 *data; +} freezeData; + +/* common defines */ +#ifndef C_ASSERT +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif + +#endif /* __PS2ETYPES_H__ */ diff --git a/plugins/zerospu2/compile b/plugins/zerospu2/compile new file mode 100644 index 0000000000..973c773214 --- /dev/null +++ b/plugins/zerospu2/compile @@ -0,0 +1 @@ +link /usr/share/automake-1.9/compile \ No newline at end of file diff --git a/plugins/zerospu2/configure.ac b/plugins/zerospu2/configure.ac new file mode 100644 index 0000000000..057d76a261 --- /dev/null +++ b/plugins/zerospu2/configure.ac @@ -0,0 +1,103 @@ +AC_INIT(ZeroSPU2,0.1,zerofrog@gmail.com) + +AM_INIT_AUTOMAKE(ZeroSPU2,0.1) + +AC_PROG_CC([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CXX([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CPP([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) + +AC_PROG_INSTALL +AC_PROG_RANLIB + +dnl necessary for compiling assembly +AM_PROG_AS + +ZEROSPU2_CURRENT=0 +ZEROSPU2_REVISION=1 +ZEROSPU2_AGE=0 +ZEROSPU2_SONAME=libZeroSPU2.so.[$ZEROSPU2_CURRENT].[$ZEROSPU2_REVISION].[$ZEROSPU2_AGE] +ZEROSPU2_RELEASE=[$ZEROSPU2_CURRENT].[$ZEROSPU2_REVISION].[$ZEROSPU2_AGE] + +AC_SUBST(ZEROSPU2_CURRENT) +AC_SUBST(ZEROSPU2_REVISION) +AC_SUBST(ZEROSPU2_AGE) +AC_SUBST(ZEROSPU2_RELEASE) +AC_SUBST(ZEROSPU2_SONAME) + +CFLAGS= +CPPFLAGS= +CXXFLAGS= + +dnl Check for debug build +AC_MSG_CHECKING(debug build) +AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [debug build]), + debug=$enableval,debug=no) +if test "x$debug" == xyes +then + AC_DEFINE(_DEBUG,1,[_DEBUG]) + CFLAGS+="-g -fPIC Wall -Wno-unused-value " + CPPFLAGS+="-g -fPIC -Wall -Wno-unused-value " + CXXFLAGS+="-g -fPIC -Wall -Wno-unused-value " +else + AC_DEFINE(NDEBUG,1,[NDEBUG]) + CFLAGS+="-O3 -fomit-frame-pointer -fPIC -Wall -Wno-unused-value " + CPPFLAGS+="-O3 -fomit-frame-pointer -fPIC -Wall -Wno-unused-value " + CXXFLAGS+="-O3 -fomit-frame-pointer -fPIC -Wall -Wno-unused-value " +fi +AM_CONDITIONAL(DEBUGBUILD, test x$debug = xyes) +AC_MSG_RESULT($debug) + +dnl Check for 64bit CPU +AC_MSG_CHECKING(for a x86-64 CPU) +dnl if test "$build_os" == "target_os" +dnl then +AC_TRY_RUN([ +int main() +{ +int a = 0; +int*pa = &a; +asm(".intel_syntax\n" + "mov %%rax, %0\n" + "mov %%eax, [%%rax]\n" + ".att_syntax\n" + : : "r"(pa) : "%rax"); +return 0; +} +],cpu64=yes,cpu64=no,) +dnl else +dnl cpu64=no +dnl fi +if test "x$cpu64" == xyes +then +AC_DEFINE(__x86_64__,1,[__x86_64__]) +fi +AC_MSG_RESULT($cpu64) +AM_CONDITIONAL(X86_64, test x$cpu64 = xyes) + +AC_CHECK_FUNCS([ _aligned_malloc _aligned_free ], AC_DEFINE(HAVE_ALIGNED_MALLOC)) + +dnl gtk +AC_MSG_CHECKING(gtk2+) +AC_CHECK_PROG(GTK_CONFIG, pkg-config, pkg-config) +LIBS+=$(pkg-config --libs gtk+-2.0) + +dnl bindir = pcsx2exe + +dnl assuming linux environment +so_ext=".so.$ZEROSPU2_RELEASE" +SHARED_LDFLAGS="-shared" +AC_SUBST(so_ext) +AC_SUBST(SHARED_LDFLAGS) + +AC_CHECK_LIB(stdc++,main,[LIBS="$LIBS -lstdc++"]) +AC_CHECK_LIB(dl,main,[LIBS="$LIBS -ldl"]) +AC_CHECK_LIB(asound,main,[LIBS="$LIBS -lasound"]) + +AC_OUTPUT([ + 3rdparty/SoundTouch/Makefile + Makefile + ]) + +echo "Configuration:" +echo " Debug build? $debug" +echo " x86-64 build? $cpu64" \ No newline at end of file diff --git a/plugins/zerospu2/depcomp b/plugins/zerospu2/depcomp new file mode 100644 index 0000000000..88b3a13969 --- /dev/null +++ b/plugins/zerospu2/depcomp @@ -0,0 +1,529 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/zerospu2/install-sh b/plugins/zerospu2/install-sh new file mode 100644 index 0000000000..4d4a9519ea --- /dev/null +++ b/plugins/zerospu2/install-sh @@ -0,0 +1,323 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2005-05-14.22 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# 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 Software. +# +# THE SOFTWARE IS 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 +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +chmodcmd="$chmodprog 0755" +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit $?;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit $?;; + + *) # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + test -n "$dir_arg$dstarg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + src= + + if test -d "$dst"; then + mkdircmd=: + chmodcmd= + else + mkdircmd=$mkdirprog + fi + else + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dst=$dst/`basename "$src"` + fi + fi + + # This sed command emulates the dirname command. + dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` + + # Make sure that the destination directory exists. + + # Skip lots of stat calls in the usual case. + if test ! -d "$dstdir"; then + defaultIFS=' + ' + IFS="${IFS-$defaultIFS}" + + oIFS=$IFS + # Some sh's can't handle IFS=/ for some reason. + IFS='%' + set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` + shift + IFS=$oIFS + + pathcomp= + + while test $# -ne 0 ; do + pathcomp=$pathcomp$1 + shift + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # mkdir can fail with a `File exist' error in case several + # install-sh are creating the directory concurrently. This + # is OK. + test -d "$pathcomp" || exit + fi + pathcomp=$pathcomp/ + done + fi + + if test -n "$dir_arg"; then + $doit $mkdircmd "$dst" \ + && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } + + else + dstfile=`basename "$dst"` + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + trap '(exit $?); exit' 1 2 13 15 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dstdir/$dstfile"; then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ + || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ + || { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + } + } + fi || { (exit 1); exit 1; } +done + +# The final little trick to "correctly" pass the exit status to the exit trap. +{ + (exit 0); exit 0 +} + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/zerospu2/misc.h b/plugins/zerospu2/misc.h new file mode 100644 index 0000000000..9a198108c8 --- /dev/null +++ b/plugins/zerospu2/misc.h @@ -0,0 +1,147 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 __LINUX__ +#include +#include +#include // ftime(), struct timeb + +#define Sleep(ms) usleep(1000*ms) + +inline unsigned long timeGetTime() +{ +#ifdef _WIN32 + _timeb t; + _ftime(&t); +#else + timeb t; + ftime(&t); +#endif + + return (unsigned long)(t.time*1000+t.millitm); +} + +#include + +#else +#include +#include + +#include // ftime(), struct timeb +#endif + +inline u64 GetMicroTime() +{ +#ifdef _WIN32 + extern LARGE_INTEGER g_counterfreq; + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + return count.QuadPart * 1000000 / g_counterfreq.QuadPart; +#else + timeval t; + gettimeofday(&t, NULL); + return t.tv_sec*1000000+t.tv_usec; +#endif +} + +#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) + +#include + +// declare linux equivalents +static __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) +{ + assert( align < 0x10000 ); + char* p = (char*)malloc(size+align); + int off = 2+align - ((int)(uptr)(p+2) % align); + + p += off; + *(u16*)(p-2) = off; + + return p; +} + +static __forceinline void pcsx2_aligned_free(void* pmem) +{ + if( pmem != NULL ) { + char* p = (char*)pmem; + free(p - (int)*(u16*)(p-2)); + } +} + +#define _aligned_malloc pcsx2_aligned_malloc +#define _aligned_free pcsx2_aligned_free +#endif + +// Atomic Operations +#if defined (_WIN32) + +#ifndef __x86_64__ +extern "C" LONG __cdecl _InterlockedExchangeAdd(LPLONG volatile Addend, LONG Value); +#endif + +#pragma intrinsic (_InterlockedExchangeAdd) +#define InterlockedExchangeAdd _InterlockedExchangeAdd + +#else + +//typedef void* PVOID; + +static __forceinline long InterlockedExchange(volatile long* Target, long Value) +{ + long result; + /* + * The XCHG instruction always locks the bus with or without the + * LOCKED prefix. This makes it significantly slower than CMPXCHG on + * uni-processor machines. The Windows InterlockedExchange function + * is nearly 3 times faster than the XCHG instruction, so this routine + * is not yet very useful for speeding up pthreads. + */ + + __asm__ __volatile__ ( + "xchgl %2,%1" + :"=r" (result) + :"m" (*Target), "0" (Value)); + + return result; +} + +static __forceinline long InterlockedExchangeAdd(volatile long* Addend, long Value) +{ + __asm__ __volatile__( + ".intel_syntax\n" + "lock xadd [%0], %%eax\n" + ".att_syntax\n" : : "r"(Addend), "a"(Value) : "memory"); +} + +static __forceinline long InterlockedCompareExchange(volatile long *dest, long value, long comp) +{ + long result; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchgl %2,%1" /* if (EAX == [location]) */ + /* [location] = value */ + /* else */ + /* EAX = [location] */ + :"=a" (result) + :"m" (*dest), "r" (value), "a" (comp)); + + return result; +} +#endif diff --git a/plugins/zerospu2/missing b/plugins/zerospu2/missing new file mode 100644 index 0000000000..894e786e16 --- /dev/null +++ b/plugins/zerospu2/missing @@ -0,0 +1,360 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2005-06-08.21 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/zerospu2/mkinstalldirs b/plugins/zerospu2/mkinstalldirs new file mode 100644 index 0000000000..259dbfcd35 --- /dev/null +++ b/plugins/zerospu2/mkinstalldirs @@ -0,0 +1,158 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2005-06-29.22 + +# Original author: Noah Friedman +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/plugins/zerospu2/reg.h b/plugins/zerospu2/reg.h new file mode 100644 index 0000000000..c5b6cfd429 --- /dev/null +++ b/plugins/zerospu2/reg.h @@ -0,0 +1,182 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 __REG_H__ +#define __REG_H__ + +//////////////////// +// SPU2 Registers // +//////////////////// +enum +{ +// Volume Registers - currently not implemented in ZeroSPU2, like most volume registers. + REG_VP_VOLL = 0x0000, // Voice Volume Left + REG_VP_VOLR = 0x0002, // Voice Volume Right + REG_VP_PITCH = 0x0004, // Pitch + REG_VP_ADSR1 = 0x0006, // Envelope 1 (Attack-Decay-Sustain-Release) + REG_VP_ADSR2 = 0x0008, // Envelope 2 (Attack-Decay-Sustain-Release) + REG_VP_ENVX = 0x000A, // Current Envelope + REG_VP_VOLXL = 0x000C, // Current Voice Volume Left + REG_VP_VOLXR = 0x000E, // Current Voice Volume Right +// end unimplemented section + + REG_C0_FMOD1 = 0x0180, // Pitch Modulation Spec. + REG_C0_FMOD2 = 0x0182, + REG_S_NON = 0x0184, // Alloc Noise Generator - unimplemented + REG_C0_VMIXL1 = 0x0188, // Voice Output Mix Left (Dry) + REG_C0_VMIXL2 = 0x018A, + REG_S_VMIXEL = 0x018C, // Voice Output Mix Left (Wet) - unimplemented + REG_C0_VMIXR1 = 0x0190, // Voice Output Mix Right (Dry) + REG_C0_VMIXR2 = 0x0192, + REG_S_VMIXER = 0x0194, // Voice Output Mix Right (Wet) - unimplemented + + REG_C0_MMIX = 0x0198, // Output Spec. After Voice Mix + REG_C0_CTRL = 0x019A, // Core X Attrib + REG_C0_IRQA_HI = 0x019C, // Interrupt Address Spec. - Hi + REG_C0_IRQA_LO = 0x019E, // Interrupt Address Spec. - Lo + + REG_C0_SPUON1 = 0x01A0, // Key On 0/1 + REG_C0_SPUON2 = 0x01A2, + REG_C0_SPUOFF1 = 0x01A4, // Key Off 0/1 + REG_C0_SPUOFF2 = 0x01A6, + + REG_C0_SPUADDR_HI = 0x01A8, // Transfer starting address - hi + REG_C0_SPUADDR_LO = 0x01AA, // Transfer starting address - lo + REG_C0_SPUDATA = 0x01AC, // Transfer data + REG_C0_DMACTRL = 0x01AE, // unimplemented + REG_C0_ADMAS = 0x01B0, // AutoDMA Status + + // Section Unimplemented + // Actually, some are implemented but weren't using the constants. + REG_VA_SSA = 0x01C0, // Waveform data starting address + REG_VA_LSAX = 0x01C4, // Loop point address + REG_VA_NAX = 0x01C8, // Waveform data that should be read next + REG_A_ESA = 0x02E0, //Address: Top address of working area for effects processing + R_FB_SRC_A = 0x02E4, // Feedback Source A + R_FB_SRC_B = 0x02E8, // Feedback Source B +R_IIR_DEST_A0 = 0x02EC, +R_IIR_DEST_A1 = 0x02F0, +R_ACC_SRC_A0 = 0x02F4, +R_ACC_SRC_A1 = 0x02F8, +R_ACC_SRC_B0 = 0x02FC, +R_ACC_SRC_B1 = 0x0300, +R_IIR_SRC_A0 = 0x0304, +R_IIR_SRC_A1 = 0x0308, +R_IIR_DEST_B0 = 0x030C, +R_IIR_DEST_B1 = 0x0310, +R_ACC_SRC_C0 = 0x0314, +R_ACC_SRC_C1 = 0x0318, +R_ACC_SRC_D0 = 0x031C, +R_ACC_SRC_D1 = 0x0320, +R_IIR_SRC_B1 = 0x0324, +R_IIR_SRC_B0 = 0x0328, +R_MIX_DEST_A0 = 0x032C, +R_MIX_DEST_A1 = 0x0330, +R_MIX_DEST_B0 = 0x0334, +R_MIX_DEST_B1 = 0x0338, + REG_A_EEA = 0x033C, // Address: End address of working area for effects processing (upper part of address only!) + // end unimplemented section + + REG_C0_END1 = 0x0340, // End Point passed flag + REG_C0_END2 = 0x0342, + REG_C0_SPUSTAT = 0x0344, // Status register? + + // core 1 has the same registers with 0x400 added, and ends at 0x746. + REG_C1_FMOD1 = 0x0580, + REG_C1_FMOD2 = 0x0582, + REG_C1_VMIXL1 = 0x0588, + REG_C1_VMIXL2 = 0x058A, + REG_C1_VMIXR1 = 0x0590, + REG_C1_VMIXR2 = 0x0592, + REG_C1_MMIX = 0x0598, + REG_C1_CTRL = 0x059A, + REG_C1_IRQA_HI = 0x059C, + REG_C1_IRQA_LO = 0x059E, + REG_C1_SPUON1 = 0x05A0, + REG_C1_SPUON2 = 0x05A2, + REG_C1_SPUOFF1 = 0x05A4, + REG_C1_SPUOFF2 = 0x05A6, + REG_C1_SPUADDR_HI = 0x05A8, + REG_C1_SPUADDR_LO = 0x05AA, + REG_C1_SPUDATA = 0x05AC, + REG_C1_DMACTRL = 0x05AE, // unimplemented + REG_C1_ADMAS = 0x05B0, + REG_C1_END1 = 0x0740, + REG_C1_END2 = 0x0742, + REG_C1_SPUSTAT = 0x0744, + + // Interesting to note that *most* of the volume controls aren't implemented in Zerospu2. + REG_P_MVOLL = 0x0760, // Master Volume Left - unimplemented + REG_P_MVOLR = 0x0762, // Master Volume Right - unimplemented + REG_P_EVOLL = 0x0764, // Effect Volume Left - unimplemented + REG_P_EVOLR = 0x0766, // Effect Volume Right - unimplemented + REG_P_AVOLL = 0x0768, // Core External Input Volume Left (Only Core 1) - unimplemented + REG_P_AVOLR = 0x076A, // Core External Input Volume Right (Only Core 1) - unimplemented + REG_C0_BVOLL = 0x076C, // Sound Data Volume Left + REG_C0_BVOLR = 0x076E, // Sound Data Volume Right + REG_P_MVOLXL = 0x0770, // Current Master Volume Left - unimplemented + REG_P_MVOLXR = 0x0772, // Current Master Volume Right - unimplemented + + // Another unimplemented section + R_IIR_ALPHA = 0x0774, // IIR alpha (% used) + R_ACC_COEF_A = 0x0776, + R_ACC_COEF_B = 0x0778, + R_ACC_COEF_C = 0x077A, + R_ACC_COEF_D = 0x077C, + R_IIR_COEF = 0x077E, + R_FB_ALPHA = 0x0780, // feedback alpha (% used) + R_FB_X = 0x0782, // feedback + R_IN_COEF_L = 0x0784, + R_IN_COEF_R = 0x0786, + // end unimplemented section + + REG_C1_BVOLL = 0x0794, + REG_C1_BVOLR = 0x0796, + + SPDIF_OUT = 0x07C0, // SPDIF Out: OFF/'PCM'/Bitstream/Bypass - unimplemented + REG_IRQINFO = 0x07C2, + SPDIF_MODE = 0x07C6, // unimplemented + SPDIF_MEDIA = 0x07C8, // SPDIF Media: 'CD'/DVD - unimplemented + SPDIF_COPY_PROT = 0x07CC // SPDIF Copy Protection - unimplemented + // NOTE: SPDIF_COPY is defined in Linux kernel headers as 0x0004. +}; + +// These SPDIF defines aren't used yet - swiped from spu2ghz, like a number of the registers I added in. +// -- arcum42 +#define SPDIF_OUT_OFF 0x0000 //no spdif output +#define SPDIF_OUT_PCM 0x0020 //encode spdif from spu2 pcm output +#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing + +#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data +#define SPDIF_MODE_BYPASS_PCM 0x0000 //bypass mode for pcm data (using analog output) + +#define SPDIF_MODE_MEDIA_CD 0x0800 //source media is a CD +#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD + +#define SPDIF_MEDIA_CDVD 0x0200 +#define SPDIF_MEDIA_400 0x0000 + +#define SPDIF_COPY_NORMAL 0x0000 // spdif stream is not protected +#define SPDIF_COPY_PROHIBIT 0x8000 // spdif stream can't be copied + +#define SPU_AUTODMA_ONESHOT 0 //spu2 +#define SPU_AUTODMA_LOOP 1 //spu2 +#define SPU_AUTODMA_START_ADDR (1 << 1) //spu2 + +#endif \ No newline at end of file diff --git a/plugins/zerospu2/voices.cpp b/plugins/zerospu2/voices.cpp new file mode 100644 index 0000000000..7d30fa4c8d --- /dev/null +++ b/plugins/zerospu2/voices.cpp @@ -0,0 +1,249 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include "zerospu2.h" + +#include "SoundTouch/SoundTouch.h" +#include "SoundTouch/WavFile.h" + + +// VOICE_PROCESSED definitions +SPU_CONTROL_* VOICE_PROCESSED::GetCtrl() +{ + return ((SPU_CONTROL_*)(spu2regs+memoffset+REG_C0_CTRL)); +} + +void VOICE_PROCESSED::SetVolume(int iProcessRight) +{ + u16 vol = iProcessRight ? pvoice->right.word : pvoice->left.word; + + if (vol&0x8000) // sweep not working + { + short sInc=1; // -> sweep up? + + if (vol&0x2000) sInc=-1; // -> or down? + if (vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this + + vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 + vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol*=128; + } + else // no sweep: + { + if (vol&0x4000) vol=0x3fff-(vol&0x3fff); // -> mmm... phase inverted? have to investigate this + } + + if ( iProcessRight ) + rightvol = vol&0x3fff; + else + leftvol = vol&0x3fff; + + bVolChanged = true; +} + +void VOICE_PROCESSED::StartSound() +{ + ADSRX.lVolume=1; // and init some adsr vars + ADSRX.State=0; + ADSRX.EnvelopeVol=0; + + if (bReverb && GetCtrl()->reverb) + { + // setup the reverb effects + } + + pCurr=pStart; // set sample start + + s_1=0; // init mixing vars + s_2=0; + iSBPos=28; + + bNew=false; // init channel flags + bStop=false; + bOn=true; + SB[29]=0; // init our interpolation helpers + SB[30]=0; + + spos=0x10000L; + SB[31]=0; +} + +void VOICE_PROCESSED::VoiceChangeFrequency() +{ + iUsedFreq=iActFreq; // -> take it and calc steps + sinc=(u32)pvoice->pitch<<4; + + if (!sinc) sinc=1; + + // -> freq change in simle imterpolation mode: set flag + SB[32]=1; +} + +void VOICE_PROCESSED::InterpolateUp() +{ + if (SB[32]==1) // flag == 1? calc step and set flag... and don't change the value in this pass + { + const int id1=SB[30]-SB[29]; // curr delta to next val + const int id2=SB[31]-SB[30]; // and next delta to next-next val :) + + SB[32]=0; + + if (id1>0) // curr delta positive + { + if (id2id1) + { + SB[28]=id1; + SB[32]=2; + } + else if (id2>(id1<<1)) + SB[28]=(id1*sinc)/0x10000L; + else + SB[28]=(id1*sinc)/0x20000L; + } + } + else if (SB[32]==2) // flag 1: calc step and set flag... and don't change the value in this pass + { + SB[32]=0; + + SB[28]=(SB[28]*sinc)/0x20000L; + if (sinc<=0x8000) + SB[29]=SB[30]-(SB[28]*((0x10000/sinc)-1)); + else + SB[29]+=SB[28]; + } + else // no flags? add bigger val (if possible), calc smaller step, set flag1 + SB[29]+=SB[28]; +} + +// +// even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm +// + +void VOICE_PROCESSED::InterpolateDown() +{ + if (sinc>=0x20000L) // we would skip at least one val? + { + SB[29]+=(SB[30]-SB[29])/2; // add easy weight + if (sinc>=0x30000L) // we would skip even more vals? + SB[29]+=(SB[31]-SB[30])/2; // add additional next weight + } +} + +void VOICE_PROCESSED::FModChangeFrequency(int ns) +{ + int NP=pvoice->pitch; + + NP=((32768L+iFMod[ns])*NP)/32768L; + + if (NP>0x3fff) NP=0x3fff; + if (NP<0x1) NP=0x1; + + NP = (SAMPLE_RATE * NP) / (4096L); // calc frequency + + iActFreq=NP; + iUsedFreq=NP; + sinc=(((NP/10)<<16)/4800); + if (!sinc) + sinc=1; + + // freq change in simple interpolation mode + SB[32]=1; + + iFMod[ns]=0; +} + +// fixme - noise handler... just produces some noise data +// surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used... +// and sometimes the noise will be used as fmod modulation... pfff +int VOICE_PROCESSED::iGetNoiseVal() +{ + int fa; + + if ((dwNoiseVal<<=1)&0x80000000L) + { + dwNoiseVal^=0x0040001L; + fa = ((dwNoiseVal>>2)&0x7fff); + fa = -fa; + } + else + fa=(dwNoiseVal>>2)&0x7fff; + + // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val + fa=iOldNoise + ((fa - iOldNoise) / ((0x001f - (GetCtrl()->noiseFreq)) + 1)); + + clamp16(fa); + + iOldNoise=fa; + SB[29] = fa; // -> store noise val in "current sample" slot + return fa; +} + +void VOICE_PROCESSED::StoreInterpolationVal(int fa) +{ + if (bFMod==2) // fmod freq channel + SB[29]=fa; + else + { + if (!GetCtrl()->spuUnmute) + fa=0; // muted? + else // else adjust + { + clamp16(fa); + } + + SB[28] = 0; + SB[29] = SB[30]; // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour' + SB[30] = SB[31]; + SB[31] = fa; + SB[32] = 1; // -> flag: calc new interolation + } +} + +int VOICE_PROCESSED::iGetInterpolationVal() +{ + int fa; + + if (bFMod==2) return SB[29]; + + if (sinc<0x10000L) // -> upsampling? + InterpolateUp(); // --> interpolate up + else + InterpolateDown(); // --> else down + + fa=SB[29]; + return fa; +} + +void VOICE_PROCESSED::Stop() +{ +} \ No newline at end of file diff --git a/plugins/zerospu2/zerodma.cpp b/plugins/zerospu2/zerodma.cpp new file mode 100644 index 0000000000..9578e68520 --- /dev/null +++ b/plugins/zerospu2/zerodma.cpp @@ -0,0 +1,271 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 "zerospu2.h" + +#include +#include + +#include "SoundTouch/SoundTouch.h" +#include "SoundTouch/WavFile.h" + +void CALLBACK SPU2readDMAMem(u16 *pMem, int size, int core) +{ + u32 spuaddr; + int i, dma, offset; + + if ( core == 0) + { + dma = 4; + offset = 0; + } + else + { + dma = 7; + offset = 0x0400; + } + + spuaddr = C_SPUADDR(core); + + SPU2_LOG("SPU2 readDMA%dMem size %x, addr: %x\n", dma, size, pMem); + + for (i=0; i < size; i++) + { + *pMem++ = *(u16*)(spu2mem + spuaddr); + if ((spu2Rs16(REG_C0_CTRL + offset) & 0x40) && (C_IRQA(core) == spuaddr)) + { + C_SPUADDR_SET(spuaddr, core); + IRQINFO |= (4 * (core + 1)); + SPU2_LOG("SPU2readDMA%dMem:interrupt\n", dma); + irqCallbackSPU2(); + } + + spuaddr++; // inc spu addr + if (spuaddr > 0x0fffff) spuaddr=0; // wrap at 2Mb + } + + spuaddr += 19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) + C_SPUADDR_SET(spuaddr, core); + + // DMA complete + spu2Ru16(REG_C0_SPUSTAT + offset) &= ~0x80; + SPUStartCycle[core] = SPUCycles; + SPUTargetCycle[core] = size; + interrupt |= (1 << (1 + core)); +} + +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size) +{ + LOG_CALLBACK("SPU2readDMA4Mem()\n"); + return SPU2readDMAMem(pMem, size, 0); +} + +void CALLBACK SPU2readDMA7Mem(u16* pMem, int size) +{ + LOG_CALLBACK("SPU2readDMA7Mem()\n"); + return SPU2readDMAMem(pMem, size, 1); +} + +// WRITE + +// AutoDMA's are used to transfer to the DIRECT INPUT area of the spu2 memory +// Left and Right channels are always interleaved together in the transfer so +// the AutoDMA's deinterleaves them and transfers them. An interrupt is +// generated when half of the buffer (256 short-words for left and 256 +// short-words for right ) has been transferred. Another interrupt occurs at +// the end of the transfer. + +int ADMASWrite(int core) +{ + u32 spuaddr; + ADMA *Adma; + int dma, offset; + + if (core == 0) + { + Adma = &Adma4; + dma = 4; + offset = 0; + } + else + { + Adma = &Adma7; + dma = 7; + offset = 0x0400; + } + + + if (interrupt & 0x2) + { + printf("%d returning for interrupt\n", dma); + return 0; + } + if (Adma->AmountLeft <= 0) + { + printf("%d amount left is 0\n", dma); + return 1; + } + + assert( Adma->AmountLeft >= 512 ); + spuaddr = C_SPUADDR(core); + + // SPU2 Deinterleaves the Left and Right Channels + memcpy((s16*)(spu2mem + spuaddr + 0x2000 + offset),(s16*)Adma->MemAddr,512); + Adma->MemAddr += 256; + memcpy((s16*)(spu2mem + spuaddr + 0x2200 + offset),(s16*)Adma->MemAddr,512); + Adma->MemAddr += 256; + + if ((spu2Ru16(REG_C0_CTRL + offset) & 0x40) && ((spuaddr + 0x2400) <= C_IRQA(core) && (spuaddr + 0x2400 + 256) >= C_IRQA(core))) + { + IRQINFO |= (4 * (core + 1)); + printf("ADMA %d Mem access:interrupt\n", dma); + irqCallbackSPU2(); + } + + if ((spu2Ru16(REG_C0_CTRL + offset) & 0x40) && ((spuaddr + 0x2600) <= C_IRQA(core) && (spuaddr + 0x2600 + 256) >= C_IRQA(core))) + { + IRQINFO |= (4 * (core + 1)); + printf("ADMA %d Mem access:interrupt\n", dma); + irqCallbackSPU2(); + } + + spuaddr = (spuaddr + 256) & 511; + C_SPUADDR_SET(spuaddr, core); + + Adma->AmountLeft -= 512; + + if (Adma->AmountLeft > 0) + return 0; + else + return 1; +} + +void CALLBACK SPU2writeDMAMem(u16* pMem, int size, int core) +{ + u32 spuaddr; + ADMA *Adma; + int dma, offset; + + if (core == 0) + { + Adma = &Adma4; + dma = 4; + offset = 0; + } + else + { + Adma = &Adma7; + dma = 7; + offset = 0x0400; + } + + SPU2_LOG("SPU2 writeDMA%dMem size %x, addr: %x(spu2:%x), ctrl: %x, adma: %x\n", \ + dma, size, pMem, C_SPUADDR(core), spu2Ru16(REG_C0_CTRL + offset), spu2Ru16(REG_C0_ADMAS + offset)); + + if ((spu2Ru16(REG_C0_ADMAS + offset) & 0x1 * (core + 1)) && ((spu2Ru16(REG_C0_CTRL + offset) & 0x30) == 0) && size) + { + if (!Adma->Enabled ) Adma->Index = 0; + + Adma->MemAddr = pMem; + Adma->AmountLeft = size; + SPUTargetCycle[core] = size; + spu2Ru16(REG_C0_SPUSTAT + offset) &= ~0x80; + if (!Adma->Enabled || (Adma->Index > 384)) + { + C_SPUADDR_SET(0, core); + if (ADMASWrite(core)) + { + SPUStartCycle[core] = SPUCycles; + interrupt |= (1 << (1 + core)); + } + } + Adma->Enabled = 1; + + return; + } + +#ifdef _DEBUG + if ((conf.Log && conf.options & OPTION_RECORDING) && (core == 1)) + LogPacketSound(pMem, 0x8000); +#endif + + spuaddr = C_SPUADDR(core); + memcpy((u8*)(spu2mem + spuaddr),(u8*)pMem,size << 1); + spuaddr += size; + C_SPUADDR_SET(spuaddr, core); + + if ((spu2Ru16(REG_C0_CTRL + offset)&0x40) && (spuaddr < C_IRQA(core) && (C_IRQA(core) <= (spuaddr+0x20)))) + { + IRQINFO |= 4 * (core + 1); + SPU2_LOG("SPU2writeDMA%dMem:interrupt\n", dma); + irqCallbackSPU2(); + } + + if (spuaddr > 0xFFFFE) spuaddr = 0x2800; + C_SPUADDR_SET(spuaddr, core); + + MemAddr[core] += size << 1; + spu2Ru16(REG_C0_SPUSTAT + offset) &= ~0x80; + SPUStartCycle[core] = SPUCycles; + SPUTargetCycle[core] = size; + interrupt |= (1 << (core + 1)); +} + +void CALLBACK SPU2writeDMA4Mem(u16* pMem, int size) +{ + LOG_CALLBACK("SPU2writeDMA4Mem()\n"); + SPU2writeDMAMem(pMem, size, 0); +} + +void CALLBACK SPU2writeDMA7Mem(u16* pMem, int size) +{ + LOG_CALLBACK("SPU2writeDMA7Mem()\n"); + SPU2writeDMAMem(pMem, size, 1); +} + +void CALLBACK SPU2interruptDMA(int core) +{ + int dma, offset; + + if (core == 0) + { + dma = 4; + offset = 0; + } + else + { + dma = 7; + offset = 0x0400; + } + + SPU2_LOG("SPU2 interruptDMA%d\n", dma); + spu2Rs16(REG_C0_CTRL + offset) &= ~0x30; + spu2Ru16(REG_C0_SPUSTAT + offset) |= 0x80; +} + +void CALLBACK SPU2interruptDMA4() +{ + LOG_CALLBACK("SPU2interruptDMA4()\n"); + SPU2interruptDMA(0); +} + +void CALLBACK SPU2interruptDMA7() +{ + LOG_CALLBACK("SPU2interruptDMA7()\n"); + SPU2interruptDMA(1); +} \ No newline at end of file diff --git a/plugins/zerospu2/zerospu2.cpp b/plugins/zerospu2/zerospu2.cpp new file mode 100644 index 0000000000..c9130d3674 --- /dev/null +++ b/plugins/zerospu2/zerospu2.cpp @@ -0,0 +1,1632 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 "zerospu2.h" + +#include +#include + +#ifdef _WIN32 +#include "svnrev.h" +#endif + +#include "SoundTouch/SoundTouch.h" +#include "SoundTouch/WavFile.h" + +char libraryName[256]; + +FILE *spu2Log; +Config conf; + +ADMA Adma4; +ADMA Adma7; + +u32 MemAddr[2]; +u32 g_nSpuInit = 0; +u16 interrupt = 0; +s8 *spu2regs = NULL; +u16* spu2mem = NULL; +u16* pSpuIrq[2] = {NULL}; +u32 dwNewChannel2[2] = {0}; // keeps track of what channels that have been turned on +u32 dwEndChannel2[2] = {0}; // keeps track of what channels have ended +unsigned long dwNoiseVal=1; // global noise generator +bool g_bPlaySound = true; // if true, will output sound, otherwise no +int iFMod[NSSIZE]; +int s_buffers[NSSIZE][2]; // left and right buffers + +// mixer thread variables +static bool s_bThreadExit = true; +static int s_nDropPacket = 0; +string s_strIniPath="inis/zerospu2.ini"; + +#ifdef _WIN32 +LARGE_INTEGER g_counterfreq; +extern HWND hWMain; +HANDLE s_threadSPU2 = NULL; +DWORD WINAPI SPU2ThreadProc(LPVOID); +#else +#include +pthread_t s_threadSPU2; +void* SPU2ThreadProc(void*); +#endif + +static AUDIOBUFFER s_pAudioBuffers[NSPACKETS]; +static int s_nCurBuffer = 0, s_nQueuedBuffers = 0; +static s16* s_pCurOutput = NULL; +static u32 g_startcount=0xffffffff; +static u32 g_packetcount=0; + +// time stretch variables +soundtouch::SoundTouch* pSoundTouch=NULL; +WavOutFile* g_pWavRecord=NULL; // used for recording + +static u64 s_GlobalTimeStamp = 0; +static int s_nDurations[64]={0}; +static int s_nCurDuration=0; +static int s_nTotalDuration=0; + +int SPUCycles = 0, SPUWorkerCycles = 0; +int SPUStartCycle[2]; +int SPUTargetCycle[2]; + +int g_logsound=0; + +int ADMASWrite(int c); + +void InitADSR(); + +// functions of main emu, called on spu irq +void (*irqCallbackSPU2)()=0; +void (*irqCallbackDMA4)()=0; +void (*irqCallbackDMA7)()=0; + +uptr g_pDMABaseAddr=0; + +const int f[5][2] = { + { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 } }; + +u32 RateTable[160]; + +// channels and voices +VOICE_PROCESSED voices[SPU_NUMBER_VOICES+1]; // +1 for modulation + +static void InitLibraryName() +{ +#ifdef _WIN32 +#ifdef PUBLIC + + // Public Release! + // Output a simplified string that's just our name: + + strcpy( libraryName, "ZeroSPU2 Playground" ); + +#elif defined( SVN_REV_UNKNOWN ) + + // Unknown revision. + // Output a name that includes devbuild status but not + // subversion revision tags: + + strcpy( libraryName, "ZeroSPU2 Playground" +# ifdef _DEBUG + "-Debug" +# endif + ); +#else + + // Use TortoiseSVN's SubWCRev utility's output + // to label the specific revision: + + sprintf_s( libraryName, "ZeroSPU2 PG r%d%s" +# ifdef _DEBUG + "-Debug" +# else + "-Dev" +# endif + ,SVN_REV, + SVN_MODS ? "m" : "" + ); +#endif +#else +// I'll hook in svn version code later. --arcum42 + + strcpy( libraryName, "ZeroSPU2 Playground" +# ifdef _DEBUG + "-Debug" +# endif + ); +# endif + +} + +u32 CALLBACK PS2EgetLibType() +{ + return PS2E_LT_SPU2; +} + +char* CALLBACK PS2EgetLibName() +{ + InitLibraryName(); + return libraryName; +} + +u32 CALLBACK PS2EgetLibVersion2(u32 type) +{ + return (SPU2_MINOR<<24) | (SPU2_VERSION<<16) | (SPU2_REVISION<<8) | SPU2_BUILD; +} + +void __Log(char *fmt, ...) +{ + va_list list; + + if (!conf.Log || spu2Log == NULL) return; + + va_start(list, fmt); + vfprintf(spu2Log, fmt, list); + va_end(list); +} + +s32 CALLBACK SPU2init() +{ + LOG_CALLBACK("SPU2init()\n"); + spu2Log = fopen("logs/spu2.txt", "w"); + if (spu2Log) setvbuf(spu2Log, NULL, _IONBF, 0); + + SPU2_LOG("Spu2 null version %d,%d\n",SPU2_REVISION,SPU2_BUILD); + SPU2_LOG("SPU2init\n"); + +#ifdef _WIN32 + QueryPerformanceFrequency(&g_counterfreq); +#else + char strcurdir[256]; + getcwd(strcurdir, 256); + s_strIniPath = strcurdir; + s_strIniPath += "/inis/zerospu2.ini"; +#endif + + spu2regs = (s8*)malloc(0x10000); + spu2mem = (u16*)malloc(0x200000); // 2Mb + memset(spu2regs, 0, 0x10000); + memset(spu2mem, 0, 0x200000); + if ((spu2mem == NULL) || (spu2regs == NULL)) + { + SysMessage("Error allocating Memory\n"); + return -1; + } + + memset(dwEndChannel2, 0, sizeof(dwEndChannel2)); + memset(dwNewChannel2, 0, sizeof(dwNewChannel2)); + memset(iFMod, 0, sizeof(iFMod)); + memset(s_buffers, 0, sizeof(s_buffers)); + + InitADSR(); + + memset(voices, 0, sizeof(voices)); + // last 24 channels have higher mem offset + for (int i = 0; i < 24; ++i) + voices[i+24].memoffset = 0x400; + + // init each channel + for (u32 i = 0; i < ARRAYSIZE(voices); ++i) { + voices[i].chanid = i; + voices[i].pLoop = voices[i].pStart = voices[i].pCurr = (u8*)spu2mem; + + voices[i].pvoice = (_SPU_VOICE*)((u8*)spu2regs+voices[i].memoffset)+(i%24); + voices[i].ADSRX.SustainLevel = 1024; // -> init sustain + } + + return 0; +} + +s32 CALLBACK SPU2open(void *pDsp) +{ + LOG_CALLBACK("SPU2open()\n"); +#ifdef _WIN32 + hWMain = pDsp == NULL ? NULL : *(HWND*)pDsp; + if (!IsWindow(hWMain)) + hWMain=GetActiveWindow(); +#endif + + LoadConfig(); + + SPUCycles = SPUWorkerCycles = 0; + interrupt = 0; + SPUStartCycle[0] = SPUStartCycle[1] = 0; + SPUTargetCycle[0] = SPUTargetCycle[1] = 0; + s_nDropPacket = 0; + + if ( conf.options & OPTION_TIMESTRETCH ) + { + pSoundTouch = new soundtouch::SoundTouch(); + pSoundTouch->setSampleRate(SAMPLE_RATE); + pSoundTouch->setChannels(2); + pSoundTouch->setTempoChange(0); + + pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 0); + pSoundTouch->setSetting(SETTING_USE_AA_FILTER, 1); + } + + //conf.Log = 1; + + g_bPlaySound = !(conf.options&OPTION_MUTE); + + if ( g_bPlaySound && SetupSound() != 0 ) + { + SysMessage("ZeroSPU2: Failed to initialize sound"); + g_bPlaySound = false; + } + + if ( g_bPlaySound ) { + // initialize the audio buffers + for (u32 i = 0; i < ARRAYSIZE(s_pAudioBuffers); ++i) + { + s_pAudioBuffers[i].pbuf = (u8*)_aligned_malloc(4*NSSIZE*NSFRAMES, 16); // 4 bytes for each sample + s_pAudioBuffers[i].len = 0; + } + + s_nCurBuffer = 0; + s_nQueuedBuffers = 0; + s_pCurOutput = (s16*)s_pAudioBuffers[0].pbuf; + assert( s_pCurOutput != NULL); + + for (int i = 0; i < ARRAYSIZE(s_nDurations); ++i) + { + s_nDurations[i] = NSFRAMES*1000; + } + s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; + s_nCurDuration = 0; + + // launch the thread + s_bThreadExit = false; +#ifdef _WIN32 + s_threadSPU2 = CreateThread(NULL, 0, SPU2ThreadProc, NULL, 0, NULL); + if ( s_threadSPU2 == NULL ) + { + return -1; + } +#else + if ( pthread_create(&s_threadSPU2, NULL, SPU2ThreadProc, NULL) != 0 ) + { + SysMessage("ZeroSPU2: Failed to create spu2thread\n"); + return -1; + } +#endif + } + + g_nSpuInit = 1; + return 0; +} + +void CALLBACK SPU2close() +{ + LOG_CALLBACK("SPU2close()\n"); + g_nSpuInit = 0; + + if ( g_bPlaySound && !s_bThreadExit ) { + s_bThreadExit = true; + printf("ZeroSPU2: Waiting for thread... "); +#ifdef _WIN32 + WaitForSingleObject(s_threadSPU2, INFINITE); + CloseHandle(s_threadSPU2); s_threadSPU2 = NULL; +#else + pthread_join(s_threadSPU2, NULL); +#endif + printf("done\n"); + } + + RemoveSound(); + + delete g_pWavRecord; g_pWavRecord = NULL; + delete pSoundTouch; pSoundTouch = NULL; + + for (u32 i = 0; i < ARRAYSIZE(s_pAudioBuffers); ++i) + { + _aligned_free(s_pAudioBuffers[i].pbuf); + } + memset(s_pAudioBuffers, 0, sizeof(s_pAudioBuffers)); +} + +void CALLBACK SPU2shutdown() +{ + LOG_CALLBACK("SPU2shutdown()\n"); + free(spu2regs); spu2regs = NULL; + free(spu2mem); spu2mem = NULL; + + if (spu2Log) fclose(spu2Log); +} + +void CALLBACK SPU2async(u32 cycle) +{ + //LOG_CALLBACK("SPU2async()\n"); + SPUCycles += cycle; + + if (interrupt & (1<<2)) + { + if (SPUCycles - SPUStartCycle[1] >= SPUTargetCycle[1]) + { + interrupt &= ~(1<<2); + irqCallbackDMA7(); + } + + } + + if (interrupt & (1<<1)) + { + if (SPUCycles - SPUStartCycle[0] >= SPUTargetCycle[0]) + { + interrupt &= ~(1<<1); + irqCallbackDMA4(); + } + } + + if ( g_nSpuInit ) + { + while( SPUCycles-SPUWorkerCycles > 0 && CYCLES_PER_MS < SPUCycles-SPUWorkerCycles ) + { + SPU2Worker(); + SPUWorkerCycles += CYCLES_PER_MS; + } + } + else + SPUWorkerCycles = SPUCycles; +} + +void InitADSR() // INIT ADSR +{ + u32 r,rs,rd; + int i; + memset(RateTable,0,sizeof(u32)*160); // build the rate table according to Neill's rules (see at bottom of file) + + r=3;rs=1;rd=0; + + for (i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 + { + if (r<0x3FFFFFFF) + { + r+=rs; + rd++; + + if (rd==5) + { + rd=1; + rs*=2; + } + } + + if (r>0x3FFFFFFF) r=0x3FFFFFFF; + RateTable[i]=r; + } +} + +int MixADSR(VOICE_PROCESSED* pvoice) // MIX ADSR +{ + u32 rateadd[8] = { 0, 4, 6, 8, 9, 10, 11, 12 }; + + if (pvoice->bStop) // should be stopped: + { + if (pvoice->ADSRX.ReleaseModeExp) // do release + { + s32 temp = ((pvoice->ADSRX.EnvelopeVol>>28)&0x7); + pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F)) - 0x18 + rateadd[temp] + 32]; + } + else + { + pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F)) - 0x0C + 32]; + } + + // bIgnoreLoop sets EnvelopeVol to 0 anyways, so we can use one if statement rather then two. + if ((pvoice->ADSRX.EnvelopeVol<0) || (pvoice->bIgnoreLoop == 0)) + { + pvoice->ADSRX.EnvelopeVol=0; + pvoice->bOn=false; + pvoice->pStart= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pLoop= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->pCurr= (u8*)(spu2mem+pvoice->iStartAddr); + pvoice->bStop = true; + pvoice->bIgnoreLoop = false; + //pvoice->bReverb=0; + //pvoice->bNoise=0; + } + + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + + return pvoice->ADSRX.lVolume; + } + else // not stopped yet? + { + s32 temp = ((pvoice->ADSRX.EnvelopeVol>>28)&0x7); + + switch (pvoice->ADSRX.State) + { + case 0: // -> attack + if (pvoice->ADSRX.AttackModeExp) + { + if (pvoice->ADSRX.EnvelopeVol<0x60000000) + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F) - 0x10 + 32]; + else + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F) - 0x18 + 32]; + } + else + { + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F) - 0x10 + 32]; + } + + if (pvoice->ADSRX.EnvelopeVol<0) + { + pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; + pvoice->ADSRX.State=1; + } + break; + + case 1: // -> decay + pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F)) - 0x18+ rateadd[temp] + 32]; + + if (pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0; + + if (((pvoice->ADSRX.EnvelopeVol>>27)&0xF) <= pvoice->ADSRX.SustainLevel) + pvoice->ADSRX.State=2; + break; + + case 2: // -> sustain + if (pvoice->ADSRX.SustainIncrease) + { + if ((pvoice->ADSRX.SustainModeExp) && (pvoice->ADSRX.EnvelopeVol>=0x60000000)) + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F) - 0x18 + 32]; + else + pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F) - 0x10 + 32]; + + if (pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; + } + else + { + if (pvoice->ADSRX.SustainModeExp) + pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F)) - 0x1B +rateadd[temp] + 32]; + else + pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F)) - 0x0F + 32]; + + if (pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0; + } + break; + + default: + // This should never happen. + return 0; + } + + pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; + return pvoice->ADSRX.lVolume; + } + + return 0; +} + +void MixChannels(int core) +{ + // mix all channels + int c_offset = 0x0400 * core; + int dma; + ADMA *Adma; + + if (core == 0) + { + Adma = &Adma4; + dma = 4; + } + else + { + Adma = &Adma7; + dma = 7; + } + + if ((spu2Ru16(REG_C0_MMIX + c_offset) & 0xF0) && (spu2Ru16(REG_C0_ADMAS + c_offset) & (0x1 + core))) + { + for (int ns=0;nsIndex]*(int)spu2Ru16(REG_C0_BVOLL + c_offset))>>16; + if ((spu2Ru16(REG_C0_MMIX + c_offset) & 0x40)) + s_buffers[ns][1] += (((short*)spu2mem)[0x2200 + c_offset +Adma->Index]*(int)spu2Ru16(REG_C0_BVOLR + c_offset))>>16; + + Adma->Index +=1; + MemAddr[core] += 4; + + if (Adma->Index == 128 || Adma->Index == 384) + { + if (ADMASWrite(core)) + { + if (interrupt & (0x2 * (core + 1))) + { + interrupt &= ~(0x2 * (core + 1)); + printf("Stopping double interrupt DMA7\n"); + } + if (core == 0) + irqCallbackDMA4(); + else + irqCallbackDMA7(); + + } + if (core == 1) Adma->Enabled = 2; + } + + if (Adma->Index == 512) + { + if ( Adma->Enabled == 2 ) Adma->Enabled = 0; + Adma->Index = 0; + } + } + } +} + +// simulate SPU2 for 1ms +void SPU2Worker() +{ + int s_1,s_2,fa; + u8* start; + u32 nSample; + int ch,predict_nr,shift_factor,flags,d,s; + + // assume s_buffers are zeroed out + if ( dwNewChannel2[0] || dwNewChannel2[1] ) + s_pAudioBuffers[s_nCurBuffer].newchannels++; + + VOICE_PROCESSED* pChannel=voices; + for (ch=0;chbNew) + { + pChannel->StartSound(); // start new sound + dwEndChannel2[ch/24]&=~(1<<(ch%24)); // clear end channel bit + dwNewChannel2[ch/24]&=~(1<<(ch%24)); // clear channel bit + } + + if (!pChannel->bOn) continue; + + if (pChannel->iActFreq!=pChannel->iUsedFreq) // new psx frequency? + pChannel->VoiceChangeFrequency(); + + // loop until 1 ms of data is reached + int ns = 0; + + while(nsbFMod==1 && iFMod[ns]) // fmod freq channel + pChannel->FModChangeFrequency(ns); + + while(pChannel->spos >= 0x10000 ) + { + if (pChannel->iSBPos == 28) // 28 reached? + { + start=pChannel->pCurr; // set up the current pos + + // special "stop" sign - fixme - an *unsigned* -1? + if (start == (u8*)-1) //!pChannel->bOn + { + pChannel->bOn=false; // -> turn everything off + pChannel->ADSRX.lVolume=0; + pChannel->ADSRX.EnvelopeVol=0; + goto ENDX; // -> and done for this channel + } + + pChannel->iSBPos=0; + + // decode the 16byte packet + s_1=pChannel->s_1; + s_2=pChannel->s_2; + + predict_nr=(s32)start[0]; + shift_factor=predict_nr&0xf; + predict_nr >>= 4; + flags=(s32)start[1]; + start += 2; + + for (nSample=0;nSample<28; ++start) + { + d = (int)*start; + s = ((d & 0xf)<<12); + if (s & 0x8000) s |= 0xffff0000; + + fa = (s >> shift_factor); + fa += ((s_1 * f[predict_nr][0]) >> 6) + ((s_2 * f[predict_nr][1]) >> 6); + s_2 = s_1; + s_1 = fa; + s = ((d & 0xf0) << 8); + + pChannel->SB[nSample++]=fa; + + if (s & 0x8000) s|=0xffff0000; + fa = (s>>shift_factor); + fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1]) >> 6); + s_2 = s_1; + s_1 = fa; + + pChannel->SB[nSample++]=fa; + } + + // irq occurs no matter what core access the address + for (int core = 0; core < 2; ++core) + { + if (((SPU_CONTROL_*)(spu2regs + 0x400 * core + REG_C0_CTRL))->irq) // some callback and irq active? + { + // if irq address reached or irq on looping addr, when stop/loop flag is set + u8* pirq = (u8*)pSpuIrq[core]; + if ((pirq > (start - 16) && pirq <= start) || ((flags & 1) && (pirq > (pChannel->pLoop - 16) && pirq <= pChannel->pLoop))) + { + IRQINFO |= 4<bIgnoreLoop)) + pChannel->pLoop=start-16; // loop adress + + if (flags&1) // 1: stop/loop + { + // We play this block out first... + dwEndChannel2[ch/24]|=(1<<(ch%24)); + + if (flags!=3 || pChannel->pLoop==NULL) + { // and checking if pLoop is set avoids crashes, yeah + start = (u8*)-1; + pChannel->bStop = true; + pChannel->bIgnoreLoop = false; + } + else + { + start = pChannel->pLoop; + } + } + + pChannel->pCurr=start; // store values for next cycle + pChannel->s_1=s_1; + pChannel->s_2=s_2; + } + + fa=pChannel->SB[pChannel->iSBPos++]; // get sample data + pChannel->StoreInterpolationVal(fa); + pChannel->spos -= 0x10000; + } + + if (pChannel->bNoise) + fa=pChannel->iGetNoiseVal(); // get noise val + else + fa=pChannel->iGetInterpolationVal(); // get sample val + + int sval = (MixADSR(pChannel) * fa) / 1023; // mix adsr + + if (pChannel->bFMod == 2) // fmod freq channel + { + iFMod[ns] = sval; // -> store 1T sample data, use that to do fmod on next channel + } + else + { + if (pChannel->bVolumeL) + s_buffers[ns][0]+=(sval * pChannel->leftvol)>>14; + + if (pChannel->bVolumeR) + s_buffers[ns][1]+=(sval * pChannel->rightvol)>>14; + } + + // go to the next packet + ns++; + pChannel->spos += pChannel->sinc; + } +ENDX: + ; + } + + // mix all channels + /*MixChannels(0); + MixChannels(1);*/ + + + // mix all channels + // This code is temporarily being put back, till I work out why the replacement is breaking things, --arcum42 + if ((spu2Ru16(REG_C0_MMIX) & 0xF0) && (spu2Ru16(REG_C0_ADMAS) & 0x1) /*&& !(spu2Ru16(REG_C0_CTRL) & 0x30)*/) + { + ADMA *Adma = &Adma4; + + for (int ns=0;nsIndex]*(int)spu2Ru16(REG_C0_BVOLL))>>16; + if ((spu2Ru16(REG_C0_MMIX) & 0x40)) + s_buffers[ns][1] += (((short*)spu2mem)[0x2200+Adma->Index]*(int)spu2Ru16(REG_C0_BVOLR))>>16; + + Adma->Index +=1; + // just add after every sample, it is better than adding 1024 all at once (games like Genji don't like it) + MemAddr[0] += 4; + + if ((Adma->Index == 128) || (Adma->Index == 384)) + { + if (ADMASWrite(0)) + { + if (interrupt & 0x2) + { + interrupt &= ~0x2; + printf("Stopping double interrupt DMA4\n"); + } + irqCallbackDMA4(); + + } + } + + if (Adma->Index == 512) + { + if ( Adma->Enabled == 2 ) + { + Adma->Enabled = 0; + } + Adma->Index = 0; + } + } + } + + // Let's do the same bloody mixing code again, only for C1. + // fixme - There is way too much duplication of code between C0 & C1, and Adma4 & Adma7. + // arcum42 + if ((spu2Ru16(REG_C1_MMIX) & 0xF0) && (spu2Ru16(REG_C1_ADMAS) & 0x2)) + { + ADMA *Adma = &Adma7; + + for (int ns=0;nsIndex]*(int)spu2Ru16(REG_C1_BVOLL))>>16; + if ((spu2Ru16(REG_C1_MMIX) & 0x40)) + s_buffers[ns][1] += (((short*)spu2mem)[0x2600+Adma->Index]*(int)spu2Ru16(REG_C1_BVOLR))>>16; + + Adma->Index +=1; + MemAddr[1] += 4; + + if (Adma->Index == 128 || Adma->Index == 384) + { + if (ADMASWrite(1)) + { + if (interrupt & 0x4) + { + interrupt &= ~0x4; + printf("Stopping double interrupt DMA7\n"); + } + irqCallbackDMA7(); + + } + Adma->Enabled = 2; + } + + if (Adma->Index == 512) + { + if ( Adma->Enabled == 2 ) Adma->Enabled = 0; + Adma->Index = 0; + } + } + } + + if ( g_bPlaySound ) + { + assert( s_pCurOutput != NULL); + + for (int ns=0; ns= 4 * NSSIZE * NSFRAMES) + { + + if ( conf.options & OPTION_RECORDING ) + { + static int lastrectime = 0; + if (timeGetTime() - lastrectime > 5000) + { + printf("ZeroSPU2: recording\n"); + lastrectime = timeGetTime(); + } + LogRawSound(s_pAudioBuffers[s_nCurBuffer].pbuf, 4, s_pAudioBuffers[s_nCurBuffer].pbuf+2, 4, NSSIZE*NSFRAMES); + } + + if ( s_nQueuedBuffers >= ARRAYSIZE(s_pAudioBuffers)-1 ) + { + //ZeroSPU2: dropping packets! game too fast + s_nDropPacket += NSFRAMES; + s_GlobalTimeStamp = GetMicroTime(); + } + else { + // submit to final mixer +#ifdef _DEBUG + if ( g_logsound ) + LogRawSound(s_pAudioBuffers[s_nCurBuffer].pbuf, 4, s_pAudioBuffers[s_nCurBuffer].pbuf+2, 4, NSSIZE*NSFRAMES); +#endif + if ( g_startcount == 0xffffffff ) + { + g_startcount = timeGetTime(); + g_packetcount = 0; + } + + if ( conf.options & OPTION_TIMESTRETCH ) + { + u64 newtime = GetMicroTime(); + if ( s_GlobalTimeStamp == 0 ) + s_GlobalTimeStamp = newtime-NSFRAMES*1000; + u32 newtotal = s_nTotalDuration-s_nDurations[s_nCurDuration]; + u32 duration = (u32)(newtime-s_GlobalTimeStamp); + s_nDurations[s_nCurDuration] = duration; + s_nTotalDuration = newtotal + duration; + s_nCurDuration = (s_nCurDuration+1)%ARRAYSIZE(s_nDurations); + s_GlobalTimeStamp = newtime; + s_pAudioBuffers[s_nCurBuffer].timestamp = timeGetTime(); + s_pAudioBuffers[s_nCurBuffer].avgtime = s_nTotalDuration/ARRAYSIZE(s_nDurations); + } + + s_pAudioBuffers[s_nCurBuffer].len = 4*NSSIZE*NSFRAMES; + InterlockedExchangeAdd((long*)&s_nQueuedBuffers, 1); + + s_nCurBuffer = (s_nCurBuffer+1)%ARRAYSIZE(s_pAudioBuffers); + s_pAudioBuffers[s_nCurBuffer].newchannels = 0; // reset + } + + // restart + s_pCurOutput = (s16*)s_pAudioBuffers[s_nCurBuffer].pbuf; + } + } +} + +// resamples pStereoSamples +void ResampleLinear(s16* pStereoSamples, int oldsamples, s16* pNewSamples, int newsamples) +{ + for (int i = 0; i < newsamples; ++i) + { + int io = i * oldsamples; + int old = io / newsamples; + int rem = io - old * newsamples; + + old *= 2; + int newsampL = pStereoSamples[old] * (newsamples - rem) + pStereoSamples[old+2] * rem; + int newsampR = pStereoSamples[old+1] * (newsamples - rem) + pStereoSamples[old+3] * rem; + pNewSamples[2 * i] = newsampL / newsamples; + pNewSamples[2 * i + 1] = newsampR / newsamples; + } +} + +static PCSX2_ALIGNED16(s16 s_ThreadBuffer[NSSIZE*NSFRAMES*2*5]); + +// SoundTouch's INTEGER system is broken these days, so we'll need this to do float conversions... +static PCSX2_ALIGNED16(float s_floatBuffer[NSSIZE*NSFRAMES*2*5]); + +// communicates with the audio hardware +#ifdef _WIN32 +DWORD WINAPI SPU2ThreadProc(LPVOID) +#else +void* SPU2ThreadProc(void* lpParam) +#endif +{ + int nReadBuf = 0; + + while (!s_bThreadExit) + { + + if (!(conf.options&OPTION_REALTIME)) + { + while(s_nQueuedBuffers< 3 && !s_bThreadExit) + { + //Sleeping + Sleep(1); + if ( s_bThreadExit ) + return NULL; + } + + while( SoundGetBytesBuffered() > 72000 ) + { + //Bytes buffered + Sleep(1); + + if ( s_bThreadExit ) return NULL; + } + } + else + { + while(s_nQueuedBuffers< 1 && !s_bThreadExit) + { + //Sleeping + Sleep(1); + } + } + + + //int ps2delay = timeGetTime() - s_pAudioBuffers[nReadBuf].timestamp; + int NewSamples = s_pAudioBuffers[nReadBuf].avgtime; + + if ( (conf.options & OPTION_TIMESTRETCH) ) + { + + int bytesbuf = SoundGetBytesBuffered(); + if ( bytesbuf < 8000 ) + NewSamples += 1000; + // check the current timestamp, if too far apart, speed up audio + else if ( bytesbuf > 40000 ) + { + //printf("making faster %d\n", timeGetTime() - s_pAudioBuffers[nReadBuf].timestamp); + NewSamples -= (bytesbuf-40000)/10;//*(ps2delay-NewSamples*8/1000); + } + + if ( s_nDropPacket > 0 ) + { + s_nDropPacket--; + NewSamples -= 1000; + } + + NewSamples *= NSSIZE; + NewSamples /= 1000; + + NewSamples = min(NewSamples, NSFRAMES * NSSIZE * 3); + + int oldsamples = s_pAudioBuffers[nReadBuf].len / 4; + + if ((nReadBuf & 3) == 0) // wow, this if statement makes the whole difference + pSoundTouch->setTempoChange(100.0f*(float)oldsamples/(float)NewSamples - 100.0f); + + for( int sx=0; sxputSamples(s_floatBuffer, oldsamples); + + // extract 2*NSFRAMES ms at a time + int nOutSamples; + + do + { + nOutSamples = pSoundTouch->receiveSamples(s_floatBuffer, NSSIZE * NSFRAMES * 5); + if ( nOutSamples > 0 ) + { + for( int sx=0; sx>=1) // loop channels + { + if ((val&1) && voices[ch].pStart) // mmm... start has to be set before key on !?! + { + voices[ch].bNew=true; + voices[ch].bIgnoreLoop = false; + dwNewChannel2[ch/24]|=(1<<(ch%24)); // clear end channel bit + } + } +} + +// turn channels off +void SoundOff(int start,int end,unsigned short val) // SOUND OFF PSX COMMAND +{ + for (int ch=start;ch>=1) // loop channels + { + if (val&1) voices[ch].bStop=true; // && s_chan[i].bOn) mmm... + } +} + +void FModOn(int start,int end,unsigned short val) // FMOD ON PSX COMMAND +{ + int ch; + + for (ch=start;ch>=1) // loop channels + { + if (val&1) + { // -> fmod on/off + if (ch>0) + { + voices[ch].bFMod=1; // --> sound channel + voices[ch-1].bFMod=2; // --> freq channel + } + } + else + voices[ch].bFMod=0; // --> turn off fmod + } +} + +void VolumeOn(int start,int end,unsigned short val,int iRight) // VOLUME ON PSX COMMAND +{ + int ch; + + for (ch=start;ch>=1) // loop channels + { + if (val&1) + { // -> reverb on/off + if (iRight) + voices[ch].bVolumeR = true; + else + voices[ch].bVolumeL = true; + } + else + { + if (iRight) + voices[ch].bVolumeR = false; + else + voices[ch].bVolumeL = false; + } + } +} + +void CALLBACK SPU2write(u32 mem, u16 value) +{ + LOG_CALLBACK("SPU2write()\n"); + u32 spuaddr; + SPU2_LOG("SPU2 write mem %x value %x\n", mem, value); + + assert(C0_SPUADDR() < 0x100000); + assert(C1_SPUADDR() < 0x100000); + + spu2Ru16(mem) = value; + u32 r = mem & 0xffff; + + // channel info + if ((r<0x0180) || (r>=0x0400 && r<0x0580)) // u32s are always >= 0. + { + int ch=0; + if (r >= 0x400) + ch = ((r - 0x400) >> 4) + 24; + else + ch = (r >> 4); + + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(r & 0x0f) + { + case 0: + case 2: + pvoice->SetVolume(mem & 0x2); + break; + case 4: + { + int NP; + if (value> 0x3fff) + NP=0x3fff; // get pitch val + else + NP=value; + + pvoice->pvoice->pitch = NP; + + NP = (SAMPLE_RATE * NP) / 4096L; // calc frequency + if (NP<1) NP = 1; // some security + pvoice->iActFreq = NP; // store frequency + break; + } + case 6: + { + pvoice->ADSRX.AttackModeExp=(value&0x8000)?1:0; + pvoice->ADSRX.AttackRate = ((value>>8) & 0x007f); + pvoice->ADSRX.DecayRate = (((value>>4) & 0x000f)); + pvoice->ADSRX.SustainLevel = (value & 0x000f); + break; + } + case 8: + pvoice->ADSRX.SustainModeExp = (value&0x8000)?1:0; + pvoice->ADSRX.SustainIncrease= (value&0x4000)?0:1; + pvoice->ADSRX.SustainRate = ((value>>6) & 0x007f); + pvoice->ADSRX.ReleaseModeExp = (value&0x0020)?1:0; + pvoice->ADSRX.ReleaseRate = ((value & 0x001f)); + break; + } + + return; + } + + // more channel info + if ((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) + { + int ch=0; + unsigned long rx=r; + if (rx>=0x400) + { + ch=24; + rx-=0x400; + } + + ch += ((rx-0x1c0)/12); + rx -= (ch%24)*12; + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch(rx) + { + case REG_VA_SSA: + pvoice->iStartAddr=(((u32)value&0x3f)<<16)|(pvoice->iStartAddr&0xFFFF); + pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); + break; + case 0x1C2: + pvoice->iStartAddr=(pvoice->iStartAddr & 0x3f0000) | (value & 0xFFFF); + pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); + break; + case REG_VA_LSAX: + pvoice->iLoopAddr =(((u32)value&0x3f)<<16)|(pvoice->iLoopAddr&0xFFFF); + pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); + pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; + break; + case 0x1C6: + pvoice->iLoopAddr=(pvoice->iLoopAddr& 0x3f0000) | (value & 0xFFFF); + pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); + pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; + break; + case REG_VA_NAX: + // unused... check if it gets written as well + pvoice->iNextAddr=(((u32)value&0x3f)<<16)|(pvoice->iNextAddr&0xFFFF); + break; + case 0x1CA: + // unused... check if it gets written as well + pvoice->iNextAddr=(pvoice->iNextAddr & 0x3f0000) | (value & 0xFFFF); + break; + } + + return; + } + + // process non-channel data + switch(mem & 0xffff) + { + case REG_C0_SPUDATA: + spuaddr = C0_SPUADDR(); + spu2mem[spuaddr] = value; + spuaddr++; + + if ((spu2Ru16(REG_C0_CTRL)&0x40) && (C0_IRQA() == spuaddr)) + { + IRQINFO |= 4; + SPU2_LOG("SPU2write:C0_CPUDATA interrupt\n"); + irqCallbackSPU2(); + } + + if (spuaddr>0xFFFFE) spuaddr = 0x2800; + + C0_SPUADDR_SET(spuaddr); + spu2Ru16(REG_C0_SPUSTAT)&=~0x80; + spu2Ru16(REG_C0_CTRL)&=~0x30; + break; + + case REG_C1_SPUDATA: + spuaddr = C1_SPUADDR(); + spu2mem[spuaddr] = value; + spuaddr++; + + if ((spu2Ru16(REG_C1_CTRL)&0x40) && (C1_IRQA() == spuaddr)) + { + IRQINFO |= 8; + SPU2_LOG("SPU2write:C1_CPUDATA interrupt\n"); + irqCallbackSPU2(); + } + + if (spuaddr>0xFFFFE) spuaddr = 0x2800; + + C1_SPUADDR_SET(spuaddr); + spu2Ru16(REG_C1_SPUSTAT)&=~0x80; + spu2Ru16(REG_C1_CTRL)&=~0x30; + break; + + case REG_C0_IRQA_HI: + case REG_C0_IRQA_LO: + pSpuIrq[0] = spu2mem + C0_IRQA(); + break; + + case REG_C1_IRQA_HI: + case REG_C1_IRQA_LO: + pSpuIrq[1] = spu2mem + C1_IRQA(); + break; + + case REG_C0_SPUADDR_HI: + case REG_C1_SPUADDR_HI: + spu2Ru16(mem) = value&0xf; + break; + + case REG_C0_CTRL: + spu2Ru16(mem) = value; + // clear interrupt + if (!(value & 0x40)) IRQINFO &= ~0x4; + break; + + case REG_C1_CTRL: + spu2Ru16(mem) = value; + // clear interrupt + if (!(value & 0x40)) IRQINFO &= ~0x8; + break; + + // Could probably simplify + case REG_C0_SPUON1: SoundOn(0,16,value); break; + case REG_C0_SPUON2: SoundOn(16,24,value); break; + case REG_C1_SPUON1: SoundOn(24,40,value); break; + case REG_C1_SPUON2: SoundOn(40,48,value); break; + case REG_C0_SPUOFF1: SoundOff(0,16,value); break; + case REG_C0_SPUOFF2: SoundOff(16,24,value); break; + case REG_C1_SPUOFF1: SoundOff(24,40,value); break; + case REG_C1_SPUOFF2: SoundOff(40,48,value); break; + + // According to manual all bits are cleared by writing an arbitary value + case REG_C0_END1: dwEndChannel2[0] &= 0x00ff0000; break; + case REG_C0_END2: dwEndChannel2[0] &= 0x0000ffff; break; + case REG_C1_END1: dwEndChannel2[1] &= 0x00ff0000; break; + case REG_C1_END2: dwEndChannel2[1] &= 0x0000ffff; break; + case REG_C0_FMOD1: FModOn(0,16,value); break; + case REG_C0_FMOD2: FModOn(16,24,value); break; + case REG_C1_FMOD1: FModOn(24,40,value); break; + case REG_C1_FMOD2: FModOn(40,48,value); break; + case REG_C0_VMIXL1: VolumeOn(0,16,value,0); break; + case REG_C0_VMIXL2: VolumeOn(16,24,value,0); break; + case REG_C1_VMIXL1: VolumeOn(24,40,value,0); break; + case REG_C1_VMIXL2: VolumeOn(40,48,value,0); break; + case REG_C0_VMIXR1: VolumeOn(0,16,value,1); break; + case REG_C0_VMIXR2: VolumeOn(16,24,value,1); break; + case REG_C1_VMIXR1: VolumeOn(24,40,value,1); break; + case REG_C1_VMIXR2: VolumeOn(40,48,value,1); break; + } + + assert( C0_SPUADDR() < 0x100000); + assert( C1_SPUADDR() < 0x100000); +} + +u16 CALLBACK SPU2read(u32 mem) +{ + LOG_CALLBACK("SPU2read()\n"); + u32 spuaddr; + u16 ret = 0; + u32 r = mem & 0xffff; // register + + // channel info + // if the register is any of the regs before core 0, or is somewhere between core 0 and 1... + if ((r < 0x0180) || (r >= 0x0400 && r < 0x0580)) // u32s are always >= 0. + { + int ch = 0; + + if (r >= 0x400) + ch=((r - 0x400) >> 4) + 24; + else + ch = (r >> 4); + + VOICE_PROCESSED* pvoice = &voices[ch]; + + if ((r&0x0f) == 10) return (u16)(pvoice->ADSRX.EnvelopeVol >> 16); + } + + + if ((r>=REG_VA_SSA && r=0x05c0 && r<0x06E0)) // some channel info? + { + int ch=0; + unsigned long rx = r; + + if (rx >=0x400) + { + ch=24; + rx-=0x400; + } + + ch+=((rx-0x1c0)/12); + rx-=(ch%24)*12; + VOICE_PROCESSED* pvoice = &voices[ch]; + + // Note - can we generalize this? + switch(rx) + { + case REG_VA_SSA: + ret = ((((uptr)pvoice->pStart-(uptr)spu2mem)>>17)&0x3F); + break; + case 0x1C2: + ret = ((((uptr)pvoice->pStart-(uptr)spu2mem)>>1)&0xFFFF); + break; + case REG_VA_LSAX: + ret = ((((uptr)pvoice->pLoop-(uptr)spu2mem)>>17)&0x3F); + break; + case 0x1C6: + ret = ((((uptr)pvoice->pLoop-(uptr)spu2mem)>>1)&0xFFFF); + break; + case REG_VA_NAX: + ret = ((((uptr)pvoice->pCurr-(uptr)spu2mem)>>17)&0x3F); + break; + case 0x1CA: + ret = ((((uptr)pvoice->pCurr-(uptr)spu2mem)>>1)&0xFFFF); + break; + } + + SPU2_LOG("SPU2 channel read mem %x: %x\n", mem, ret); + return ret; + } + + switch(mem & 0xffff) + { + case REG_C0_SPUDATA: + spuaddr = C0_SPUADDR(); + ret =spu2mem[spuaddr]; + spuaddr++; + if (spuaddr > 0xfffff) spuaddr=0; + C0_SPUADDR_SET(spuaddr); + break; + case REG_C1_SPUDATA: + spuaddr = C1_SPUADDR(); + ret = spu2mem[spuaddr]; + spuaddr++; + if (spuaddr > 0xfffff) spuaddr=0; + C1_SPUADDR_SET(spuaddr); + break; + + case REG_C0_END1: ret = (dwEndChannel2[0]&0xffff); break; + case REG_C1_END1: ret = (dwEndChannel2[1]&0xffff); break; + case REG_C0_END2: ret = (dwEndChannel2[0]>>16); break; + case REG_C1_END2: ret = (dwEndChannel2[1]>>16); break; + + case REG_IRQINFO: + ret = IRQINFO; + break; + + default: + ret = spu2Ru16(mem); + } + + SPU2_LOG("SPU2 read mem %x: %x\n", mem, ret); + + return ret; +} + +void CALLBACK SPU2WriteMemAddr(int core, u32 value) +{ + LOG_CALLBACK("SPU2WriteMemAddr(%d, %d)\n", core, value); + MemAddr[core] = g_pDMABaseAddr + value; +} + +u32 CALLBACK SPU2ReadMemAddr(int core) +{ + LOG_CALLBACK("SPU2ReadMemAddr(%d)\n", core); + return MemAddr[core] - g_pDMABaseAddr; +} + +void CALLBACK SPU2setDMABaseAddr(uptr baseaddr) +{ + LOG_CALLBACK("SPU2setDMABaseAddr()\n"); + g_pDMABaseAddr = baseaddr; +} + +void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()) +{ + LOG_CALLBACK("SPU2irqCallback()\n"); + irqCallbackSPU2 = SPU2callback; + irqCallbackDMA4 = DMA4callback; + irqCallbackDMA7 = DMA7callback; +} + +s32 CALLBACK SPU2test() +{ + LOG_CALLBACK("SPU2test()\n"); + return 0; +} + +#define SetPacket(s) \ +{ \ + if (s & 0x8000) s|=0xffff0000; \ + fa = (s >> shift_factor); \ + fa += ((s_1 * f[predict_nr][0]) >> 6) + ((s_2 * f[predict_nr][1]) >> 6); \ + s_2 = s_1; \ + s_1 = fa; \ + buf[nSample++] = fa; \ +} + +// size is in bytes +void LogPacketSound(void* packet, int memsize) +{ + u16 buf[28]; + + u8* pstart = (u8*)packet; + int s_1 = 0, s_2=0; + + for (int i = 0; i < memsize; i += 16) + { + int predict_nr=(int)pstart[0]; + int shift_factor=predict_nr&0xf; + predict_nr >>= 4; + pstart += 2; + + for (int nSample=0;nSample<28; ++pstart) + { + int d=(int)*pstart; + int s, fa; + + s =((d & 0xf) << 12); + SetPacket(s); + + s=((d & 0xf0) << 8); + SetPacket(s); + } + + LogRawSound(buf, 2, buf, 2, 28); + } +} + +void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int numsamples) +{ + if (g_pWavRecord == NULL ) + g_pWavRecord = new WavOutFile(RECORD_FILENAME, SAMPLE_RATE, 16, 2); + + u8* left = (u8*)pleft; + u8* right = (u8*)pright; + static vector tempbuf; + + tempbuf.resize(2 * numsamples); + + for (int i = 0; i < numsamples; ++i) + { + tempbuf[2*i+0] = *(s16*)left; + tempbuf[2*i+1] = *(s16*)right; + left += leftstride; + right += rightstride; + } + + g_pWavRecord->write(&tempbuf[0], numsamples*2); +} + +int CALLBACK SPU2setupRecording(int start, void* pData) +{ + LOG_CALLBACK("SPU2setupRecording()\n"); + if ( start ) + { + conf.options |= OPTION_RECORDING; + printf("ZeroSPU2: started recording at %s\n", RECORD_FILENAME); + } + else + { + conf.options &= ~OPTION_RECORDING; + printf("ZeroSPU2: stopped recording\n"); + } + + return 1; +} + +s32 CALLBACK SPU2freeze(int mode, freezeData *data) +{ + LOG_CALLBACK("SPU2freeze()\n"); + SPU2freezeData *spud; + int i; + assert( g_pDMABaseAddr != 0 ); + + if (mode == FREEZE_LOAD) + { + spud = (SPU2freezeData*)data->data; + if (spud->version != 0x70000001) + { + printf("zerospu2: data wrong format\n"); + return 0; + } + + memcpy(spu2regs, spud->spu2regs, 0x10000); + memcpy(spu2mem, spud->spu2mem, 0x200000); + pSpuIrq[0] = spu2mem + spud->nSpuIrq[0]; + pSpuIrq[1] = spu2mem + spud->nSpuIrq[1]; + memcpy(dwNewChannel2, spud->dwNewChannel2, 4*2); + memcpy(dwEndChannel2, spud->dwEndChannel2, 4*2); + dwNoiseVal = spud->dwNoiseVal; + memcpy(iFMod, spud->iFMod, sizeof(iFMod)); + interrupt = spud->interrupt; + memcpy(MemAddr, spud->MemAddr, sizeof(MemAddr)); + Adma4 = spud->adma[0]; + Adma4.MemAddr = (u16*)(g_pDMABaseAddr+spud->Adma4MemAddr); + Adma7 = spud->adma[1]; + Adma7.MemAddr = (u16*)(g_pDMABaseAddr+spud->Adma7MemAddr); + + SPUCycles = spud->SPUCycles; + SPUWorkerCycles = spud->SPUWorkerCycles; + memcpy(SPUStartCycle, spud->SPUStartCycle, sizeof(SPUStartCycle)); + memcpy(SPUTargetCycle, spud->SPUTargetCycle, sizeof(SPUTargetCycle)); + + for (i = 0; i < ARRAYSIZE(voices); ++i) + { + memcpy(&voices[i], &spud->voices[i], min((int)SPU_VOICE_STATE_SIZE, spud->voicesize)); + voices[i].pStart = (u8*)((uptr)spud->voices[i].pStart+(uptr)spu2mem); + voices[i].pLoop = (u8*)((uptr)spud->voices[i].pLoop+(uptr)spu2mem); + voices[i].pCurr = (u8*)((uptr)spud->voices[i].pCurr+(uptr)spu2mem); + } + + s_GlobalTimeStamp = 0; + g_startcount = 0xffffffff; + + for (int i = 0; i < ARRAYSIZE(s_nDurations); ++i) + { + s_nDurations[i] = NSFRAMES*1000; + } + + s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; + s_nCurDuration = 0; + s_nQueuedBuffers = 0; + s_nDropPacket = 0; + } + else if (mode == FREEZE_SAVE) + { + spud = (SPU2freezeData*)data->data; + spud->version = 0x70000001; + + memcpy(spud->spu2regs, spu2regs, 0x10000); + memcpy(spud->spu2mem, spu2mem, 0x200000); + spud->nSpuIrq[0] = (int)(pSpuIrq[0] - spu2mem); + spud->nSpuIrq[1] = (int)(pSpuIrq[1] - spu2mem); + memcpy(spud->dwNewChannel2, dwNewChannel2, 4*2); + memcpy(spud->dwEndChannel2, dwEndChannel2, 4*2); + spud->dwNoiseVal = dwNoiseVal; + memcpy(spud->iFMod, iFMod, sizeof(iFMod)); + spud->interrupt = interrupt; + memcpy(spud->MemAddr, MemAddr, sizeof(MemAddr)); + + spud->adma[0] = Adma4; + spud->Adma4MemAddr = (u32)((uptr)Adma4.MemAddr - g_pDMABaseAddr); + spud->adma[1] = Adma7; + spud->Adma7MemAddr = (u32)((uptr)Adma7.MemAddr - g_pDMABaseAddr); + + spud->SPUCycles = SPUCycles; + spud->SPUWorkerCycles = SPUWorkerCycles; + + memcpy(spud->SPUStartCycle, SPUStartCycle, sizeof(SPUStartCycle)); + memcpy(spud->SPUTargetCycle, SPUTargetCycle, sizeof(SPUTargetCycle)); + + for (i = 0; i < ARRAYSIZE(s_nDurations); ++i) + { + s_nDurations[i] = NSFRAMES*1000; + } + s_nTotalDuration = ARRAYSIZE(s_nDurations)*NSFRAMES*1000; + s_nCurDuration = 0; + + spud->voicesize = SPU_VOICE_STATE_SIZE; + for (i = 0; i < ARRAYSIZE(voices); ++i) + { + memcpy(&spud->voices[i], &voices[i], SPU_VOICE_STATE_SIZE); + spud->voices[i].pStart = (u8*)((uptr)voices[i].pStart-(uptr)spu2mem); + spud->voices[i].pLoop = (u8*)((uptr)voices[i].pLoop-(uptr)spu2mem); + spud->voices[i].pCurr = (u8*)((uptr)voices[i].pCurr-(uptr)spu2mem); + } + + g_startcount=0xffffffff; + s_GlobalTimeStamp = 0; + s_nDropPacket = 0; + } + else if (mode == FREEZE_SIZE) + { + data->size = sizeof(SPU2freezeData); + } + + return 0; +} diff --git a/plugins/zerospu2/zerospu2.h b/plugins/zerospu2/zerospu2.h new file mode 100644 index 0000000000..c67b54d1f5 --- /dev/null +++ b/plugins/zerospu2/zerospu2.h @@ -0,0 +1,399 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 __SPU2_H__ +#define __SPU2_H__ + +#include +#include +#include + +extern "C" { +#define SPU2defs +#include "PS2Edefs.h" +} + +#include "reg.h" +#include "misc.h" + +#include +#include +using namespace std; + +extern FILE *spu2Log; + +// Prints most of the function names of the callbacks as they are called by pcsx2. +// I'm keeping the code in because I have a feeling it will come in handy. +//#define PRINT_CALLBACKS + +#ifdef PRINT_CALLBACKS +#define LOG_CALLBACK printf +#else +#define LOG_CALLBACK 0&& +#endif + +#ifdef _DEBUG +#define SPU2_LOG __Log //debug mode +#else +#define SPU2_LOG 0&& +#endif + +#define SPU2_VERSION PS2E_SPU2_VERSION +#define SPU2_REVISION 0 +#define SPU2_BUILD 4 // increase that with each version +#define SPU2_MINOR 6 + +#define OPTION_TIMESTRETCH 1 // stretches samples without changing pitch to reduce cracking +#define OPTION_REALTIME 2 // sync to real time instead of ps2 time +#define OPTION_MUTE 4 // don't output anything +#define OPTION_RECORDING 8 + +// ADSR constants +#define ATTACK_MS 494L +#define DECAYHALF_MS 286L +#define DECAY_MS 572L +#define SUSTAIN_MS 441L +#define RELEASE_MS 437L + +#define CYCLES_PER_MS (36864000/1000) + +#define AUDIO_BUFFER 2048 + +#define NSSIZE 48 // ~ 1 ms of data +#define NSFRAMES 16 // gather at least NSFRAMES of NSSIZE before submitting +#define NSPACKETS 24 + +#define SAMPLE_RATE 48000L +#define RECORD_FILENAME "zerospu2.wav" + +extern s8 *spu2regs; +extern u16* spu2mem; +extern int iFMod[NSSIZE]; +extern u32 MemAddr[2]; +extern unsigned long dwNoiseVal; // global noise generator + +// functions of main emu, called on spu irq +extern void (*irqCallbackSPU2)(); +extern void (*irqCallbackDMA4)(); +extern void (*irqCallbackDMA7)(); + +extern int SPUCycles, SPUWorkerCycles; +extern int SPUStartCycle[2]; +extern int SPUTargetCycle[2]; + +extern u16 interrupt; + +typedef struct { + int Log; + int options; +} Config; + +extern Config conf; + +void __Log(char *fmt, ...); +void SaveConfig(); +void LoadConfig(); +void SysMessage(char *fmt, ...); + +void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int numsamples); +void LogPacketSound(void* packet, int memsize); + +// simulate SPU2 for 1ms +void SPU2Worker(); + +// hardware sound functions +int SetupSound(); // if successful, returns 0 +void RemoveSound(); +int SoundGetBytesBuffered(); +// returns 0 is successful, else nonzero +void SoundFeedVoiceData(unsigned char* pSound,long lBytes); + +#define clamp16(dest) \ +{ \ + if ( dest < -32768L ) \ + dest = -32768L; \ + else if ( dest > 32767L ) \ + dest = 32767L; \ +} + +#define clampandwrite16(dest,value) \ +{ \ + if ( value < -32768 ) \ + dest = -32768; \ + else if ( value > 32767 ) \ + dest = 32767; \ + else \ + dest = (s16)value; \ +} + +#define spu2Rs16(mem) (*(s16*)&spu2regs[(mem) & 0xffff]) +#define spu2Ru16(mem) (*(u16*)&spu2regs[(mem) & 0xffff]) + +#define IRQINFO spu2Ru16(REG_IRQINFO) + +static __forceinline u32 SPU2_GET32BIT(u32 lo, u32 hi) +{ + return (((u32)(spu2Ru16(hi) & 0x3f) << 16) | (u32)spu2Ru16(lo)); +} + +static __forceinline void SPU2_SET32BIT(u32 value, u32 lo, u32 hi) +{ + spu2Ru16(hi) = ((value) >> 16) & 0x3f; + spu2Ru16(lo) = (value) & 0xffff; +} + +static __forceinline u32 C0_IRQA() +{ + return SPU2_GET32BIT(REG_C0_IRQA_LO, REG_C0_IRQA_HI); +} + +static __forceinline u32 C1_IRQA() +{ + return SPU2_GET32BIT(REG_C1_IRQA_LO, REG_C1_IRQA_HI); +} + +static __forceinline u32 C_IRQA(int c) +{ + if (c == 0) + return C0_IRQA(); + else + return C1_IRQA(); +} + +static __forceinline u32 C0_SPUADDR() +{ + return SPU2_GET32BIT(REG_C0_SPUADDR_LO, REG_C0_SPUADDR_HI); +} + +static __forceinline u32 C1_SPUADDR() +{ + return SPU2_GET32BIT(REG_C1_SPUADDR_LO, REG_C1_SPUADDR_HI); +} + +static __forceinline u32 C_SPUADDR(int c) +{ + if (c == 0) + return C0_SPUADDR(); + else + return C1_SPUADDR(); +} + +static __forceinline void C0_SPUADDR_SET(u32 value) +{ + SPU2_SET32BIT(value, REG_C0_SPUADDR_LO, REG_C0_SPUADDR_HI); +} + +static __forceinline void C1_SPUADDR_SET(u32 value) +{ + SPU2_SET32BIT(value, REG_C1_SPUADDR_LO, REG_C1_SPUADDR_HI); +} + +static __forceinline void C_SPUADDR_SET(u32 value, int c) +{ + if (c == 0) + C0_SPUADDR_SET(value); + else + C1_SPUADDR_SET(value); +} + +#define SPU_NUMBER_VOICES 48 + +struct SPU_CONTROL_ +{ + u16 extCd : 1; + u16 extAudio : 1; + u16 cdreverb : 1; + u16 extr : 1; // external reverb + u16 dma : 2; // 1 - no dma, 2 - write, 3 - read + u16 irq : 1; + u16 reverb : 1; + u16 noiseFreq : 6; + u16 spuUnmute : 1; + u16 spuon : 1; +}; + +#if defined(_MSC_VER) +#pragma pack(1) +#endif +// the layout of each voice in wSpuRegs +struct _SPU_VOICE +{ + union + { + struct { + u16 Vol : 14; + u16 Inverted : 1; + u16 Sweep0 : 1; + } vol; + struct { + u16 Vol : 7; + u16 res1 : 5; + u16 Inverted : 1; + u16 Decrease : 1; // if 0, increase + u16 ExpSlope : 1; // if 0, linear slope + u16 Sweep1 : 1; // always one + } sweep; + u16 word; + } left, right; + + u16 pitch : 14; // 1000 - no pitch, 2000 - pitch + 1, etc + u16 res0 : 2; + + u16 SustainLvl : 4; + u16 DecayRate : 4; + u16 AttackRate : 7; + u16 AttackExp : 1; // if 0, linear + + u16 ReleaseRate : 5; + u16 ReleaseExp : 1; // if 0, linear + u16 SustainRate : 7; + u16 res1 : 1; + u16 SustainDec : 1; // if 0, inc + u16 SustainExp : 1; // if 0, linear + + u16 AdsrVol; + u16 Address; // add / 8 + u16 RepeatAddr; // gets reset when sample starts +#if defined(_MSC_VER) +}; //+22 +#else +} __attribute__((packed)); +#endif + +// ADSR INFOS PER CHANNEL +struct ADSRInfoEx +{ + int State; + int AttackModeExp; + int AttackRate; + int DecayRate; + int SustainLevel; + int SustainModeExp; + int SustainIncrease; + int SustainRate; + int ReleaseModeExp; + int ReleaseRate; + int EnvelopeVol; + long lVolume; +}; + +#define SPU_VOICE_STATE_SIZE (sizeof(VOICE_PROCESSED)-4*sizeof(void*)) + +struct VOICE_PROCESSED +{ + VOICE_PROCESSED() + { + memset(this, 0, sizeof(VOICE_PROCESSED)); + } + + void SetVolume(int right); + void StartSound(); + void VoiceChangeFrequency(); + void InterpolateUp(); + void InterpolateDown(); + void FModChangeFrequency(int ns); + int iGetNoiseVal(); + void StoreInterpolationVal(int fa); + int iGetInterpolationVal(); + void Stop(); + + SPU_CONTROL_* GetCtrl(); + + // start save state + int leftvol, rightvol; // left right volumes + + int iSBPos; // mixing stuff + int SB[32+32]; + int spos; + int sinc; + + int iIrqDone; // debug irq done flag + int s_1; // last decoding infos + int s_2; + int iOldNoise; // old noise val for this channel + int iActFreq; // current psx pitch + int iUsedFreq; // current pc pitch + + int iStartAddr, iLoopAddr, iNextAddr; + int bFMod; + + ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start) + int memoffset; // if first core, 0, if second, 0x400 + int chanid; // channel id + + bool bIgnoreLoop, bNew, bNoise, bReverb, bOn, bStop, bVolChanged; + bool bVolumeR, bVolumeL; + + // end save state + + /////////////////// + // Sound Buffers // + /////////////////// + u8* pStart; // start and end addresses + u8* pLoop, *pCurr; + + _SPU_VOICE* pvoice; +}; + +struct AUDIOBUFFER +{ + u8* pbuf; + u32 len; + + // 1 if new channels started in this packet + // Variable used to smooth out sound by concentrating on new voices + u32 timestamp; // in microseconds, only used for time stretching + u32 avgtime; + int newchannels; +}; + +struct ADMA +{ + unsigned short * MemAddr; + int Index; + int AmountLeft; + int Enabled; + // used to make sure that ADMA doesn't get interrupted with a writeDMA call +}; + +extern ADMA Adma4; +extern ADMA Adma7; + +struct SPU2freezeData +{ + u32 version; + u8 spu2regs[0x10000]; + u8 spu2mem[0x200000]; + u16 interrupt; + int nSpuIrq[2]; + u32 dwNewChannel2[2], dwEndChannel2[2]; + u32 dwNoiseVal; + int iFMod[NSSIZE]; + u32 MemAddr[2]; + ADMA adma[2]; + u32 Adma4MemAddr, Adma7MemAddr; + + int SPUCycles, SPUWorkerCycles; + int SPUStartCycle[2]; + int SPUTargetCycle[2]; + + int voicesize; + VOICE_PROCESSED voices[SPU_NUMBER_VOICES+1]; +}; + +#endif /* __SPU2_H__ */